Involved Source Files Package log provides a structured logger.
Structured logging produces logs easily consumed later by humans or
machines. Humans might be interested in debugging errors, or tracing
specific requests. Machines might be interested in counting interesting
events, or aggregating information for off-line processing. In both cases,
it is important that the log messages are structured and actionable.
Package log is designed to encourage both of these best practices.
Basic Usage
The fundamental interface is Logger. Loggers create log events from
key/value data. The Logger interface has a single method, Log, which
accepts a sequence of alternating key/value pairs, which this package names
keyvals.
type Logger interface {
Log(keyvals ...interface{}) error
}
Here is an example of a function using a Logger to create log events.
func RunTask(task Task, logger log.Logger) string {
logger.Log("taskID", task.ID, "event", "starting task")
...
logger.Log("taskID", task.ID, "event", "task complete")
}
The keys in the above example are "taskID" and "event". The values are
task.ID, "starting task", and "task complete". Every key is followed
immediately by its value.
Keys are usually plain strings. Values may be any type that has a sensible
encoding in the chosen log format. With structured logging it is a good
idea to log simple values without formatting them. This practice allows
the chosen logger to encode values in the most appropriate way.
Contextual Loggers
A contextual logger stores keyvals that it includes in all log events.
Building appropriate contextual loggers reduces repetition and aids
consistency in the resulting log output. With, WithPrefix, and WithSuffix
add context to a logger. We can use With to improve the RunTask example.
func RunTask(task Task, logger log.Logger) string {
logger = log.With(logger, "taskID", task.ID)
logger.Log("event", "starting task")
...
taskHelper(task.Cmd, logger)
...
logger.Log("event", "task complete")
}
The improved version emits the same log events as the original for the
first and last calls to Log. Passing the contextual logger to taskHelper
enables each log event created by taskHelper to include the task.ID even
though taskHelper does not have access to that value. Using contextual
loggers this way simplifies producing log output that enables tracing the
life cycle of individual tasks. (See the Contextual example for the full
code of the above snippet.)
Dynamic Contextual Values
A Valuer function stored in a contextual logger generates a new value each
time an event is logged. The Valuer example demonstrates how this feature
works.
Valuers provide the basis for consistently logging timestamps and source
code location. The log package defines several valuers for that purpose.
See Timestamp, DefaultTimestamp, DefaultTimestampUTC, Caller, and
DefaultCaller. A common logger initialization sequence that ensures all log
entries contain a timestamp and source location looks like this:
logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout))
logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
Concurrent Safety
Applications with multiple goroutines want each log event written to the
same logger to remain separate from other log events. Package log provides
two simple solutions for concurrent safe logging.
NewSyncWriter wraps an io.Writer and serializes each call to its Write
method. Using a SyncWriter has the benefit that the smallest practical
portion of the logging logic is performed within a mutex, but it requires
the formatting Logger to make only one call to Write per log event.
NewSyncLogger wraps any Logger and serializes each call to its Log method.
Using a SyncLogger has the benefit that it guarantees each log event is
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
})json_logger.golog.gologfmt_logger.gonop_logger.gostdlib.gosync.govalue.go
LoggerFunc is an adapter to allow use of ordinary functions as Loggers. If
f is a function with the appropriate signature, LoggerFunc(f) is a Logger
object that calls f. Log implements Logger by calling f(keyvals...).
LoggerFunc : Logger
LoggerFunc : github.com/efficientgo/core/logerrcapture.Logger
StdlibAdapter wraps a Logger and allows it to be passed to the stdlib
logger's SetOutput. It will extract date/timestamps, filenames, and
messages, and place them under relevant keys.LoggerLogger( StdlibAdapter) Log(keyvals ...interface{}) error( StdlibAdapter) Write(p []byte) (int, error)
StdlibAdapter : Logger
StdlibAdapter : github.com/efficientgo/core/logerrcapture.Logger
StdlibAdapter : github.com/miekg/dns.Writer
StdlibAdapter : internal/bisect.Writer
StdlibAdapter : io.Writer
StdlibWriter implements io.Writer by invoking the stdlib log.Print. It's
designed to be passed to a Go kit logger as the writer, for cases where
it's necessary to redirect all Go kit log output to the stdlib logger.
If you have any choice in the matter, you shouldn't use this. Prefer to
redirect the stdlib log to the Go kit logger via NewStdlibAdapter. Write implements io.Writer.
StdlibWriter : github.com/miekg/dns.Writer
StdlibWriter : internal/bisect.Writer
StdlibWriter : io.Writer
SwapLogger wraps another logger that may be safely replaced while other
goroutines use the SwapLogger concurrently. The zero value for a SwapLogger
will discard all log events without error.
SwapLogger serves well as a package global logger that can be changed by
importers. Log implements the Logger interface by forwarding keyvals to the currently
wrapped logger. It does not log anything if the wrapped logger is nil. Swap replaces the currently wrapped logger with logger. Swap may be called
concurrently with calls to Log from other goroutines.
*SwapLogger : Logger
*SwapLogger : github.com/efficientgo/core/logerrcapture.Logger
Caller returns a Valuer that returns a file and line from a specified depth
in the callstack. Users will probably want to use DefaultCaller.
FileKey sets the key for the file and line field. By default, it's "caller".
MessageKey sets the key for the actual log message. By default, it's "msg".
NewJSONLogger returns a Logger that encodes keyvals to the Writer as a
single JSON object. Each log event produces no more than one call to
w.Write. The passed Writer must be safe for concurrent use by multiple
goroutines if the returned Logger will be used concurrently.
NewLogfmtLogger returns a logger that encodes keyvals to the Writer in
logfmt format. Each log event produces no more than one call to w.Write.
The passed Writer must be safe for concurrent use by multiple goroutines if
the returned Logger will be used concurrently.
NewNopLogger returns a logger that doesn't do anything.
NewStdlibAdapter returns a new StdlibAdapter wrapper around the passed
logger. It's designed to be passed to log.SetOutput.
NewSyncLogger returns a logger that synchronizes concurrent use of the
wrapped logger. When multiple goroutines use the SyncLogger concurrently
only one goroutine will be allowed to log to the wrapped logger at a time.
The other goroutines will block until the logger is available.
NewSyncWriter returns a new writer that is safe for concurrent use by
multiple goroutines. Writes to the returned writer are passed on to w. If
another write is already in progress, the calling goroutine blocks until
the writer is available.
If w implements the following interface, so does the returned writer.
interface {
Fd() uintptr
}
Prefix configures the adapter to parse a prefix from stdlib log events. If
you provide a non-empty prefix to the stdlib logger, then your should provide
that same prefix to the adapter via this option.
By default, the prefix isn't included in the msg key. Set joinPrefixToMsg to
true if you want to include the parsed prefix in the msg.
Timestamp returns a timestamp Valuer. It invokes the t function to get the
time; unless you are doing something tricky, pass time.Now.
Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
are TimestampFormats that use the RFC3339Nano format.
TimestampFormat returns a timestamp Valuer with a custom time format. It
invokes the t function to get the time to format; unless you are doing
something tricky, pass time.Now. The layout string is passed to
Time.Format.
Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
are TimestampFormats that use the RFC3339Nano format.
TimestampKey sets the key for the timestamp field. By default, it's "ts".
With returns a new contextual logger with keyvals prepended to those passed
to calls to Log. If logger is also a contextual logger created by With,
WithPrefix, or WithSuffix, keyvals is appended to the existing context.
The returned Logger replaces all value elements (odd indexes) containing a
Valuer with their generated value for each call to its Log method.
WithPrefix returns a new contextual logger with keyvals prepended to those
passed to calls to Log. If logger is also a contextual logger created by
With, WithPrefix, or WithSuffix, keyvals is prepended to the existing context.
The returned Logger replaces all value elements (odd indexes) containing a
Valuer with their generated value for each call to its Log method.
WithSuffix returns a new contextual logger with keyvals appended to those
passed to calls to Log. If logger is also a contextual logger created by
With, WithPrefix, or WithSuffix, keyvals is appended to the existing context.
The returned Logger replaces all value elements (odd indexes) containing a
Valuer with their generated value for each call to its Log method.
Package-Level Variables (total 4)
DefaultCaller is a Valuer that returns the file and line where the Log
method was invoked. It can only be used with log.With.
DefaultTimestamp is a Valuer that returns the current wallclock time,
respecting time zones, when bound.
DefaultTimestampUTC is a Valuer that returns the current time in UTC
when bound.
ErrMissingValue is appended to keyvals slices with odd length to substitute
the missing value.
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.