author

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 23, 2026 License: MIT Imports: 10 Imported by: 0

README

   █████████   █████  █████ ███████████ █████   █████    ███████    ███████████  
  ███░░░░░███ ░░███  ░░███ ░█░░░███░░░█░░███   ░░███   ███░░░░░███ ░░███░░░░░███ 
 ░███    ░███  ░███   ░███ ░   ░███  ░  ░███    ░███  ███     ░░███ ░███    ░███ 
 ░███████████  ░███   ░███     ░███     ░███████████ ░███      ░███ ░██████████  
 ░███░░░░░███  ░███   ░███     ░███     ░███░░░░░███ ░███      ░███ ░███░░░░░███ 
 ░███    ░███  ░███   ░███     ░███     ░███    ░███ ░░███     ███  ░███    ░███ 
 █████   █████ ░░████████      █████    █████   █████ ░░░███████░   █████   █████
░░░░░   ░░░░░   ░░░░░░░░      ░░░░░    ░░░░░   ░░░░░    ░░░░░░░    ░░░░░   ░░░░░ 
    

Zero-allocation structured logger for Go.

Currently under active development and breaking changes are possible

Install

go get github.com/0x626f/author

Quick start

logger := author.New(author.Config{
    Level: author.INFO,
})

logger.Info("server started")
// INFO: server started

logger.Info("user %s connected (id=%d)", "alice", 42)
// INFO: user alice connected (id=42)

Config

logger := author.New(author.Config{
    Level:     author.INFO,
    Format:    author.Terminal, // author.Terminal (default) or author.JSON
    Name:      "api",         // adds [api] prefix to every line
    Timestamp: true,          // prepends timestamp to every line
    Out:       os.Stdout,     // defaults to os.Stdout
    Err:       os.Stderr,     // defaults to os.Stderr
})

Log levels

Levels are ordered: FATAL < ERROR < WARNING < INFO < DEBUG < TRACE < NONE. Setting Level suppresses everything above it.

logger.Trace("entering reconcile loop")
logger.Debug("query took %dms", 12)
logger.Info("listening on :%d", 8080)
logger.Warning("retry %d of 3", attempt)
logger.Error("connection refused: %v", err)
logger.Log("raw message without a level") // requires Level=author.NONE

Error writes to Err, everything else writes to Out.

Bound attributes

Calling With on a logger creates and returns a single-use LogRecord. Attributes belong to that record and do not mutate the logger or leak into other records. Record builders are intentionally lock-free: build and finish each record from one goroutine.

record := logger.With("env", "prod").
    With("region", "eu-west-1")

record.Info("server ready")
// INFO: server ready env: prod region: eu-west-1

Calling With on a record returns the same record, enabling fluent chaining. Calling it again with the same key overwrites the previous value on that record. A log method is terminal; do not reuse the record afterward.

Bound records

Use a LogRecord to build the attributes for one log event. Attribute updates append directly without synchronization, and the record proxies its output through the logger it is bound to.

record := logger.Record()
record.With("component", "checkout").
    With("region", "eu-west-1")

record.Info("request accepted")
// INFO: request accepted component: checkout region: eu-west-1

logger.With(...) is shorthand for creating a record and applying the first attribute.

LogRecord and JsonLogRecord instances are backed by separate internal sync.Pools. Calling any log method clears and returns the record to its pool automatically. Do not share an unfinished record between goroutines or use it after a log method. The Logger remains safe for concurrent calls; each goroutine should acquire its own record.

JSON output

Set Format to author.JSON to emit regular log calls as JSON:

logger := author.New(author.Config{
    Level:  author.INFO,
    Format: author.JSON,
})

logger.Info("server started on port %d", 8080)
// {"level":"INFO","message":"server started on port 8080"}

To add typed fields, create a single-use JsonLogRecord with JSON():

record := logger.JSON().
    String("env", "prod").
    Int("port", 8080).
    Bool("tls", true).
    Float64("latency_ms", 142.7)

record.Info("request handled")
// {"env":"prod","port":8080,"tls":true,"latency_ms":142.7,"level":"INFO","message":"request handled"}

The log call clears and internally recycles the record. Create a new JSON record for the next event.

Available field types: String, Byte, Bytes, Bool, Int, Int8, Int16, Int32, Int64, UInt, UInt8, UInt16, UInt32, UInt64, Float32, Float64, StringArray, ByteArray, BoolArray, IntArray (and all numeric array variants).

Nested objects

Implement JSONMarshaller to embed a struct as a nested JSON object.

type User struct{ ID int; Role string }

func (u *User) Marshall(r *author.JsonLogRecord) {
    r.Int("id", u.ID).String("role", u.Role)
}

record := logger.JSON().Object("user", &User{ID: 1, Role: "admin"})
record.Info("access granted")
// {"user":{"id":1,"role":"admin"},"level":"INFO","message":"access granted"}

