zap

package module
v0.1.0-beta.1 Latest Latest
Warning

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

Go to latest
Published: Feb 7, 2017 License: MIT Imports: 18 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 project 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
package main

import (
	"time"

	"github.com/uber-go/zap"
)

func main() {
	// Log in JSON, using zap's reflection-free JSON encoder. By default, loggers
	// write all InfoLevel and above logs to standard out.
	logger := zap.New(
		zap.NewJSONEncoder(zap.NoTime()), // drop timestamps in tests
	)

	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:

{"level":"warn","msg":"Log without structured data..."}
{"level":"warn","msg":"Or use strongly-typed wrappers to add structured context.","library":"zap","latency":1}
{"level":"error","msg":"Oh no!","user":"jane@test.com","visits":42}
Example (FileOutput)
package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/uber-go/zap"
)

func main() {
	// Create a temporary file to output logs to.
	f, err := ioutil.TempFile("", "log")
	if err != nil {
		panic("failed to create temporary file")
	}
	defer os.Remove(f.Name())

	logger := zap.New(
		zap.NewJSONEncoder(zap.NoTime()), // drop timestamps in tests
		// Write the logging output to the specified file instead of stdout.
		// Any type implementing zap.WriteSyncer or zap.WriteFlusher can be used.
		zap.Output(f),
	)

	logger.Info("This is an info log.", zap.Int("foo", 42))

	// Sync the file so logs are written to disk, and print the file contents.
	// zap will call Sync automatically when logging at FatalLevel or PanicLevel.
	f.Sync()
	contents, err := ioutil.ReadFile(f.Name())
	if err != nil {
		panic("failed to read temporary file")
	}

	fmt.Println(string(contents))
}
Output:

{"level":"info","msg":"This is an info log.","foo":42}

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// Discard is a convenience wrapper around ioutil.Discard.
	Discard = AddSync(ioutil.Discard)
	// DiscardOutput is an Option that discards logger output.
	DiscardOutput = Output(Discard)
)

Functions

This section is empty.

Types

type AtomicLevel

type AtomicLevel struct {
	// contains filtered or unexported fields
}

AtomicLevel wraps an atomically change-able Level value. It must be created by the DynamicLevel() function to allocate the internal atomic pointer.

func DynamicLevel

func DynamicLevel() AtomicLevel

DynamicLevel creates an atomically changeable dynamic logging level. The returned level can be passed as a logger option just like a concrete level.

The value's SetLevel() method may be called later to change the enabled logging level of all loggers that were passed the value (either explicitly, or by creating sub-loggers with Logger.With).

func (AtomicLevel) Enabled

func (lvl AtomicLevel) Enabled(l Level) bool

Enabled loads the level value, and calls its Enabled method.

func (AtomicLevel) Level

func (lvl AtomicLevel) Level() Level

Level returns the minimum enabled log level.

func (AtomicLevel) ServeHTTP

func (lvl AtomicLevel) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP supports changing logging level with an HTTP request.

GET requests return a JSON description of the current logging level. PUT requests change the logging level and expect a payload like:

{"level":"info"}

func (AtomicLevel) SetLevel

func (lvl AtomicLevel) SetLevel(l Level)

SetLevel alters the logging level.

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.New(
		zap.NewJSONEncoder(zap.NoTime()), // drop timestamps in tests
	)

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

{"level":"info","msg":"This is an info log."}

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) Chain

func (m *CheckedMessage) Chain(ms ...*CheckedMessage) *CheckedMessage

Chain combines two or more CheckedMessages. If the receiver message is not OK(), the passed message is returned. Otherwise if the passed message is OK(), then it is retained such that its Write() will be called after the receiver's Write(), and any previously Chain()'ed messages already so retained.

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 will call the underlying level method (Debug, Info, Warn, Error, DPanic, Panic, and Fatal) for the defined levels; the Log method is only called for unknown logging levels.

It MUST be called at most once, since Write will return the *CheckedMessage to an internal pool for potentially immediate re-use; re-using a *CheckedMessage after calling Write() will result in data races or other undefined behavior. An attempt is made to detect and DPanic log any re-use, but such detection is not guaranteed due to race conditions.

type Encoder

