logkit

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2025 License: MIT Imports: 9 Imported by: 0

README

logkit

Go version Go Reference Go Report Card License

A lightweight, configurable logging toolkit for Go's slog with context support and validation.

Table of Contents

Features

  • Custom log levels: TRACE, VERBOSE, FATAL — beyond standard slog
  • Context-aware logging: automatically inject values from context.Context using typed keys
  • Configurable output: JSON or text format, custom time template, stdout/stderr or any custom writer
  • Functional options: clean, composable API via WithConfig, WithWriter, WithExtraContextFields
  • Validation: config errors are collected and reported clearly
  • Zero dependencies beyond Go standard library

Quick Start

import "github.com/Averlex/logkit"

// Create a default logger (JSON, ERROR level, stdout)
logger, err := logkit.NewLogger()
if err != nil {
    panic(err)
}

logger.Info(context.Background(), "Application started")
// Output: {"time":"05.04.2025 10:00:00.000","level":"INFO","msg":"Application started"}

Custom Configuration

// Configure logger with custom options
logger, err := logkit.NewLogger(
    logkit.WithConfig(map[string]any{
        "format":        "text",
        "level":         "debug",
        "time_template": "15:04:05",
        "log_stream":    "stdout",
    }),
)
if err != nil {
    log.Fatal(err)
}

logger.Debug(ctx, "Debug message")
// Output: time=15:04:05 level=DEBUG msg="Debug message"

Context-Aware Logging

Use WithExtraContextFields to automatically include values from context.Context in every log entry.

var RequestIDKey struct{}
func (RequestIDKey) String() string { return "request_id" }

logger, _ := logkit.NewLogger(logkit.WithExtraContextFields(RequestIDKey))
ctx := context.WithValue(context.Background(), RequestIDKey, "abc-123")
logger.Info(ctx, "Handling request")
// Output: {"time":"...","level":"INFO","msg":"Handling request","request_id":"abc-123"}
Key Requirements

Only string and fmt.Stringer keys are supported. This ensures compatibility with slog, which requires attribute keys to be strings.

  • If the context key is a string, it is used directly.
  • If the key implements fmt.Stringer, its String() method provides the attribute name.
  • All other key types are ignored.
Special Case: slog.Attr

If a value in the context is of type slog.Attr, it is logged as-is, preserving its key, value, and type. This allows full control over the logged attribute.

ctx := context.WithValue(ctx, key, slog.Int("user_id", 42))
logger.Info(ctx, "User action")
// Output includes: "user_id":42 with correct type

This makes logkit compatible with advanced slog patterns while keeping the API simple.

Custom Log Levels

Level Use case
TRACE Very detailed debugging
DEBUG Standard debug info
VERBOSE Between DEBUG and INFO
INFO General information
WARN Potential issues
ERROR Errors that don't crash the app
FATAL Critical errors; calls os.Exit(1)
logger.Trace(ctx, "Entering function")
logger.Verbose(ctx, "Processing batch")
logger.Fatal(ctx, "Failed to initialize", "error", err)

Advanced Usage

Custom Writer
file, _ := os.Create("app.log")
logger, _ := logkit.NewLogger(logkit.WithWriter(file))
Functional Options

Options can be combined:

logger, _ := logkit.NewLogger(
    logkit.WithDefaults(),
    logkit.WithConfig(customConfig),
    logkit.WithExtraContextFields(RequestIDKey, UserIDKey),
)

Error Handling

NewLogger returns an error if configuration is invalid:

if logger, err := logkit.NewLogger(invalidConfig); err != nil {
    log.Printf("Logger setup failed: %v", err)
    // Example: "config data is invalid: invalid_type=time_template, invalid_value=level,format"
}

⚠️ Note: Validation errors are accumulated — you’ll see all issues at once, not just the first one.

Testing

logkit is designed to be testable:

  • Accepts any io.Writer (use WithWriter option).
  • Supports JSON format - parse easily with encoding/json
  • No global state.

Here is a quick example:

var buf bytes.Buffer
logger, _ := logkit.NewLogger(logkit.WithWriter(&buf))

logger.Info(context.Background(), "test message")
// Parse buf.String() as JSON in test

Installation

go get github.com/Averlex/logkit

Documentation

Overview

Package logkit provides a structured logging wrapper over slog.Logger with enhanced context handling, custom levels, and flexible configuration.

Index

Constants