Attributes in JSON

With attributes appear as fields in the JSON object too.

record := logger.JSON().Int("port", 8080)
record.With("env", "prod").Info("ready")
// {"env":"prod","port":8080,"level":"INFO","message":"ready"}

Context

Store a logger in a context.Context and retrieve it anywhere downstream.

ctx := logger.Ctx(context.Background())

// later, in a handler or downstream function:
author.Ctx(ctx).Info("handling request")

Ctx(ctx) panics if no logger was stored.

To capture selected values from any context chain, pass their keys to WithContextValues:

type contextKey string

const (
    requestIDKey contextKey = "request_id"
    traceIDKey   contextKey = "trace_id"
)

ctx := context.WithValue(context.Background(), requestIDKey, "req-123")
ctx = context.WithValue(ctx, traceIDKey, "trace-456")

record := logger.WithContextValues(ctx, requestIDKey, traceIDKey)
record.Info("handling request")
// INFO: handling request request_id: req-123 trace_id: trace-456

On a logger, WithContextValues creates and returns a new LogRecord. On an existing record, it adds the attributes and returns that same record. It captures the nearest value for each requested key and uses fmt.Sprint(key) as its attribute name. Nil keys and missing values are ignored. Go contexts cannot be enumerated, so every desired key must be requested explicitly. Logger, LogRecord, and JsonLogRecord all implement IAttributeLogger and therefore ILogger.

Parsing log level from config

var cfg struct {
    LogLevel author.LogLevel `env:"LOG_LEVEL"`
}
// also available directly:
level := author.ParseLogLevel("debug") // returns author.DEBUG

Benchmarks

Run the Author benchmarks with:

go test -run '^$' -bench . -benchmem -benchtime=500ms -count=5

Representative medians on Go 1.25.5, Linux/amd64, AMD Ryzen AI 7 350, and GOMAXPROCS=16, writing to io.Discard:

Path ns/op B/op allocs/op
Terminal Info 19.8 0 0
JSON Info 30.9 0 0
JSON formatted Info 100.8 0 0
Empty JsonLogRecord 37.0 0 0
JsonLogRecord, 3 typed fields 71.9 0 0
JsonLogRecord, 10 typed fields 178.3 0 0
Bound With(...).Info(...) 84.7 0 0
Filtered terminal Info 1.37 0 0

Typed JsonLogRecord fields are the zero-allocation path. Dynamically sourced values passed through the generic With(name, value any) API can incur interface-boxing allocations.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Name            string
	Level           LogLevel
	Format          LogFormat
	Timestamp       bool
	TimestampFormat string
	Out, Err        io.Writer
}

type IAttributeLogger added in v0.2.0

type IAttributeLogger interface {
	ILogger

	// With binds an attribute and returns the logging primitive that owns it.
	// Logger returns a new LogRecord; records return themselves.
	With(name string, value any) IAttributeLogger
	// WithContextValues captures each ctx.Value(key) under the fmt.Sprint(key)
	// name and returns the logging primitive that owns the attributes. Keys that
	// are nil or absent from the context are ignored.
	WithContextValues(ctx context.Context, keys ...any) IAttributeLogger
}

IAttributeLogger describes a logger that can bind attributes to a log event.

type ILogger added in v0.2.0

type ILogger interface {
	Log(msg string, args ...any)
	Trace(msg string, args ...any)
	Debug(msg string, args ...any)
	Info(msg string, args ...any)
	Warning(msg string, args ...any)
	Error(msg string, args ...any)
	Fatal(msg string, args ...any)
	Panic(msg string, args ...any)
}

ILogger describes all logging primitives exposed by author.

type JSONMarshaller

type JSONMarshaller interface {
	Marshall(*JsonLogRecord)
}

JSONMarshaller writes the fields of a nested JSON object.

type JSONRecord

type JSONRecord = JsonLogRecord

JSONRecord is retained as a source-compatible alias.

type JsonLogRecord added in v0.2.0

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

JsonLogRecord is a single-goroutine, single-use structured record bound to a Logger. It owns the complete JSON event buffer; a log method writes that buffer directly, then returns the record to its internal pool.

func NewJSONLogRecord added in v0.2.0

func NewJSONLogRecord(logger *Logger) *JsonLogRecord

NewJSONLogRecord acquires a single-use JSON record bound to logger.

func (*JsonLogRecord) Bool added in v0.2.0

func (record *JsonLogRecord) Bool(name string, value bool) *JsonLogRecord

func (*JsonLogRecord) BoolArray added in v0.2.0

func (record *JsonLogRecord) BoolArray(name string, value []bool) *JsonLogRecord

func (*JsonLogRecord) Byte added in v0.2.0