type Encoder interface {
	KeyValue

	// Copy the encoder, ensuring that adding fields to the copy doesn't affect
	// the original.
	Clone() Encoder
	// Return the encoder to the appropriate sync.Pool. Unpooled encoder
	// implementations can no-op this method.
	Free()
	// Write the supplied message, level, and timestamp to the writer, along with
	// any accumulated context.
	WriteEntry(io.Writer, string, Level, time.Time) error
}

Encoder is a format-agnostic interface for all log entry marshalers. Since log encoders don't need to support the same wide range of use cases as general-purpose marshalers, it's possible to make them much faster and lower-allocation.

Implementations of the KeyValue interface's methods can, of course, freely modify the receiver. However, the Clone and WriteEntry methods will be called concurrently and shouldn't modify the receiver.

func NewJSONEncoder

func NewJSONEncoder(options ...JSONOption) Encoder

NewJSONEncoder creates a fast, low-allocation JSON encoder. By default, JSON encoders put the log message under the "msg" key, the timestamp (as floating-point seconds since epoch) under the "ts" key, and the log level under the "level" key. The encoder appropriately escapes all field keys and values.

Note that the encoder doesn't deduplicate keys, so it's possible to produce a message like

{"foo":"bar","foo":"baz"}

This is permitted by the JSON specification, but not encouraged. Many libraries will ignore duplicate key-value pairs (typically keeping the last pair) when unmarshaling, but users should attempt to avoid adding duplicate keys.

Example
package main

import (
	"github.com/uber-go/zap"
)

func main() {
	// An encoder with the default settings.
	zap.NewJSONEncoder()

	// Dropping timestamps is often useful in tests.
	zap.NewJSONEncoder(zap.NoTime())

	// In production, customize the encoder to work with your log aggregation
	// system.
	zap.NewJSONEncoder(
		zap.RFC3339Formatter("@timestamp"), // human-readable timestamps
		zap.MessageKey("@message"),         // customize the message key
		zap.LevelString("@level"),          // stringify the log level
	)
}
Output:

func NewTextEncoder

func NewTextEncoder(options ...TextOption) Encoder

NewTextEncoder creates a line-oriented text encoder whose output is optimized for human, rather than machine, consumption. By default, the encoder uses RFC3339-formatted timestamps.

Example
package main

import (
	"time"

	"github.com/uber-go/zap"
)

func main() {
	// A text encoder with the default settings.
	zap.NewTextEncoder()

	// Dropping timestamps is often useful in tests.
	zap.NewTextEncoder(zap.TextNoTime())

	// If you don't like the default timestamp formatting, choose another.
	zap.NewTextEncoder(zap.TextTimeFormat(time.RFC822))
}
Output:

func NullEncoder

func NullEncoder() Encoder

NullEncoder returns the fast, no-allocation encoder.

type Entry

type Entry struct {
	Level   Level
	Time    time.Time
	Message string
	// contains filtered or unexported fields
}

An Entry represents a complete log message. The entry's structured context is already serialized, but the log level, time, and message are available for inspection and modification.

Entries are pooled, so any functions that accept them must be careful not to retain references to them.

func (Entry) Fields

func (e Entry) Fields() KeyValue

Fields returns a mutable reference to the entry's accumulated context.

type Field added in v1.8.0

type Field struct {
	// contains filtered or unexported fields
}

A Field is a marshaling operation used to add a key-value pair to a logger's context. Most fields are lazily marshaled, so it's inexpensive to add fields to disabled debug-level log statements.

func Base64

func Base64(key string, val []byte) Field

Base64 constructs a field that encodes the given value as a padded base64 string. The byte slice is converted to a base64 string eagerly.

func Bool

func Bool(key string, val bool) Field

Bool constructs a Field with the given key and value. Bools are marshaled lazily.

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 Error

func Error(err error) Field

Error constructs a Field that lazily stores err.Error() under the key "error". If passed a nil error, the field is a no-op.

func Float64

func Float64(key string, val float64) Field

Float64 constructs a Field with the given key and value. The way the floating-point value is represented is encoder-dependent, so marshaling is necessarily lazy.

func Int

func Int(key string, val int) Field

Int constructs a Field with the given key and value. Marshaling ints is lazy.

func Int64

func Int64(key string, val int64) Field

