Documentation ¶
Overview ¶
Package zap provides fast, structured, leveled logging in Go.
Example ¶
package main import ( "time" "github.com/uber-go/zap" ) func main() { // Log in JSON, using zap's reflection-free JSON encoder. // The default options will log any Info or higher logs to standard out. logger := zap.NewJSON() // For repeatable tests, pretend that it's always 1970. logger.StubTime() logger.Warn("Log without structured data...") logger.Warn( "Or use strongly-typed wrappers to add structured context.", zap.String("library", "zap"), zap.Duration("latency", time.Nanosecond), ) // Avoid re-serializing the same data repeatedly by creating a child logger // with some attached context. That context is added to all the child's // log output, but doesn't affect the parent. child := logger.With(zap.String("user", "jane@test.com"), zap.Int("visits", 42)) child.Error("Oh no!") }
Output: {"msg":"Log without structured data...","level":"warn","ts":0,"fields":{}} {"msg":"Or use strongly-typed wrappers to add structured context.","level":"warn","ts":0,"fields":{"library":"zap","latency":1}} {"msg":"Oh no!","level":"error","ts":0,"fields":{"user":"jane@test.com","visits":42}}
Index ¶
- Variables
- func NewHTTPHandler(logger Logger) http.Handler
- type AppendFunc
- type CheckedMessage
- type Field
- func Bool(key string, val bool) Field
- func Duration(key string, val time.Duration) Field
- func Error(err error) Field
- func Float64(key string, val float64) Field
- func Int(key string, val int) Field
- func Int64(key string, val int64) Field
- func Marshaler(key string, val LogMarshaler) Field
- func Nest(key string, fields ...Field) Field
- func Object(key string, val interface{}) Field
- func Stack() Field
- func String(key string, val string) Field
- func Stringer(key string, val fmt.Stringer) Field
- func Time(key string, val time.Time) Field
- type KeyValue
- type Level
- type LogMarshaler
- type Logger
- type Option
- type WriteFlusher
- type WriteSyncer
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var Discard = AddSync(ioutil.Discard)
Discard is a convenience wrapper around ioutil.Discard.
Functions ¶
func NewHTTPHandler ¶
NewHTTPHandler returns an HTTP handler that can change the logging level at runtime.
GET requests return a JSON description of the current logging level. PUT requests change the logging level and expect a payload like
{"level":"info"}
Types ¶
type CheckedMessage ¶
type CheckedMessage struct {
// contains filtered or unexported fields
}
A CheckedMessage is the result of a call to Logger.Check, which allows especially performance-sensitive applications to avoid allocations for disabled or heavily sampled log levels.
Example ¶
package main import ( "github.com/uber-go/zap" ) func main() { logger := zap.NewJSON() // Stub the current time in tests. logger.StubTime() // By default, the debug logging level is disabled. However, calls to // logger.Debug will still allocate a slice to hold any passed fields. // Particularly performance-sensitive applications can avoid paying this // penalty by using checked messages. if cm := logger.Check(zap.DebugLevel, "This is a debug log."); cm.OK() { // Debug-level logging is disabled, so we won't get here. cm.Write(zap.Int("foo", 42), zap.Stack()) } if cm := logger.Check(zap.InfoLevel, "This is an info log."); cm.OK() { // Since info-level logging is enabled, we expect to write out this message. cm.Write() } }
Output: {"msg":"This is an info log.","level":"info","ts":0,"fields":{}}
func NewCheckedMessage ¶
func NewCheckedMessage(logger Logger, lvl Level, msg string) *CheckedMessage
NewCheckedMessage constructs a CheckedMessage. It's only intended for use by wrapper libraries, and shouldn't be necessary in application code.
func (*CheckedMessage) OK ¶
func (m *CheckedMessage) OK() bool
OK checks whether it's safe to call Write.
func (*CheckedMessage) Write ¶
func (m *CheckedMessage) Write(fields ...Field)
Write logs the pre-checked message with the supplied fields. It should only be used once; if a CheckedMessage is re-used, it also logs an error message with the underlying logger's DFatal method.
type Field ¶
type Field struct {
// contains filtered or unexported fields
}
A Field is a deferred marshaling operation used to add a key-value pair to a logger's context. Keys and values are appropriately escaped for the current encoding scheme (e.g., JSON).
func Duration ¶
Duration constructs a Field with the given key and value. It represents durations as an integer number of nanoseconds.
func Error ¶
Error constructs a Field that stores err.Error() under the key "error". This is just a convenient shortcut for a common pattern - apart from saving a few keystrokes, it's no different from using zap.String.
func Float64 ¶
Float64 constructs a Field with the given key and value. The floating-point value is encoded using strconv.FormatFloat's 'g' option (exponential notation for large exponents, grade-school notation otherwise).
func Marshaler ¶
func Marshaler(key string, val LogMarshaler) Field
Marshaler constructs a field with the given key and zap.LogMarshaler. It provides a flexible, but still type-safe and efficient, way to add user-defined types to the logging context.
Example ¶
package main import ( "time" "github.com/uber-go/zap" ) type Auth struct { ExpiresAt time.Time `json:"expires_at"` // Since we'll need to send the token to the browser, we include it in the // struct's JSON representation. Token string `json:"token"` } func (a Auth) MarshalLog(kv zap.KeyValue) error { kv.AddInt64("expires_at", a.ExpiresAt.UnixNano()) // We don't want to log sensitive data. kv.AddString("token", "---") return nil } type User struct { Name string `json:"name"` Age int `json:"age"` Auth Auth `auth:"auth"` } func (u User) MarshalLog(kv zap.KeyValue) error { kv.AddString("name", u.Name) kv.AddInt("age", u.Age) return kv.AddMarshaler("auth", u.Auth) } func main() { jane := User{ Name: "Jane Doe", Age: 42, Auth: Auth{ ExpiresAt: time.Unix(0, 100), Token: "super secret", }, } logger := zap.NewJSON() // Stub time in tests. logger.StubTime() logger.Info("Successful login.", zap.Marshaler("user", jane)) }
Output: {"msg":"Successful login.","level":"info","ts":0,"fields":{"user":{"name":"Jane Doe","age":42,"auth":{"expires_at":100,"token":"---"}}}}
func Nest ¶
Nest takes a key and a variadic number of Fields and creates a nested namespace.
Example ¶
package main import ( "github.com/uber-go/zap" ) func main() { logger := zap.NewJSON() // Stub the current time in tests. logger.StubTime() // We'd like the logging context to be {"outer":{"inner":42}} nest := zap.Nest("outer", zap.Int("inner", 42)) logger.Info("Logging a nested field.", nest) }
Output: {"msg":"Logging a nested field.","level":"info","ts":0,"fields":{"outer":{"inner":42}}}
func Object ¶
Object constructs a field with the given key and an arbitrary object. It uses an encoding-appropriate, reflection-based function to serialize nearly any object into the logging context, but it's relatively slow and allocation-heavy.
If encoding fails (e.g., trying to serialize a map[int]string to JSON), Object includes the error message in the final log output.
func Stack ¶
func Stack() Field
Stack constructs a Field that stores a stacktrace of the current goroutine under the key "stacktrace". Keep in mind that taking a stacktrace is extremely expensive (relatively speaking); this function both makes an allocation and takes ~10 microseconds.
type KeyValue ¶
type KeyValue interface { AddBool(string, bool) AddFloat64(string, float64) AddInt(string, int) AddInt64(string, int64) AddMarshaler(string, LogMarshaler) error // AddObject uses reflection to serialize arbitrary objects, so it's slow and // allocation-heavy. Consider implementing the LogMarshaler interface instead. AddObject(string, interface{}) AddString(string, string) Nest(string, func(KeyValue) error) error }
KeyValue is an encoding-agnostic interface to add structured data to the logging context. Like maps, KeyValues aren't safe for concurrent use (though typical use shouldn't require locks).
See Marshaler for an example.
type Level ¶
type Level int32
A Level is a logging priority. Higher levels are more important.
Note that Level satisfies the Option interface, so any Level can be passed to NewJSON to override the default logging priority.
const ( // DebugLevel logs are typically voluminous, and are usually disabled in // production. DebugLevel Level = iota - 1 // InfoLevel is the default logging priority. InfoLevel // WarnLevel logs are more important than Info, but don't need individual // human review. WarnLevel // ErrorLevel logs are high-priority. If an application is running smoothly, // it shouldn't generate any error-level logs. ErrorLevel // PanicLevel logs a message, then panics. PanicLevel // FatalLevel logs a message, then calls os.Exit(1). FatalLevel // AllLevel logs everything. AllLevel Level = math.MinInt32 // NoneLevel silences logging completely. NoneLevel Level = math.MaxInt32 )
func LevelFlag ¶
LevelFlag defines a Level flag with specified name, default value and usage string. The return value is the address of a Level value that stores the value of the flag.
func (*Level) MarshalText ¶
MarshalText marshals the Level to text. Note that the text representation drops the -Level suffix (see example).
Example ¶
package main import ( "encoding/json" "fmt" "github.com/uber-go/zap" ) func main() { level := zap.ErrorLevel s := struct { Level *zap.Level `json:"level"` }{&level} bytes, _ := json.Marshal(s) fmt.Println(string(bytes)) }
Output: {"level":"error"}
func (*Level) UnmarshalText ¶
UnmarshalText unmarshals text to a level. Like MarshalText, UnmarshalText expects the text representation of a Level to drop the -Level suffix (see example).
In particular, this makes it easy to configure logging levels using YAML, TOML, or JSON files.
Example ¶
package main import ( "encoding/json" "fmt" "github.com/uber-go/zap" ) func main() { var s struct { Level zap.Level `json:"level"` } // The zero value for a zap.Level is zap.InfoLevel. fmt.Println(s.Level) json.Unmarshal([]byte(`{"level":"error"}`), &s) fmt.Println(s.Level) }
Output: info error
type LogMarshaler ¶
LogMarshaler allows user-defined types to efficiently add themselves to the logging context, and to selectively omit information which shouldn't be included in logs (e.g., passwords).
type Logger ¶
type Logger interface { // Check if output at a specific level is enabled. Enabled(Level) bool // Check the minimum enabled log level. Level() Level // Change the level of this logger, as well as all its ancestors and // descendants. This makes it easy to change the log level at runtime // without restarting your application. SetLevel(Level) // Create a child logger, and optionally add some context to that logger. With(...Field) Logger // StubTime stops the logger from including the current time in each // message. Instead, it always reports the time as Unix epoch 0. (This is // useful in tests and examples.) // // TODO: remove this kludge in favor of a more comprehensive message-formatting // option. StubTime() // Check returns a CheckedMessage if logging a message at the specified level // is enabled. It's a completely optional optimization; in high-performance // applications, Check can help avoid allocating a slice to hold fields. // // See CheckedMessage for an example. Check(Level, string) *CheckedMessage // Log a message at the given level. Messages include any context that's // accumulated on the logger, as well as any fields added at the log site. Log(Level, string, ...Field) Debug(string, ...Field) Info(string, ...Field) Warn(string, ...Field) Error(string, ...Field) Panic(string, ...Field) Fatal(string, ...Field) // If the logger is in development mode (via the Development option), DFatal // logs at the Fatal level. Otherwise, it logs at the Error level. DFatal(string, ...Field) }
A Logger enables leveled, structured logging. All methods are safe for concurrent use.
func NewJSON ¶
NewJSON returns a logger that formats its output as JSON. Zap uses a customized JSON encoder to avoid reflection and minimize allocations.
By default, the logger will write Info logs or higher to standard out. Any errors during logging will be written to standard error.
Options can change the log level, the output location, or the initial fields that should be added as context.
Example ¶
package main import ( "github.com/uber-go/zap" ) func main() { // The default logger outputs to standard out and only writes logs that are // Info level or higher. logger := zap.NewJSON() // Stub the current time in tests. logger.StubTime() // The default logger does not print Debug logs. logger.Debug("This won't be printed.") logger.Info("This is an info log.") }
Output: {"msg":"This is an info log.","level":"info","ts":0,"fields":{}}
Example (Options) ¶
package main import ( "github.com/uber-go/zap" ) func main() { // We can pass multiple options to the NewJSON method to configure // the logging level, output location, or even the initial context. logger := zap.NewJSON( zap.DebugLevel, zap.Fields(zap.Int("count", 1)), ) // Stub the current time in tests. logger.StubTime() logger.Debug("This is a debug log.") logger.Info("This is an info log.") }
Output: {"msg":"This is a debug log.","level":"debug","ts":0,"fields":{"count":1}} {"msg":"This is an info log.","level":"info","ts":0,"fields":{"count":1}}
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
Option is used to set options for the logger.
func AddCaller ¶
func AddCaller() Option
AddCaller configures the Logger to annotate each message with the filename and line number of zap's caller.
func AddStacks ¶
AddStacks configures the Logger to record a stack trace for all messages at or above a given level. Keep in mind that this is (relatively speaking) quite expensive.
func Append ¶
func Append(appendFunc AppendFunc) Option
func Development ¶
func Development() Option
Development puts the logger in development mode, which alters the behavior of the DFatal method.
func ErrorOutput ¶
func ErrorOutput(w WriteSyncer) Option
ErrorOutput sets the destination for errors generated by the logger.
func Output ¶
func Output(w WriteSyncer) Option
Output sets the destination for the logger's output.
type WriteFlusher ¶
A WriteFlusher is an io.Writer that can also flush any buffered data.
type WriteSyncer ¶
A WriteSyncer is an io.Writer that can also flush any buffered data. Note that *os.File (and thus, os.Stderr and os.Stdout) implement WriteSyncer.
func AddSync ¶
func AddSync(w io.Writer) WriteSyncer
AddSync converts an io.Writer to a WriteSyncer. It attempts to be intelligent: if the concrete type of the io.Writer implements WriteSyncer or WriteFlusher, we'll use the existing Sync or Flush methods. If it doesn't, we'll add a no-op Sync method.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package spy provides an implementation of zap.Logger that helps test logging wrappers.
|
Package spy provides an implementation of zap.Logger that helps test logging wrappers. |
Package spywrite provides various I/O implementations with known errors.
|
Package spywrite provides various I/O implementations with known errors. |
Package testutils provides some simple testing helpers (most of which aren't specifically logging-related).
|
Package testutils provides some simple testing helpers (most of which aren't specifically logging-related). |
Package zbark provides a wrapper to make zap.Loggers compatible with the bark.Logger interface.
|
Package zbark provides a wrapper to make zap.Loggers compatible with the bark.Logger interface. |
Package zwrap provides a variety of wrappers for the core zap logger.
|
Package zwrap provides a variety of wrappers for the core zap logger. |