func (record *JsonLogRecord) Byte(name string, value byte) *JsonLogRecord

func (*JsonLogRecord) ByteArray added in v0.2.0

func (record *JsonLogRecord) ByteArray(name string, value []byte) *JsonLogRecord

func (*JsonLogRecord) Bytes added in v0.2.0

func (record *JsonLogRecord) Bytes(name string, value []byte) *JsonLogRecord

func (*JsonLogRecord) Debug added in v0.2.0

func (record *JsonLogRecord) Debug(msg string, args ...any)

func (*JsonLogRecord) Error added in v0.2.0

func (record *JsonLogRecord) Error(msg string, args ...any)

func (*JsonLogRecord) Fatal added in v0.2.0

func (record *JsonLogRecord) Fatal(msg string, args ...any)

func (*JsonLogRecord) Float32 added in v0.2.0

func (record *JsonLogRecord) Float32(name string, value float32) *JsonLogRecord

func (*JsonLogRecord) Float32Array added in v0.2.0

func (record *JsonLogRecord) Float32Array(name string, value []float32) *JsonLogRecord

func (*JsonLogRecord) Float64 added in v0.2.0

func (record *JsonLogRecord) Float64(name string, value float64) *JsonLogRecord

func (*JsonLogRecord) Float64Array added in v0.2.0

func (record *JsonLogRecord) Float64Array(name string, value []float64) *JsonLogRecord

func (*JsonLogRecord) Info added in v0.2.0

func (record *JsonLogRecord) Info(msg string, args ...any)

func (*JsonLogRecord) Int added in v0.2.0

func (record *JsonLogRecord) Int(name string, value int) *JsonLogRecord

func (*JsonLogRecord) Int8 added in v0.2.0

func (record *JsonLogRecord) Int8(name string, value int8) *JsonLogRecord

func (*JsonLogRecord) Int8Array added in v0.2.0

func (record *JsonLogRecord) Int8Array(name string, value []int8) *JsonLogRecord

func (*JsonLogRecord) Int16 added in v0.2.0

func (record *JsonLogRecord) Int16(name string, value int16) *JsonLogRecord

func (*JsonLogRecord) Int16Array added in v0.2.0

func (record *JsonLogRecord) Int16Array(name string, value []int16) *JsonLogRecord

func (*JsonLogRecord) Int32 added in v0.2.0

func (record *JsonLogRecord) Int32(name string, value int32) *JsonLogRecord

func (*JsonLogRecord) Int32Array added in v0.2.0

func (record *JsonLogRecord) Int32Array(name string, value []int32) *JsonLogRecord

func (*JsonLogRecord) Int64 added in v0.2.0

func (record *JsonLogRecord) Int64(name string, value int64) *JsonLogRecord

func (*JsonLogRecord) Int64Array added in v0.2.0

func (record *JsonLogRecord) Int64Array(name string, value []int64) *JsonLogRecord

func (*JsonLogRecord) IntArray added in v0.2.0

func (record *JsonLogRecord) IntArray(name string, value []int) *JsonLogRecord

func (*JsonLogRecord) Log added in v0.2.0

func (record *JsonLogRecord) Log(msg string, args ...any)

func (*JsonLogRecord) Object added in v0.2.0

func (record *JsonLogRecord) Object(name string, value JSONMarshaller) *JsonLogRecord

func (*JsonLogRecord) Panic added in v0.2.0

func (record *JsonLogRecord) Panic(msg string, args ...any)

func (*JsonLogRecord) String added in v0.2.0

func (record *JsonLogRecord) String(name string, value string) *JsonLogRecord

func (*JsonLogRecord) StringArray added in v0.2.0

func (record *JsonLogRecord) StringArray(name string, value []string) *JsonLogRecord

func (*JsonLogRecord) Trace added in v0.2.0

func (record *JsonLogRecord) Trace(msg string, args ...any)

func (*JsonLogRecord) UInt added in v0.2.0

func (record *JsonLogRecord) UInt(name string, value uint) *JsonLogRecord

func (*JsonLogRecord) UInt8 added in v0.2.0

func (record *JsonLogRecord) UInt8(name string, value uint8) *JsonLogRecord

func (*JsonLogRecord) UInt8Array added in v0.2.0

func (record *JsonLogRecord) UInt8Array(name string, value []uint8) *JsonLogRecord

func (*JsonLogRecord) UInt16 added in v0.2.0

func (record *JsonLogRecord) UInt16(name string, value uint16) *JsonLogRecord

func (*JsonLogRecord) UInt16Array added in v0.2.0

func (record *JsonLogRecord) UInt16Array(name string, value []uint16) *JsonLogRecord

func (*JsonLogRecord) UInt32 added in v0.2.0

func (record *JsonLogRecord) UInt32(name string, value uint32) *JsonLogRecord

