zlog

package module
v2.0.0-alpha.2 Latest Latest
Warning

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

Go to latest
Published: Dec 12, 2023 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package zlog is an slog.Handler implementation focused on performant contextual logging.

Journald

On Linux sytems, this package will automatically upgrade to speaking the native Journald protocol using the heuristic outlined on systemd.io. For this process, some information must be gathered via proc(5); exotic runtime configurations may not support this. The values "wmem_default" and "wmem_max" are consulted to determine optimal settings for the opened socket to journald and for when the memfd-based (see memfd_create(2) and unix(7)) protocol must be used.

Prose output

If ProseFormat is set, output will be in prose rather than JSON. The field order is not configurable. ANSI color codes and terminal hyperlinks will be used when attached to a TTY. The environment variables "NO_COLOR" and "ZLOG_COLORS" can be used to control colors. Log records are separated by a ␞, fields are separated by a ␟, and the attributes are separated from the message with a ␝. These field separators may trip up incorrect programs.

ZLOG_COLORS

The "ZLOG_COLORS" environment variable is akin to "LS_COLORS". It is a colon-delimited series of SGR parameters. Any characters outside of the range [0-;] will be ignored. The controllable colors are, in order:

All left-ward elements must be present, but may be empty. For example, to highlight only errors:

ZLOG_COLORS='::::::::::::::5';
export ZLOG_COLORS

See DefaultProseColors for the default colors.

Example
h := NewHandler(os.Stdout, &ExampleOpts)
slog.New(h).With("a", "b").Info("test", "c", "d")
Output:

{"level":"INFO","msg":"test","a":"b","c":"d"}
Example (Baggage)
BaggageOpts := Options{
	OmitTime:   true,
	OmitSource: true,
	Baggage:    func(_ string) bool { return true },
}
b := must(baggage.New(
	must(baggage.NewMember("test_kind", "example")),
))
ctx := baggage.ContextWithBaggage(context.Background(), b)
h := NewHandler(os.Stdout, &BaggageOpts)
slog.New(h).InfoContext(ctx, "test")
Output:

{"level":"INFO","msg":"test","baggage":{"test_kind":"example"}}
Example (Pprof)
ctx := pprof.WithLabels(context.Background(), pprof.Labels("test_kind", "example"))
pprof.SetGoroutineLabels(ctx)
h := NewHandler(os.Stdout, &ExampleOpts)
slog.New(h).InfoContext(ctx, "test")
Output:

{"level":"INFO","msg":"test","goroutine":{"test_kind":"example"}}

Index

Examples

Constants

View Source
const DefaultProseColors = `31:33:32:3:96:93::36::1;32:1;31:1;33:32:95:33:4:34:35:21:91`

DefaultProseColors are the colors used when the "ZLOG_COLORS" environment variable isn't set.

Variables

View Source
var (
	// Everything is just a nice low number to almost certainly catch anything
	// emitted.
	LevelEverything = slog.Level(-100)

	SyslogDebug    = slog.LevelDebug
	SyslogInfo     = slog.LevelInfo
	SyslogNotice   = slog.LevelInfo + 2
	SyslogWarning  = slog.LevelWarn
	SyslogError    = slog.LevelError
	SyslogCritical = slog.LevelError + 4
	SyslogAlert    = slog.LevelError + 8
	// Emergency is documented as "a panic condition".
	//
	// This package does no special handling for Go panics.
	SyslogEmergency = slog.LevelError + 12
)

Some extra slog.Level aliases and syslog(3) compatible levels (as implemented in this package).

The syslog mapping attempts to keep the slog convention of a 4-count gap between levels.

Functions

func NewHandler

func NewHandler(w io.Writer, opts *Options) slog.Handler

NewHandler returns an slog.Handler emitting records to "w", according to the provided options.

If "nil" is passed for options, suitable defaults will be used. On Linux systems, the journald native protocol will be used if the process is launched with the appropriate environment variables and the passed io.Writer is os.Stderr. The default for a process running inside a Kubernetes container or as systemd service is to not emit timestamps.

