From 10ce6cf971564cabc5cd7a2a279e8f2401fdd4a5 Mon Sep 17 00:00:00 2001 From: Chris Hines Date: Tue, 10 Jan 2017 22:24:30 -0500 Subject: [PATCH 1/2] log: Add NewSyncWriter example. --- log/example_test.go | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/log/example_test.go b/log/example_test.go index b07ef8ec6..809593c77 100644 --- a/log/example_test.go +++ b/log/example_test.go @@ -1,7 +1,9 @@ package log_test import ( + "math/rand" "os" + "sync" "time" "github.com/go-kit/kit/log" @@ -96,7 +98,40 @@ func Example_debugInfo() { logger.Log("call", "third") // Output: - // time=2015-02-03T10:00:01Z caller=example_test.go:91 call=first - // time=2015-02-03T10:00:02Z caller=example_test.go:92 call=second - // time=2015-02-03T10:00:03Z caller=example_test.go:96 call=third + // time=2015-02-03T10:00:01Z caller=example_test.go:93 call=first + // time=2015-02-03T10:00:02Z caller=example_test.go:94 call=second + // time=2015-02-03T10:00:03Z caller=example_test.go:98 call=third +} + +func Example_syncWriter() { + w := log.NewSyncWriter(os.Stdout) + logger := log.NewLogfmtLogger(w) + + type Task struct { + ID int + } + + var wg sync.WaitGroup + + RunTask := func(task Task, logger log.Logger) { + logger.Log("taskID", task.ID, "event", "starting task") + + time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond) + + logger.Log("taskID", task.ID, "event", "task complete") + wg.Done() + } + + wg.Add(2) + + go RunTask(Task{ID: 1}, logger) + go RunTask(Task{ID: 2}, logger) + + wg.Wait() + + // Unordered output: + // taskID=1 event="starting task" + // taskID=2 event="starting task" + // taskID=1 event="task complete" + // taskID=2 event="task complete" } From 1b5215d847b40886c1fe6be118d58c9147af6229 Mon Sep 17 00:00:00 2001 From: Chris Hines Date: Tue, 10 Jan 2017 23:41:41 -0500 Subject: [PATCH 2/2] log: Explain why Logger.Log returns an error and how to work with it. --- log/doc.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/log/doc.go b/log/doc.go index 49d3f1810..ad1128eba 100644 --- a/log/doc.go +++ b/log/doc.go @@ -90,4 +90,27 @@ // handled atomically within the wrapped logger, but it typically serializes // both the formatting and output logic. Use a SyncLogger if the formatting // logger may perform multiple writes per log event. +// +// Error Handling +// +// This package relies on the practice of wrapping or decorating loggers with +// other loggers to provide composable pieces of functionality. It also means +// that Logger.Log must return an error because some +// implementations—especially those that output log data to an io.Writer—may +// encounter errors that cannot be handled locally. This in turn means that +// Loggers that wrap other loggers should return errors from the wrapped +// logger up the stack. +// +// Fortunately, the decorator pattern also provides a way to avoid the +// necessity to check for errors every time an application calls Logger.Log. +// An application required to panic whenever its Logger encounters +// an error could initialize its logger as follows. +// +// fmtlogger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout)) +// logger := log.LoggerFunc(func(keyvals ...interface{}) error { +// if err := fmtlogger.Log(keyvals...); err != nil { +// panic(err) +// } +// return nil +// }) package log