func (*JsonLogRecord) UInt32Array added in v0.2.0

func (record *JsonLogRecord) UInt32Array(name string, value []uint32) *JsonLogRecord

func (*JsonLogRecord) UInt64 added in v0.2.0

func (record *JsonLogRecord) UInt64(name string, value uint64) *JsonLogRecord

func (*JsonLogRecord) UInt64Array added in v0.2.0

func (record *JsonLogRecord) UInt64Array(name string, value []uint64) *JsonLogRecord

func (*JsonLogRecord) UIntArray added in v0.2.0

func (record *JsonLogRecord) UIntArray(name string, value []uint) *JsonLogRecord

func (*JsonLogRecord) Warning added in v0.2.0

func (record *JsonLogRecord) Warning(msg string, args ...any)

func (*JsonLogRecord) With added in v0.2.0

func (record *JsonLogRecord) With(name string, value any) IAttributeLogger

With adds an attribute to record and returns record for fluent calls.

func (*JsonLogRecord) WithContextValues added in v0.2.0

func (record *JsonLogRecord) WithContextValues(ctx context.Context, keys ...any) IAttributeLogger

WithContextValues adds selected context values and returns record.

type LogFormat added in v0.2.0

type LogFormat uint8
const (
	Terminal LogFormat = iota
	JSON
)

type LogLevel

type LogLevel uint8
const (
	FATAL LogLevel = iota
	ERROR
	WARNING
	INFO
	DEBUG
	TRACE
	NONE
)

func ParseLogLevel

func ParseLogLevel(level string) LogLevel

func (*LogLevel) String

func (level *LogLevel) String() string

func (*LogLevel) UnmarshalText

func (level *LogLevel) UnmarshalText(text []byte) error

type LogRecord added in v0.2.0

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

LogRecord is a single-goroutine, single-use set of attributes bound to a Logger. A log method is terminal and returns the record to its internal pool.

func (*LogRecord) Debug added in v0.2.0

func (record *LogRecord) Debug(msg string, args ...any)

func (*LogRecord) Error added in v0.2.0

func (record *LogRecord) Error(msg string, args ...any)

func (*LogRecord) Fatal added in v0.2.0

func (record *LogRecord) Fatal(msg string, args ...any)

func (*LogRecord) Info added in v0.2.0

func (record *LogRecord) Info(msg string, args ...any)

func (*LogRecord) Log added in v0.2.0

func (record *LogRecord) Log(msg string, args ...any)

func (*LogRecord) Panic added in v0.2.0

func (record *LogRecord) Panic(msg string, args ...any)

func (*LogRecord) Trace added in v0.2.0

func (record *LogRecord) Trace(msg string, args ...any)

func (*LogRecord) Warning added in v0.2.0

func (record *LogRecord) Warning(msg string, args ...any)

func (*LogRecord) With added in v0.2.0

func (record *LogRecord) With(name string, value any) IAttributeLogger

With adds an attribute to record and returns record for fluent calls.

func (*LogRecord) WithContextValues added in v0.2.0

func (record *LogRecord) WithContextValues(ctx context.Context, keys ...any) IAttributeLogger

WithContextValues adds selected context values and returns record.

type Logger

type Logger struct {
	Config
	// contains filtered or unexported fields
}

func Ctx

func Ctx(ctx context.Context) *Logger

func New

func New(config ...Config) *Logger

func (*Logger) Ctx

func (logger *Logger) Ctx(parent context.Context) context.Context

func (*Logger) Debug

func (logger *Logger) Debug(msg string, args ...any)

func (*Logger) Error

func (logger *Logger) Error(msg string, args ...any)

func (*Logger) Fatal

func (logger *Logger) Fatal(msg string, args ...any)

func (*Logger) Info

func (logger *Logger) Info(msg string, args ...any)

func (*Logger) JSON

func (logger *Logger) JSON() *JsonLogRecord

JSON acquires a single-use JSON record bound to logger.

func (*Logger) Log

func (logger *Logger) Log(msg string, args ...any)

func (*Logger) Panic

func (logger *Logger) Panic(msg string, args ...any)

func (*Logger) Record added in v0.2.0

func (logger *Logger) Record() *LogRecord

Record acquires a single-use attribute record bound to logger.

func (*Logger) Trace

func (logger *Logger) Trace(msg string, args ...any)

func (*Logger) Warning

func (logger *Logger) Warning(msg string, args ...any)

func (*Logger) With

func (logger *Logger) With(name string, value any) IAttributeLogger

With acquires a bound LogRecord containing the attribute.

func (*Logger) WithContextValues added in v0.2.0

func (logger *Logger) WithContextValues(ctx context.Context, keys ...any) IAttributeLogger

WithContextValues acquires a bound LogRecord containing the selected values.

Jump to

Keyboard shortcuts

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