func WithAttrs

func WithAttrs(ctx context.Context, args ...any) context.Context

WithAttrs records the provided arguments to be added as additional slog.Attr elements to any records created with the returned context.

Adding Attrs for a previously added Key replaces that Attr in the returned Context. To remove an Attr, use an empty slog.Group as the value.

This is more expensive than adding Attrs via slog.Logger.With, which should be preferred when function signatures allow.

Example
opts := Options{
	OmitTime:   true,
	OmitSource: true,
}
ctx := context.Background()
h := NewHandler(os.Stdout, &opts)
l := slog.New(h)
l.InfoContext(ctx, "without ctx attrs", "a", "b")
ctx = WithAttrs(ctx, "contextual", "value")
l.InfoContext(ctx, "with ctx attrs", "a", "b")
{
	ctx := WithLevel(ctx, slog.LevelDebug)
	l.DebugContext(ctx, "with ctx attrs", "a", "b")
}
ctx = WithAttrs(ctx, "contextual", slog.GroupValue())
l.InfoContext(ctx, "removed ctx attrs", "a", "b")
Output:

{"level":"INFO","msg":"without ctx attrs","a":"b"}
{"level":"INFO","msg":"with ctx attrs","contextual":"value","a":"b"}
{"level":"DEBUG","msg":"with ctx attrs","contextual":"value","a":"b"}
{"level":"INFO","msg":"removed ctx attrs","a":"b"}

func WithLevel

func WithLevel(ctx context.Context, l slog.Level) context.Context

WithLevel overrides the minimum log level for all records created with the returned context.

Example
opts := Options{
	OmitTime:   true,
	OmitSource: true,
}
levels := []slog.Level{slog.LevelDebug, slog.LevelInfo, slog.LevelWarn, slog.LevelError}
ctx := context.Background()
h := NewHandler(os.Stdout, &opts)
for _, l := range levels {
	ctx := WithLevel(ctx, l)
	for i, l := range levels {
		slog.New(h).LogAttrs(ctx, l, "normal log message", slog.Int("i", i))
	}
}
Output:

{"level":"DEBUG","msg":"normal log message","i":0}
{"level":"INFO","msg":"normal log message","i":1}
{"level":"WARN","msg":"normal log message","i":2}
{"level":"ERROR","msg":"normal log message","i":3}
{"level":"INFO","msg":"normal log message","i":1}
{"level":"WARN","msg":"normal log message","i":2}
{"level":"ERROR","msg":"normal log message","i":3}
{"level":"WARN","msg":"normal log message","i":2}
{"level":"ERROR","msg":"normal log message","i":3}
{"level":"ERROR","msg":"normal log message","i":3}

Types

type Options

type Options struct {
	// Level is the minimum level that a log message must have to be processed
	// by the Handler.
	//
	// This can be overridden on a per-message basis by [WithLevel].
	Level slog.Leveler
	// Baggage is a selection function for keys in the OpenTelemetry Baggage
	// contained in the [context.Context] used with a log message.
	Baggage func(key string) bool
	// WriteError is a hook for receiving errors that occurred while attempting
	// to write the log message.
	//
	// The [slog] logging methods current do not have any means of reporting the
	// errors that Handler implementations return.
	WriteError func(context.Context, error)
	// OmitSource controls whether source position information should be
	// emitted.
	OmitSource bool
	// OmitTime controls whether a timestamp should be emitted.
	OmitTime bool
	//  ProseFormat controls whether the lines should be emitted in prose or
	//  JSON format.
	//
	// When connected to the Journal, this setting has no effect.
	ProseFormat bool
	// contains filtered or unexported fields
}

Options is used to configure the slog.Handler returned by NewHandler.

Notes

Bugs

  • The JSON encoding behavior for DEL (0x7F) seems wrong, but matches Go's encoding/json behavior.

Jump to

Keyboard shortcuts

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