Add general Writer logger, and use it for Std and File loggers

Change-Id: I6a14112c8e4e3875897c16b9518a81bcccc9a985
diff --git a/log/std.go b/log/std.go
deleted file mode 100644
index d7cb4fe..0000000
--- a/log/std.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package log
-
-import (
-	"os"
-)
-
-// Std returns a Logger that writes to stdout and stderr.
-func Std() Logger {
-	out := make(chan interface{}, 64)
-	go func() {
-		for t := range out {
-			switch t := t.(type) {
-			case Entry:
-				if t.Kind == Error {
-					os.Stderr.WriteString(t.String())
-				} else {
-					os.Stdout.WriteString(t.String())
-				}
-
-			case FlushRequest:
-				os.Stderr.Sync()
-				os.Stdout.Sync()
-				close(t)
-			}
-		}
-	}()
-	nextUid := uint32(1)
-	return &channel{
-		uid:     0,
-		nextUid: &nextUid,
-		scope:   "",
-		out:     out,
-	}
-}
diff --git a/log/file.go b/log/writer.go
similarity index 60%
rename from log/file.go
rename to log/writer.go
index 001eaac..8615004 100644
--- a/log/file.go
+++ b/log/writer.go
@@ -15,28 +15,47 @@
 package log
 
 import (
+	"io"
 	"os"
 	"path/filepath"
 )
 
-// File creates a new Logger that will write messages to the specified file path.
-// If a file exists at the specified path, then this file will be overwritten.
-func File(path string) (Logger, error) {
-	os.MkdirAll(filepath.Dir(path), 0755)
-	file, err := os.Create(path)
-	if err != nil {
-		return nil, err
+type syncer interface {
+	Sync() error
+}
+
+func doSync(w io.Writer) {
+	if w != nil {
+		if s, ok := w.(syncer); ok {
+			s.Sync()
+		}
 	}
+}
+
+// Writer returns a Logger that writes to the supplied streams.
+func Writer(info, warn, err io.Writer, done func()) Logger {
 	out := make(chan interface{}, 64)
 	go func() {
-		defer file.Close()
+		if done != nil {
+			defer done()
+		}
 		for t := range out {
 			switch t := t.(type) {
 			case Entry:
-				file.WriteString(t.String())
-
+				switch t.Kind {
+				case Info:
+					io.WriteString(info, t.String())
+				case Warning:
+					io.WriteString(warn, t.String())
+				case Error:
+					io.WriteString(err, t.String())
+				default:
+					io.WriteString(info, t.String())
+				}
 			case FlushRequest:
-				file.Sync()
+				doSync(info)
+				doSync(warn)
+				doSync(err)
 				close(t)
 			}
 		}
@@ -47,5 +66,21 @@
 		nextUid: &nextUid,
 		scope:   "",
 		out:     out,
-	}, nil
+	}
+}
+
+// File creates a new Logger that will write messages to the specified file path.
+// If a file exists at the specified path, then this file will be overwritten.
+func File(path string) (Logger, error) {
+	os.MkdirAll(filepath.Dir(path), 0755)
+	file, err := os.Create(path)
+	if err != nil {
+		return nil, err
+	}
+	return Writer(file, file, file, func() { file.Close() }), nil
+}
+
+// Std returns a Logger that writes to stdout and stderr.
+func Std() Logger {
+	return Writer(os.Stdout, os.Stdout, os.Stderr, nil)
 }