zap

package module
v0.0.0-...-bdba58c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 31, 2016 License: MIT Imports: 17 Imported by: 0

README

⚡ zap GoDoc Build Status Coverage Status

Blazing fast, structured, leveled logging in Go.

Installation

go get -u github.com/uber-go/zap

Structure

Zap takes an opinionated stance on logging and doesn't provide any printf-style helpers. Rather than logger.Printf("Failed to fetch URL %s (attempt %v), sleeping %s before retry.", url, tryNum, sleepFor), zap encourages the more structured

logger.Info("Failed to fetch URL.",
  zap.String("url", url),
  zap.Int("attempt", tryNum),
  zap.Duration("backoff", sleepFor),
)

This a bit more verbose, but it enables powerful ad-hoc analysis, flexible dashboarding, and accurate message bucketing. In short, it helps you get the most out of tools like ELK, Splunk, and Sentry. All log messages are JSON-serialized, though PRs to support other formats are welcome.

For compatibility with the standard library and bark, zap provides the zwrap.Standardize and zbark.Barkify wrappers. Both are slower than the core zap logger, but faster than the libraries they replace.

Performance

For applications that log in the hot path, reflection-based serialization and string formatting are prohibitively expensive — they're CPU-intensive and make many small allocations. Put differently, using encoding/json and fmt.Fprintf to log tons of interface{}s makes your application slow.

Zap takes a different approach. It includes a reflection-free, zero-allocation JSON encoder, and it offers a variety of type-safe ways to add structured context to your log messages. It strives to avoid serialization overhead and allocations wherever possible, so collecting rich debug logs doesn't impact normal operations.

As measured by its own benchmarking suite, not only is zap more performant than comparable structured logging libraries — it's also faster than the standard library. Like all benchmarks, take these with a grain of salt.1

Log a message and 10 fields:

Library Time Bytes Allocated Objects Allocated
⚡ zap 1279 ns/op 705 B/op 2 allocs/op
logrus 10369 ns/op 5275 B/op 78 allocs/op
go-kit 6969 ns/op 3204 B/op 70 allocs/op
log15 22246 ns/op 4783 B/op 91 allocs/op
apex/log 16379 ns/op 3608 B/op 63 allocs/op

Log a message using a logger that already has 10 fields of context:

Library Time Bytes Allocated Objects Allocated
⚡ zap 231 ns/op 0 B/op 0 allocs/op
logrus 8532 ns/op 3438 B/op 61 allocs/op
go-kit 6874 ns/op 2486 B/op 48 allocs/op
log15 20462 ns/op 4118 B/op 70 allocs/op
apex/log 13886 ns/op 2384 B/op 48 allocs/op

Log a static string, without any context or printf-style formatting:

Library Time Bytes Allocated Objects Allocated
⚡ zap 222 ns/op 0 B/op 0 allocs/op
standard library 565 ns/op 32 B/op 2 allocs/op
logrus 3085 ns/op 1336 B/op 26 allocs/op
go-kit 1061 ns/op 624 B/op 13 allocs/op
log15 5462 ns/op 1351 B/op 23 allocs/op
apex/log 3009 ns/op 584 B/op 11 allocs/op

Development Status: Beta

Ready for adventurous users, but we're planning several breaking changes before releasing version 1.0. This milestone tracks our progress toward a stable release.


Released under the [MIT License](LICENSE.txt).

1 In particular, keep in mind that we may be benchmarking against slightly older versions of other libraries. Versions are pinned in zap's glide.lock file.

Documentation

Overview

Package zap provides fast, structured, leveled logging in Go.

Example
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

Examples

Constants

This section is empty.

Variables

Discard is a convenience wrapper around ioutil.Discard.

Functions

func NewHTTPHandler

func NewHTTPHandler(logger Logger) http.Handler

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
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 Bool

func Bool(key string, val bool) Field

Bool constructs a Field with the given key and value.

func Duration

func Duration(key string, val time.Duration) Field

Duration constructs a Field with the given key and value. It represents durations as an integer number of nanoseconds.

func Err

func Err(err error) Field

Err constructs a Field that stores err.Error() under the key "error".

func Float64

func Float64(key string, val float64) Field

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 Int

func Int(key string, val int) Field

Int constructs a Field with the given key and value.

func Int64

func Int64(key string, val int64) Field

Int64 constructs a Field with the given key and value.

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
Output:

{"msg":"Successful login.","level":"info","ts":0,"fields":{"user":{"name":"Jane Doe","age":42,"auth":{"expires_at":100,"token":"---"}}}}

func Nest

func Nest(key string, fields ...Field) Field

Nest takes a key and a variadic number of Fields and creates a nested namespace.

Example
Output:

{"msg":"Logging a nested field.","level":"info","ts":0,"fields":{"outer":{"inner":42}}}

func Object

func Object(key string, val interface{}) Field

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.

func String

func String(key string, val string) Field

String constructs a Field with the given key and value.

func Stringer

func Stringer(key string, val fmt.Stringer) Field

Stringer constructs a Field with the given key and value. The value is the result of the String method.

func Time

func Time(key string, val time.Time) Field

Time constructs a Field with the given key and value. It represents a time.Time as nanoseconds since epoch.

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 (
	// Debug logs are typically voluminous, and are usually disabled in
	// production.
	Debug Level = iota - 1
	// Info is the default logging priority.
	Info
	// Warn logs are more important than Info, but don't need individual human review.
	Warn
	// Error logs are high-priority. If an application is running smoothly, it
	// shouldn't generate any error-level logs.
	Error
	// Panic logs a message, then panics.
	Panic
	// Fatal logs a message, then calls os.Exit(1).
	Fatal

	// All logs everything.
	All Level = math.MinInt32
	// None silences logging completely.
	None Level = math.MaxInt32
)

func LevelFlag

func LevelFlag(name string, defaultLevel Level, usage string) *Level

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

func (l *Level) MarshalText() ([]byte, error)

MarshalText satisfies text.Marshaler.

func (Level) String

func (l Level) String() string

String returns a lower-case ASCII representation of the log level.

func (*Level) UnmarshalText

func (l *Level) UnmarshalText(text []byte) error

UnmarshalText satisfies text.Unmarshaler.

In particular, this makes it easy to configure logging levels using YAML, TOML, or JSON files.

type LogMarshaler

type LogMarshaler interface {
	MarshalLog(KeyValue) error
}

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

func NewJSON(options ...Option) Logger

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
Output:

{"msg":"This is an info log.","level":"info","ts":0,"fields":{}}
Example (Options)
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

func AddStacks(lvl Level) Option

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 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 Fields

func Fields(fields ...Field) Option

Fields sets the initial fields for the logger.

func Output

func Output(w WriteSyncer) Option

Output sets the destination for the logger's output.

type WriteFlusher

type WriteFlusher interface {
	io.Writer
	Flush() error
}

A WriteFlusher is an io.Writer that can also flush any buffered data.

type WriteSyncer

type WriteSyncer interface {
	io.Writer
	Sync() error
}

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.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL