logging

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 8 Imported by: 0

README

slogenv

Slog setup I use across projects.

Text output goes through tint, the only non-stdlib dependency.

Usage

cfg, err := logging.ConfigFromEnv()
if err != nil {
	return err
}
closer, err := logging.Setup(cfg, requestid.LogAttrs)
if err != nil {
	return err
}
defer func() { _ = closer.Close() }()

Setup installs the default logger with slog.SetDefault and echoes the resolved config at Info. NewHandler is the same construction without the global write, for a caller that wants its own *slog.Logger:

h, closer, err := logging.NewHandler(cfg, nil)

The returned io.Closer closes the log file. A no-op in case of stdout.

Environment

Var Values Default Notes
LOG_LEVEL debug info warn error info Minimum log level being printed.
LOG_FORMAT text json text text is a human readable format (colorized if using stdout); json is for machines.
LOG_FILE file path (empty -> stdout) If set, logs go to this file only.
LOG_TIME sec milli nano dt-sec dt-milli rfc3339 rfc3339nano dt-milli timestamp layout; dt- means the date is printed. Ignored if LOG_FORMAT is json (always RFC3339Nano).

Values are trimmed and lowercased. An unknown one is an error. Config's zero value resolves to the same defaults.

Context attrs

Passed using function

type AttrsFunc func(ctx context.Context) []slog.Attr

Example

func LogAttrs(ctx context.Context) []slog.Attr {
	if id := FromContext(ctx); id != "" {
		return []slog.Attr{slog.String("request_id", id)}
	}
	return nil
}

Attrs injected right after the message, ahead of the call site's own attrs. A nil AttrsFunc leaves the record untouched.

May be used without the rest of the package:

slog.New(logging.NewContextHandler(myHandler, requestid.LogAttrs))

Tests

go test ./...
go test -race ./...         

Documentation

Overview

Package logging configures log/slog from the environment: a level, an encoding, a timestamp layout and an optional log file.

Text output goes through github.com/lmittmann/tint, which colorizes the level and an http-style "status" attr when the destination is a terminal.

NewHandler builds a handler and touches no global state. Setup is the same thing installed with slog.SetDefault, which is what a main usually wants.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewContextHandler

func NewContextHandler(next slog.Handler, fn AttrsFunc) slog.Handler

See https://pkg.go.dev/log/slog#example-Handler-LevelHandler and https://github.com/golang/example/blob/master/slog-handler-guide/README.md

Wraps next so every record carries the attrs fn reports for its ctx. slog handlers ignore the ctx by default, so without this every *Context call site would have to repeat those attrs.

A nil fn returns next unchanged.

func NewHandler

func NewHandler(cfg Config, fn AttrsFunc) (slog.Handler, io.Closer, error)

Builds the handler cfg describes. Handler wraps call to fn: it would add attrs which fn AttrsFunc returns from the context. The returned io.Closer closes the log file. It is a no-op when writing to stdout.

func Setup

func Setup(cfg Config, fn AttrsFunc) (io.Closer, error)

uses NewHandler as the default logger. Logs one Info record echoing the config.

Types

type AttrsFunc

type AttrsFunc func(ctx context.Context) []slog.Attr

AttrsFunc pulls ctx-scoped attrs, e.g. a request correlation id. Returning nil or an empty slice leaves the record untouched.

type Config

type Config struct {
	Level      slog.Level
	Format     Format
	TimeFormat TimeFormat
	File       string // empty writes to stdout
}

Config is a logging setup. Its zero value resolves to the documented defaults.

func ConfigFromEnv

func ConfigFromEnv() (Config, error)

Env vars:

  • LOG_LEVEL: debug | info (default) | warn | error
  • LOG_FORMAT: text (default) | json
  • LOG_FILE: path; empty writes to stdout (default)
  • LOG_TIME: sec | milli | nano | dt-sec | dt-milli (default) | rfc3339 | rfc3339nano; text timestamp layout ('dt-' prefixed ones add the date). json is unaffected, it always writes RFC3339Nano.

type Format

type Format string

Format selects the log encoding: maps to the slog.Handler type. Configured via LOG_FORMAT. The zero value resolves to FormatText.

const (
	FormatText Format = "text"
	FormatJSON Format = "json"
)

type TimeFormat

type TimeFormat string

TimeFormat selects the text handler's timestamp layout. Configured via LOG_TIME. The zero value resolves to TimeDateMilli.

const (
	TimeSec         TimeFormat = "sec"
	TimeMilli       TimeFormat = "milli"
	TimeNano        TimeFormat = "nano"
	TimeDateSec     TimeFormat = "dt-sec"
	TimeDateMilli   TimeFormat = "dt-milli"
	TimeRFC3339     TimeFormat = "rfc3339"
	TimeRFC3339Nano TimeFormat = "rfc3339nano"
)

Jump to

Keyboard shortcuts

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