slogutils

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2023 License: MIT Imports: 12 Imported by: 0

README

slog utilities

Utilities and handlers for the Go log/slog package.

go get github.com/networkteam/slogutils

Features

CLI handler

  • Unobstrusive minimal logging output for humans (no timestamps, no log levels)
  • Supports ReplaceAttr as in slog.HandlerOptions
  • Grouping and quoting of attributes
  • Prefixes, colors and paddings can be fully customized
  • Supports an additional slogutils.LevelTrace level that is below slog.LevelDebug and can be used for tracing
Example
package main

import (
	"context"
	"errors"
	"log/slog"
	"os"
	"time"

	"github.com/networkteam/slogutils"
)

func main() {
	slog.SetDefault(slog.New(
		slogutils.NewCLIHandler(os.Stderr, &slogutils.CLIHandlerOptions{
			Level: slogutils.LevelTrace,
		}),
	))

	slog.Info("Starting server", "addr", ":8080", "env", "production")
	slog.Debug("Connected to DB", "db", "myapp", "host", "localhost:5432")
	slog.Warn("Slow request", "method", "GET", "path", "/users", "duration", 497*time.Millisecond)
	slog.Error("DB connection lost", slogutils.Err(errors.New("connection reset")), "db", "myapp")
	// This is a non-standard log level that is below debug
	slog.Log(context.Background(), slogutils.LevelTrace, "Trace message", "foo", "bar")
}

Context helper

Setting a logger instance with groups / attributes on a context is very useful e.g. in request processing or distributed tracing.

  • Use slogutils.FromContext to get a logger instance from a context (or slog.Default() as a fallback)
  • Use slogutils.WithLogger to set a logger instance on a context
Example
package main

import (
	"log/slog"
	"net/http"
	"time"
)

func main() {
	// An HTTP middleware with a simple request ID
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		logger := slogutils.FromContext(r.Context())
		logger.Info("Handling main route")
	})

	http.ListenAndServe(":8080", withRequestID(mux))
}

func withRequestID(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		requestID := time.Now().UnixNano() // Note: use a better request ID based on UUIDs in production

		// Get the logger from the request context and add the request ID as an attribute,
		// then set the logger back to a new context.
		logger := slogutils.FromContext(r.Context()).With(slog.Group("request", "id", requestID))
		ctx := slogutils.WithLogger(r.Context(), logger)

		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

Acknowledgements

Documentation

Overview

Example
package main

import (
	"errors"
	"log/slog"
	"os"
	"time"

	"github.com/networkteam/slogutils"
)

func main() {
	slog.SetDefault(slog.New(slogutils.NewCLIHandler(os.Stderr, &slogutils.CLIHandlerOptions{
		Level: slog.LevelDebug,
	})))

	slog.Info("Starting server", "addr", ":8080", "env", "production")
	slog.Debug("Connected to DB", "db", "myapp", "host", "localhost:5432")
	slog.Warn("Slow request", "method", "GET", "path", "/users", "duration", 497*time.Millisecond)
	slog.Error("DB connection lost", slogutils.Err(errors.New("connection reset")), "db", "myapp")
}
Output:

Index

Examples

Constants

View Source
const (
	// ErrorKey is the key for an error attribute.
	ErrorKey = "err"
)

Keys for special attributes.

View Source
const (
	// LevelTrace is an extra level for tracing that is lower than debug.
	LevelTrace slog.Level = -8
)

Variables

This section is empty.

Functions

func Err

func Err(err error) slog.Attr

func FromContext

func FromContext(ctx context.Context) *slog.Logger

FromContext returns a logger instance from the context or the default logger.

func WithLogger

func WithLogger(ctx context.Context, logger *slog.Logger) context.Context

WithLogger sets the logger instance as a value in the context and returns the new context. The logger instance can be retrieved from the context using FromContext.

Types

type CLIHandler

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

func NewCLIHandler

func NewCLIHandler(w io.Writer, opts *CLIHandlerOptions) *CLIHandler

func (*CLIHandler) Enabled

func (h *CLIHandler) Enabled(ctx context.Context, level slog.Level) bool

func (*CLIHandler) Handle

func (h *CLIHandler) Handle(ctx context.Context, r slog.Record) error

func (*CLIHandler) WithAttrs

func (h *CLIHandler) WithAttrs(attrs []slog.Attr) slog.Handler

func (*CLIHandler) WithGroup

func (h *CLIHandler) WithGroup(name string) slog.Handler

type CLIHandlerOptions

type CLIHandlerOptions struct {
	// Level reports the minimum record level that will be logged.
	// The handler discards records with lower levels.
	// If Level is nil, the handler assumes LevelInfo.
	// The handler calls Level.Level for each record processed;
	// to adjust the minimum level dynamically, use a LevelVar.
	Level slog.Leveler

	// Prefix options for setting a custom padding and level prefixes.
	Prefix *PrefixOptions

	// LevelColors can set a custom map of level colors.
	// It must be complete, i.e. contain all levels.
	LevelColors map[slog.Level]*color.Color

	// MessagePadding is the number of spaces to pad the message with.
	// A default of 25 is used if this is 0.
	// Setting it to a negative value disables padding.
	MessagePadding int

	// ReplaceAttr is called to rewrite each non-group attribute before it is logged.
	// See https://pkg.go.dev/log/slog#HandlerOptions for details.
	ReplaceAttr func(groups []string, attr slog.Attr) slog.Attr
}

CLIHandlerOptions are options for a CLIHandler. A zero CLIHandlerOptions consists entirely of default values.

type PrefixOptions

type PrefixOptions struct {
	// Padding is the number of spaces to pad the prefix with.
	Padding int

	// Prefixes can set a custom map of prefixes for each level.
	// It must be complete, i.e. contain all levels.
	Prefixes map[slog.Level]string
}

Jump to

Keyboard shortcuts

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