slogbetterstack

package module
v1.5.0 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 17 Imported by: 0

README

Better Stack Go client

Better Stack dashboard

MIT License Latest version build

Experience SQL-compatible structured log management based on ClickHouse. Learn more ⇗

Documentation

Getting started ⇗

Need help?

Please let us know at hello@betterstack.com. We're happy to help!

Credits

slog-betterstack was created and maintained by Samuel Berthe and released under the MIT license. Tomáš Procházka reported that records logged before exit were lost, and his analysis of the official clients shaped the delivery defaults and the drop accounting.

Thank you, Samuel and Tomáš! ❤️


MIT license, example project

Documentation

Overview

Package slogbetterstack sends the logs of a Go application to Better Stack through a log/slog handler.

handler := slogbetterstack.Option{
	Token:    "$SOURCE_TOKEN",
	Endpoint: "https://$INGESTING_HOST/",
	Level:    slog.LevelInfo, // Debug if omitted
}.NewBetterstackHandler()
defer handler.Close()

logger := slog.New(handler)
logger.Info("Hello from Better Stack!", "service", "UserService")

Records are queued and uploaded in batches by a background goroutine, so logging never waits for the network. Close delivers what is still queued and must run before the program exits; os.Exit and log.Fatal skip deferred calls. Delivery failures, and a missing token, are reported through Option.OnError, on stderr by default, and counted in Stats.

See https://betterstack.com/docs/logs/go/ for the full documentation.

Index

Constants

View Source
const BetterstackEndpoint = "https://in.logs.betterstack.com/"

Variables

View Source
var ContextKey = "extra"
View Source
var ErrClosed = errors.New("slog-betterstack: the handler is closed")

ErrClosed is returned by Handle and Flush once the handler has been closed.

View Source
var ErrMissingToken = errors.New("slog-betterstack: no source token configured, records are dropped")

ErrMissingToken is returned by Handle, and reported through OnError once, when the handler was built without a source token. Nothing is sent and every record is counted as dropped.

View Source
var ErrorKeys = []string{"error", "err"}
View Source
var SourceKey = "runtime"

Functions

func DefaultConverter

func DefaultConverter(addSource bool, replaceAttr func(groups []string, a slog.Attr) slog.Attr, loggerAttr []slog.Attr, groups []string, record *slog.Record) map[string]any

Types

type BetterstackHandler

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

BetterstackHandler is a slog.Handler that sends records to Better Stack. Handlers derived with WithAttrs and WithGroup share the queue and the uploads of the handler they came from, and Close on any of them closes all of them.

func (*BetterstackHandler) Close added in v1.5.0

func (h *BetterstackHandler) Close() error

Close delivers what is still queued, waits for the uploads in flight up to ShutdownTimeout and stops the background goroutine. It must run before the program exits: records are batched, so without it the last ones are lost. Note that os.Exit and log.Fatal skip deferred calls. Close is safe to call more than once; later calls return the first result.

func (*BetterstackHandler) Enabled

func (h *BetterstackHandler) Enabled(_ context.Context, level slog.Level) bool

func (*BetterstackHandler) Flush added in v1.5.0

func (h *BetterstackHandler) Flush(ctx context.Context) error

Flush uploads every record queued so far and returns once Better Stack has acknowledged them, a delivery failed for good, or ctx is done. Failures are reported through OnError.

func (*BetterstackHandler) Handle

func (h *BetterstackHandler) Handle(ctx context.Context, record slog.Record) error

Handle converts the record and queues it for upload. It never waits for the network: when the queue is full the record is dropped and counted. After Close it returns ErrClosed.

func (*BetterstackHandler) Stats added in v1.5.0

func (h *BetterstackHandler) Stats() Stats

Stats reports what happened to the records handed to this handler and the ones derived from it.

func (*BetterstackHandler) WithAttrs

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

func (*BetterstackHandler) WithGroup

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

type Converter

type Converter func(addSource bool, replaceAttr func(groups []string, a slog.Attr) slog.Attr, loggerAttr []slog.Attr, groups []string, record *slog.Record) map[string]any

type Option

type Option struct {
	// log level (default: debug)
	Level slog.Leveler

	// source token; without it the handler reports the omission through OnError once and
	// drops every record instead of sending anything
	Token string
	// optional: endpoint
	Endpoint string
	// optional: how long one upload attempt may take (default: 10s)
	Timeout time.Duration

	// optional: customize record builder
	Converter Converter
	// optional: custom marshaler, called with the []map[string]any of a batch's records
	Marshaler func(v any) ([]byte, error)
	// optional: fetch attributes from context
	AttrFromContext []func(ctx context.Context) []slog.Attr

	// optional: see slog.HandlerOptions
	AddSource   bool
	ReplaceAttr func(groups []string, a slog.Attr) slog.Attr

	// optional: records per upload (default: 1000)
	BatchSize int
	// optional: how long a partial batch waits before it is uploaded (default: 1s)
	BatchInterval time.Duration
	// optional: records the queue holds while uploads are behind; further records are
	// dropped and counted rather than blocking the application (default: 100000)
	MaxQueueSize int
	// optional: concurrent uploads (default: 5)
	MaxInFlight int
	// optional: retries after a failed attempt, for 408, 429, 5xx and network errors;
	// negative disables retries (default: 5)
	MaxRetries int
	// optional: base delay before a retry, doubled on every attempt with jitter; a
	// Retry-After header is honoured instead (default: 300ms)
	RetryBackoff time.Duration
	// optional: how long Close waits for queued and in-flight records (default: 15s)
	ShutdownTimeout time.Duration
	// optional: send the JSON uncompressed instead of gzip-compressed
	DisableCompression bool
	// optional: receives every delivery failure and drop summary. It is called from
	// background goroutines, possibly several at once, must return promptly and must not
	// log through this handler (default: one line on stderr)
	OnError func(err error)
	// optional: the HTTP client to upload with; Timeout still applies to every request
	HTTPClient *http.Client
}

func (Option) NewBetterstackHandler

func (o Option) NewBetterstackHandler() *BetterstackHandler

NewBetterstackHandler returns a handler that sends records to Better Stack. The handler is also a slog.Handler; keep the returned value to call Close before the program exits. Create one handler per process rather than one per request: each handler owns a goroutine and a connection pool from its first record until Close.

type Stats added in v1.5.0

type Stats struct {
	Enqueued uint64 // records handed to Handle
	Sent     uint64 // records acknowledged by Better Stack
	Retries  uint64 // upload attempts after the first

	DroppedQueueFull uint64 // the application logged faster than records could be delivered
	DroppedRejected  uint64 // Better Stack refused them, the retries ran out, or they could not be encoded
	DroppedOversize  uint64 // a single record larger than Better Stack accepts
	DroppedClosed    uint64 // logged after Close, or not delivered before the shutdown timeout
}

Stats counts what happened to the records handed to a handler. Once Close has returned, Enqueued equals Sent plus all the Dropped counters.

Directories

Path Synopsis
A small program that sends a few log records to Better Stack.
A small program that sends a few log records to Better Stack.

Jump to

Keyboard shortcuts

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