Int64 constructs a Field with the given key and value. Like ints, int64s are marshaled lazily.

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. The LogMarshaler's MarshalLog method is called lazily.

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.New(zap.NewJSONEncoder(zap.NoTime()))
	logger.Info("Successful login.", zap.Marshaler("user", jane))

}
Output:

{"level":"info","msg":"Successful login.","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
package main

import (
	"github.com/uber-go/zap"
)

func main() {
	logger := zap.New(
		zap.NewJSONEncoder(zap.NoTime()), // drop timestamps in tests
	)

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

{"level":"info","msg":"Logging a nested field.","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 lazily 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 Skip

func Skip() Field

Skip constructs a no-op Field.

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 eager and 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 the output of the value's String method. The Stringer's String method is called lazily.

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 a floating-point number of seconds since epoch. Conversion to a float64 happens eagerly.

func Uint

func Uint(key string, val uint) Field

Uint constructs a Field with the given key and value.

func Uint64

func Uint64(key string, val uint64) Field

Uint64 constructs a Field with the given key and value.

func Uintptr

func Uintptr(key string, val uintptr) Field

Uintptr constructs a Field with the given key and value.

func (Field) AddTo

func (f Field) AddTo(kv KeyValue)

AddTo exports a field through the KeyValue interface. It's primarily useful to library authors, and shouldn't be necessary in most applications.

type Hook

type Hook func(*Entry) error

A Hook is executed each time the logger writes an Entry. It can modify the entry (including adding context to Entry.Fields()), but must not retain references to the entry or any of its contents. Returned errors are written to the logger's error output.

Hooks implement the Option interface.

type JSONOption

type JSONOption interface {
	// contains filtered or unexported methods
}

JSONOption is used to set options for a JSON encoder. MessageFormatters, TimeFormatters, and LevelFormatters all implement the JSONOption interface.

type KeyValue

type KeyValue interface {
	AddBool(key string, value bool)
	AddFloat64(key string, value float64)
	AddInt(key string, value int)
	AddInt64(key string, value int64)
	AddUint(key string, value uint)
	AddUint64(key string, value uint64)
	AddUintptr(key string, value uintptr)
	AddMarshaler(key string, marshaler LogMarshaler) error
	// AddObject uses reflection to serialize arbitrary objects, so it's slow and
	// allocation-heavy. Consider implementing the LogMarshaler interface instead.
	AddObject(key string, value interface{}) error
	AddString(key, value string)
}

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 New to override the default logging priority.

const (

	// DebugLevel logs are typically voluminous, and are usually disabled in
	// production.
	DebugLevel Level
	// 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
	// DPanicLevel logs are particularly important errors. In development the
	// logger panics after writing the message.
	DPanicLevel
	// PanicLevel logs a message, then panics.
	PanicLevel
	// FatalLevel logs a message, then calls os.Exit(1).
	FatalLevel
)

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) Enabled

func (l Level) Enabled(lvl Level) bool

Enabled returns true if the given level is at or above this level.

func (*Level) Get

func (l *Level) Get() interface{}

Get gets the level for the flag.Getter interface.

func (*Level) MarshalText

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

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) Set

func (l *Level) Set(s string) error

Set sets the level for the flag.Value interface.

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

type LevelEnabler interface {
	Enabled(Level) bool
}

LevelEnabler decides whether a given logging level is enabled when logging a message.

Enablers are intended to be used to implement deterministic filters; concerns like sampling are better implemented as a Logger implementation.

Each concrete Level value implements a static LevelEnabler which returns true for itself and all higher logging levels. For example WarnLevel.Enabled() will return true for WarnLevel, ErrorLevel, PanicLevel, and FatalLevel, but return false for InfoLevel and DebugLevel.

type LevelEnablerFunc

type LevelEnablerFunc func(Level) bool

LevelEnablerFunc is a convenient way to implement LevelEnabler around an anonymous function. It is also a valid Option to pass to a logger.

func (LevelEnablerFunc) Enabled

func (f LevelEnablerFunc) Enabled(lvl Level) bool

Enabled calls the wrapped function.

type LevelFormatter

type LevelFormatter func(Level) Field

A LevelFormatter defines how to convert an entry's logging level into a Field. LevelFormatters implement the JSONOption interface.

func LevelString

func LevelString(key string) LevelFormatter

LevelString encodes the entry's level under the provided key. It uses the level's String method to serialize it.

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 LogMarshalerFunc

type LogMarshalerFunc func(KeyValue) error

LogMarshalerFunc is a type adapter that allows using a function as a LogMarshaler.

func (LogMarshalerFunc) MarshalLog

func (f LogMarshalerFunc) MarshalLog(kv KeyValue) error

MarshalLog calls the underlying function.

type Logger

type Logger interface {
	// Create a child logger, and optionally add some context to that logger.
	With(...Field) Logger

	// 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.
	//
	// Calling Panic should panic() and calling Fatal should terminate the
	// process, but calling Log(PanicLevel, ...) or Log(FatalLevel, ...) should
	// not. It may not be possible for compatibility wrappers to comply with
	// this last part (e.g. the bark wrapper).
	Log(Level, string, ...Field)
	Debug(string, ...Field)
	Info(string, ...Field)
	Warn(string, ...Field)
	Error(string, ...Field)
	DPanic(string, ...Field)
	Panic(string, ...Field)
	Fatal(string, ...Field)
}

A Logger enables leveled, structured logging. All methods are safe for concurrent use.

func New

func New(enc Encoder, options ...Option) Logger

New constructs a logger that uses the provided encoder. 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, the initial fields that should be added as context, and many other behaviors.

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.New(zap.NewJSONEncoder(
		zap.NoTime(), // drop timestamps in tests
	))

	// The default logger does not print Debug logs.
	logger.Debug("This won't be printed.")
	logger.Info("This is an info log.")

}
Output:

{"level":"info","msg":"This is an info log."}
Example (Options)
package main

import (
	"github.com/uber-go/zap"
)

func main() {
	// We can pass multiple options to the New method to configure the logging
	// level, output location, or even the initial context.
	logger := zap.New(
		zap.NewJSONEncoder(zap.NoTime()), // drop timestamps in tests
		zap.DebugLevel,
		zap.Fields(zap.Int("count", 1)),
	)

	logger.Debug("This is a debug log.")
	logger.Info("This is an info log.")

}
Output:

{"level":"debug","msg":"This is a debug log.","count":1}
{"level":"info","msg":"This is an info log.","count":1}
Example (TextEncoder)
package main

import (
	"github.com/uber-go/zap"
)

func main() {
	// For more human-readable output in the console, use a TextEncoder.
	textLogger := zap.New(zap.NewTextEncoder(
		zap.TextNoTime(), // drop timestamps in tests.
	))

	textLogger.Info("This is a text log.", zap.Int("foo", 42))

}
Output:

[I] This is a text log. foo=42

func Tee

func Tee(logs ...Logger) Logger

Tee creates a Logger that duplicates its log calls to two or more loggers. It is similar to io.MultiWriter.

For each logging level method (.Debug, .Info, etc), the Tee calls each sub-logger's level method.

Exceptions are made for the DPanic, Panic, and Fatal methods: the returned logger calls .Log(DPanicLevel, ...), .Log(PanicLevel, ...), and .Log(FatalLevel, ...) respectively. Only after all sub-loggers have received the message, then the Tee terminates the process (using os.Exit or panic() per usual semantics).

NOTE: DPanic will currently never panic, since the Tee Logger does not accept options (nor even have a development flag).

Check returns a CheckedMessage chain of any OK CheckedMessages returned by all sub-loggers. The returned message is OK if any of the sub-messages are. An exception is made for FatalLevel and PanicLevel, where a CheckedMessage is returned against the Tee itself. This is so that tlog.Check(PanicLevel, ...).Write(...) is equivalent to tlog.Panic(...) (likewise for FatalLevel).

Example
package main

import (
	"os"

	"github.com/uber-go/zap"
)

func main() {
	// Multiple loggers can be combine using Tee.
	output := zap.Output(os.Stdout)
	logger := zap.Tee(
		zap.New(zap.NewTextEncoder(zap.TextNoTime()), output),
		zap.New(zap.NewJSONEncoder(zap.NoTime()), output),
	)

	logger.Info("this log gets encoded twice, differently", zap.Int("foo", 42))
}
Output:

[I] this log gets encoded twice, differently foo=42
{"level":"info","msg":"this log gets encoded twice, differently","foo":42}

type MessageFormatter

type MessageFormatter func(string) Field

A MessageFormatter defines how to convert a log message into a Field. MessageFormatters implement the JSONOption interface.

