Structured Logging
Write logs with a fluent API that makes adding fields, metadata, and errors simple.
A consistent logging experience for Go, on top of any logging library.

package main
import (
"errors"
"go.loglayer.dev/v2"
"go.loglayer.dev/transports/structured/v2"
)
func main() {
log := loglayer.New(loglayer.Config{
Transport: structured.New(structured.Config{}),
FieldsKey: "context",
MetadataFieldName: "metadata",
})
// WithFields returns a NEW logger; assign it.
log = log.WithFields(loglayer.Fields{"service": "api"})
log.WithMetadata(loglayer.Metadata{"userId": "1234"}).
WithError(errors.New("something went wrong")).
Error("user action failed")
}{
"level": "error",
"time": "2026-04-25T12:00:00Z",
"msg": "user action failed",
"context": { "service": "api" },
"metadata": { "userId": "1234" },
"err": { "message": "something went wrong" }
}Self-contained transports that format the entry and write it to an io.Writer. Pick one of these when you want LogLayer to do the rendering itself.
| Name | Version | Go Reference | Description |
|---|---|---|---|
| Blank | Delegates dispatch to a user-supplied function. For prototyping or one-off integrations. | ||
| CLI | Tuned for CLI apps: short level prefixes, stdout/stderr routing, TTY-detected color, no timestamps. | ||
| Console | Plain fmt.Println-style output to stdout/stderr; minimal formatting. | ||
| Pretty | Colorized, theme-aware terminal output. Recommended for local dev. | ||
| Structured | One JSON object per log entry. Recommended for production. | ||
| Testing | Captures entries in memory for tests. |
Managed log services. Async + batched by default; site-aware where applicable.
| Name | Version | Go Reference | Description |
|---|---|---|---|
| Axiom | Ships logs to Axiom via caller-supplied *axiom.Client. NDJSON ingestion with configurable message field. | ||
| Better Stack | Ships logs to Better Stack via HTTP intake. Source token auth, configurable timestamp field. | ||
| Datadog | Datadog Logs HTTP intake. Site-aware URL, DD-API-KEY header, status mapping. | ||
| Google Cloud Logging | Forwards entries to a caller-supplied *logging.Logger from cloud.google.com/go/logging. Severity mapping, root-level Entry skeleton, async + sync dispatch. | ||
| New Relic | New Relic Log Ingest API. Site-aware URL, api-key header, LogEvent encoding. | ||
| Sentry | Forwards entries to a sentry.Logger. Routes fatal/panic through LFatal so loglayer's core controls termination. |
Generic shippers and on-disk sinks.
| Name | Version | Go Reference | Description |
|---|---|---|---|
| File (Lumberjack) | One JSON object per line written to a rotating file. Backed by lumberjack.v2. | ||
| HTTP | Generic batched HTTP POST to any endpoint. Pluggable Encoder. | ||
| OpenTelemetry Logs | Emits to an OTel log.Logger. Forwards WithContext so SDK processors can correlate with the active span. |
Transports that hand the entry off to an existing third-party logger you already configure. Pick one of these when you have an established logging stack and want LogLayer's API on top.
| Name | Version | Go Reference | Description |
|---|---|---|---|
| charmbracelet/log | Pretty terminal-friendly logger from Charm | ||
| log/slog | Wraps a stdlib *slog.Logger. Forwards WithContext to handlers. | ||
| logrus | The classic structured logger | ||
| phuslu/log | High-performance zero-alloc JSON logger. Always exits on fatal. | ||
| Zap | Wraps a *zap.Logger | ||
| Zerolog | Wraps a *zerolog.Logger |
Hook into the LogLayer pipeline to transform metadata, fields, data, messages, log level, or per-transport dispatch.
| Name | Version | Go Reference | Description |
|---|---|---|---|
| Redact | Replace values for a configured set of keys (and optional regex patterns) before metadata or fields reach a transport. Walks structs, maps, and slices via reflection; preserves the runtime type. | ||
| Sampling | Drop a fraction of emissions to keep volume and cost under control. FixedRate (per-emission Bernoulli draw), FixedRatePerLevel (per-level rate), and Burst (rate cap per rolling window). Composes with itself for "1% kept, capped at 100/sec" patterns. | ||
| Format Strings | Opt the logger into fmt.Sprintf-style format strings: log.Info("user %d", id) resolves to "user 1234" before downstream hooks see it. | ||
| Datadog APM Trace Injector | Inject the active Datadog APM trace and span IDs (dd.trace_id, dd.span_id) into every log entry that carries a context, enabling Datadog's log/trace correlation. Tracer-agnostic; bring your own dd-trace-go (v1 or v2). | ||
| OpenTelemetry Trace Injector | Inject the active OTel trace_id and span_id (and optional trace_flags) into every log entry that carries a context. Use with non-OTel transports for log/trace correlation; the OTel pipeline does this itself when shipping via transports/otellog. |
LogLayer for Go is made with ❤️ by Theo Gravity / Disaresta. Logo by Akshaya Madhavan.