View Source
const (
	// DefaultTimeTemplate is a default time format string.
	DefaultTimeTemplate = "02.01.2006 15:04:05.000"
	// DefaultLogType is a default log type.
	DefaultLogType = "json"
	// DefaultLevel is a default log level.
	DefaultLevel = "error"
	// DefaultLevelValue is a default log level value.
	DefaultLevelValue = slog.LevelError
	// DefaultWriter is a default writer to use for logging.
	DefaultWriter = "stdout"
)
View Source
const (
	// LevelTrace is a trace log level - the lowest possible level.
	LevelTrace = slog.Level(-8)
	// LevelDebug is an alias for slog.LevelDebug.
	LevelDebug = slog.LevelDebug
	// LevelVerbose is a verbose log level - the middleground between Debug and Info levels.
	LevelVerbose = slog.Level(-2)
	// LevelInfo is an alias for slog.LevelInfo.
	LevelInfo = slog.LevelInfo
	// LevelWarn is an alias for slog.LevelWarn.
	LevelWarn = slog.LevelWarn
	// LevelError is an alias for slog.LevelError.
	LevelError = slog.LevelError
	// LevelFatal is a fatal log level - the highest possible level.
	LevelFatal = slog.Level(16)
)

Additional log levels.

Variables

View Source
var DefaultWriterValue = os.Stdout

DefaultWriterValue is a default writer value.

Functions

This section is empty.

Types

type Config

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

Config defines an inner logger configuration.

type Logger

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

Logger is a wrapper around slog.Logger that supports:

  • automatic context field injection.
  • custom log levels (TRACE, VERBOSE, FATAL).
  • configurable time format and output.

func NewLogger

func NewLogger(opts ...Option) (*Logger, error)

NewLogger returns a new Logger with the given log type and level. If no opts are provided, it returns a default logger.

The log type can be "text" or "json". The log level can be "debug", "info", "warn" or "error".

timeTemplate is a time format string. Any format which is valid for time.Time format is acceptable.

Empty log level corresponds to "error", as well as empty log type corresponds to "json". Empty time format is equal to the default value which is "02.01.2006 15:04:05.000". Empty writer option equals to using os.Stdout. Custom writer might be set using WithWriter option.

If the log type or level is unknown, it returns an error.

func (Logger) Debug

func (logg Logger) Debug(ctx context.Context, msg string, args ...any)

Debug logs a message with level Debug on the standard logger.

func (Logger) Error

func (logg Logger) Error(ctx context.Context, msg string, args ...any)

Error logs a message with level Error on the standard logger.

func (Logger) Fatal

func (logg Logger) Fatal(ctx context.Context, msg string, args ...any)

Fatal logs a message with level Error on the standard logger and then calls os.Exit(1).

func (Logger) Info

func (logg Logger) Info(ctx context.Context, msg string, args ...any)

Info logs a message with level Info on the standard logger.

func (Logger) Trace

func (logg Logger) Trace(ctx context.Context, msg string, args ...any)

Trace logs a message with level Trace on the standard logger.

func (Logger) Verbose

func (logg Logger) Verbose(ctx context.Context, msg string, args ...any)

Verbose logs a message with level Verbose on the standard logger.

func (Logger) Warn

func (logg Logger) Warn(ctx context.Context, msg string, args ...any)

Warn logs a message with level Warn on the standard logger.

func (Logger) With

func (logg Logger) With(args ...any) *Logger

With returns a new Logger that adds the given key-value pairs to the logger's context.

type Option

type Option func(c *Config) error

Option defines a function that allows to configure underlying logger on construction.

func WithConfig

func WithConfig(cfg map[string]any) Option

WithConfig allows to apply custom configuration. Expected following config structure:

{
		format        string, // "text" or "json"
		level         string, // "debug", "info", "warn", "error"
		time_template string, // any valid time format
		log_stream:   string, // "stdout", "stderr"
}

func WithDefaults

func WithDefaults() Option

WithDefaults applies default configuration to the logger. May be overwritten by WithConfig and/or WithWriter options.

func WithExtraContextFields

func WithExtraContextFields(fields ...any) Option

WithExtraContextFields configures the logger to automatically include values from the context in every log record, using the provided keys.

The keys must be comparable (as required by context.Context) and are used directly in ctx.Value(key) to retrieve the corresponding values. Compatible key types are:

  • string: used directly as the attribute key in logs.
  • Any type implementing fmt.Stringer: its String() method is used as the attribute key.

This includes named string types (e.g., type MyString string) that implement fmt.Stringer. The logger will use these keys to extract values from the context and add them as log attributes:

  • If a value is of type slog.Attr, it is added to the log as is - using internal key in slog.Attr pair.
  • Otherwise, it is added as a regular attribute with the key as described above.

If no key is found in the context, it is safely ignored by the logger.

Example:

var RequestIDKey struct{}
func (RequestIDKey) String() string { return "request_id" }

logger := NewLogger(WithExtraContextFields(RequestIDKey))
ctx := context.WithValue(ctx, RequestIDKey, "abc-123")
logger.Info(ctx, "event") // → request_id=abc-123

If no fields are provided, the option does nothing and returns nil. If any key types are invalid, a single error listing all erroneous types is returned.

func WithWriter

func WithWriter(w io.Writer) Option

WithWriter allows to apply custom configuration.

Jump to

Keyboard shortcuts

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