func MessageKey

func MessageKey(key string) MessageFormatter

MessageKey encodes log messages under the provided key.

type Meta

type Meta struct {
	LevelEnabler

	Development bool
	Encoder     Encoder
	Hooks       []Hook
	Output      WriteSyncer
	ErrorOutput WriteSyncer
}

Meta is implementation-agnostic state management for Loggers. Most Logger implementations can reduce the required boilerplate by embedding a Meta.

Note that while the level-related fields and methods are safe for concurrent use, the remaining fields are not.

func MakeMeta

func MakeMeta(enc Encoder, options ...Option) Meta

MakeMeta returns a new meta struct with sensible defaults: logging at InfoLevel, development mode off, and writing to standard error and standard out.

func (Meta) Check

func (m Meta) Check(log Logger, lvl Level, msg string) *CheckedMessage

Check returns a CheckedMessage logging the given message is Enabled, nil otherwise.

func (Meta) Clone

func (m Meta) Clone() Meta

Clone creates a copy of the meta struct. It deep-copies the encoder, but not the hooks (since they rarely change).

func (Meta) Encode

func (m Meta) Encode(w io.Writer, t time.Time, lvl Level, msg string, fields []Field) error

Encode runs any Hook functions and then writes an encoded log entry to the given io.Writer, returning any error.

func (Meta) InternalError

func (m Meta) InternalError(cause string, err error)

InternalError prints an internal error message to the configured ErrorOutput. This method should only be used to report internal logger problems and should not be used to report user-caused problems.

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 DPanic method.

func ErrorOutput

func ErrorOutput(w WriteSyncer) Option

ErrorOutput sets the destination for errors generated by the logger. The supplied WriteSyncer is automatically wrapped with a mutex, so it need not be safe for concurrent use.

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. The supplied WriteSyncer is automatically wrapped with a mutex, so it need not be safe for concurrent use.

type TextOption

type TextOption interface {
	// contains filtered or unexported methods
}

A TextOption is used to set options for a text encoder.

func TextNoTime

func TextNoTime() TextOption

TextNoTime omits timestamps from the serialized log entries.

func TextTimeFormat

func TextTimeFormat(layout string) TextOption

TextTimeFormat sets the format for log timestamps, using the same layout strings supported by time.Parse.

type TimeFormatter

type TimeFormatter func(time.Time) Field

A TimeFormatter defines how to convert the time of a log entry into a Field. TimeFormatters implement the JSONOption interface.

func EpochFormatter

func EpochFormatter(key string) TimeFormatter

EpochFormatter uses the Time field (floating-point seconds since epoch) to encode the entry time under the provided key.

func NoTime

func NoTime() TimeFormatter

NoTime drops the entry time altogether. It's often useful in testing, since it removes the need to stub time.Now.

func RFC3339Formatter

func RFC3339Formatter(key string) TimeFormatter

RFC3339Formatter encodes the entry time as an RFC3339-formatted string under the provided key.

func RFC3339NanoFormatter

func RFC3339NanoFormatter(key string) TimeFormatter

RFC3339NanoFormatter encodes the entry time as an RFC3339-formatted string with nanosecond precision under the provided key.

func UnixNanoFormatter

func UnixNanoFormatter(key string) TimeFormatter

UnixNanoFormatter encodes the entry time as a single int64 with nanosecond precision under the provided key.

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.

func MultiWriteSyncer

func MultiWriteSyncer(ws ...WriteSyncer) WriteSyncer

MultiWriteSyncer creates a WriteSyncer that duplicates its writes and sync calls, similarly to to io.MultiWriter.

Example
package main

import (
	"os"

	"github.com/uber-go/zap"
)

func main() {
	// To send output to multiple outputs, use MultiWriteSyncer.
	textLogger := zap.New(
		zap.NewTextEncoder(zap.TextNoTime()),
		zap.Output(zap.MultiWriteSyncer(os.Stdout, os.Stdout)),
	)

	textLogger.Info("One becomes two")
}
Output:

[I] One becomes two
[I] One becomes two

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 and a wrapper to make bark.Loggers compatible with zap.Logger interface.
Package zbark provides a wrapper to make zap.Loggers compatible with the bark.Logger interface and a wrapper to make bark.Loggers compatible with zap.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