Simple and minimal logger in Go for my projects.
Find a file
2026-04-25 20:35:03 +00:00
.gitignore Initial commit 2026-04-25 20:12:29 +00:00
console_stream.go restructured logger from budigt 2026-04-25 20:35:03 +00:00
console_stream_test.go restructured logger from budigt 2026-04-25 20:35:03 +00:00
file_rotation.go restructured logger from budigt 2026-04-25 20:35:03 +00:00
file_stream.go restructured logger from budigt 2026-04-25 20:35:03 +00:00
file_stream_test.go restructured logger from budigt 2026-04-25 20:35:03 +00:00
go.mod restructured logger from budigt 2026-04-25 20:35:03 +00:00
LICENSE Initial commit 2026-04-25 20:12:29 +00:00
logger.go restructured logger from budigt 2026-04-25 20:35:03 +00:00
logger_test.go restructured logger from budigt 2026-04-25 20:35:03 +00:00
README.md restructured logger from budigt 2026-04-25 20:35:03 +00:00
splinter.go restructured logger from budigt 2026-04-25 20:35:03 +00:00
stream.go restructured logger from budigt 2026-04-25 20:35:03 +00:00

splinter

Simple and minimal logger in Go for my projects.

Fans out structured records to one or more streams. Ships with a console stream (JSON or pretty text) and a file stream with size- and time-based rotation, optional gzip compression, and backup pruning.

Install

go get git.juancwu.dev/juancwu/splinter

Requires Go 1.26 or newer.

Quick start

The package exposes a default logger that writes JSON to stderr at LevelInfo:

package main

import "git.juancwu.dev/juancwu/splinter"

func main() {
    splinter.Info("server started", "port", 8080)
    splinter.Error("request failed", "err", "timeout")
}

Custom logger with file output and rotation

package main

import (
    "time"

    "git.juancwu.dev/juancwu/splinter"
)

func main() {
    logger := splinter.New(
        splinter.WithStream(splinter.NewConsoleStream(
            splinter.ConsolePretty, splinter.LevelDebug,
        )),
        splinter.WithStream(splinter.MustFileStream("logs/app.log", splinter.FileStreamConfig{
            Level:      splinter.LevelInfo,
            Format:     splinter.FileJSON,
            MaxSizeMB:  100,              // rotate at 100 MB
            MaxAge:     24 * time.Hour,   // and at least once per day
            MaxBackups: 7,                // keep the 7 most recent files
            Compress:   true,             // gzip rotated backups
        })),
        splinter.WithAttrs(map[string]any{"service": "api"}),
    )
    defer logger.Close()

    splinter.SetDefault(logger)

    splinter.Info("ready")
}

Child loggers

Logger.With returns a child that inherits streams and merges additional attributes onto every record:

req := logger.With(map[string]any{"request_id": id})
req.Info("handled", "status", 200)

Custom streams

Implement the Stream interface to send logs anywhere — a database, a message queue, an HTTP endpoint, an in-memory buffer for tests:

type Stream interface {
    Name() string
    Write(ctx context.Context, rec splinter.Record) error
    Enabled(level splinter.Level) bool
    Close() error
}

Add it with splinter.WithStream(myStream) at construction time.

Configuration reference

ConsoleStream

Constructor Behaviour
NewConsoleStream(ConsoleJSON, level) One JSON object per line on stderr.
NewConsoleStream(ConsolePretty, level) key=value text on stderr.
ConsoleWriter(w) option Override the destination writer.

FileStream

Field Default Notes
Level LevelInfo Minimum level written to the file.
Format FileJSON FileJSON or FileText.
MaxSizeMB 100 Rotation threshold in MB. 0 disables size-based rotation.
MaxAge 0 Rotation threshold by age. 0 disables time-based rotation.
MaxBackups 5 Number of rotated files to retain (raw + .gz combined).
Compress false gzip rotated files asynchronously after rename.

When both MaxSizeMB and MaxAge are zero, MaxSizeMB defaults to 100 to prevent unbounded growth.

License

MIT — see LICENSE.