diff --git a/doc.go b/doc.go index 7b70508..7be4a9c 100644 --- a/doc.go +++ b/doc.go @@ -2,7 +2,7 @@ // fluent builder API. The core defines the LogLayer type, the Transport // and Plugin interfaces, and the dispatch pipeline. Concrete transports // (zap, zerolog, slog, charmlog, OTel, etc.) ship as separately-versioned -// sub-modules under go.loglayer.dev/transports/. +// sub-modules under go.loglayer.dev/transports//v2. // // Full docs: https://go.loglayer.dev // diff --git a/docs/src/configuration.md b/docs/src/configuration.md index cafe095..5318a30 100644 --- a/docs/src/configuration.md +++ b/docs/src/configuration.md @@ -16,7 +16,7 @@ type Config struct { Transport Transport // single transport (mutually exclusive with Transports) Transports []Transport // multiple transports (mutually exclusive with Transport) Plugins []Plugin // plugins to register at construction time - Prefix string // prepended to first string message + Prefix string // surfaced to transports as TransportParams.Prefix Disabled bool // suppress all output (default: false) ErrorSerializer ErrorSerializer // customize error rendering ErrorFieldName string // key for serialized error (default: "err") diff --git a/docs/src/introduction.md b/docs/src/introduction.md index 3036ab3..9557e92 100644 --- a/docs/src/introduction.md +++ b/docs/src/introduction.md @@ -176,6 +176,8 @@ Send logs directly to any HTTP endpoint without a third-party logging library, w Built-in mocks make testing painless: ```go +import lltest "go.loglayer.dev/transports/testing/v2" + // Silent mock for tests that don't care about output log := loglayer.NewMock() diff --git a/docs/src/migrating-to-v2.md b/docs/src/migrating-to-v2.md index 0eb960a..ac5d3e5 100644 --- a/docs/src/migrating-to-v2.md +++ b/docs/src/migrating-to-v2.md @@ -5,7 +5,7 @@ description: "Upgrade guide for loglayer-go v2: import paths bump to /v2, the pr # Migrating to v2 -`loglayer-go` v2 ships one breaking change: **the loglayer core no longer mutates `Messages[0]` to fold the `WithPrefix` value into the message text.** The prefix now flows through `TransportParams.Prefix` and each transport decides how to render it. +`loglayer-go` v2 ships two breaking changes: **every import path bumps to `/v2`**, and **the loglayer core no longer mutates `Messages[0]` to fold the `WithPrefix` value into the message text.** The prefix now flows through `TransportParams.Prefix` and each transport decides how to render it. This page is the upgrade checklist. @@ -19,16 +19,18 @@ You can migrate one module at a time: a project that uses several `loglayer-go` `v1.x` folded the prefix into `Messages[0]` from the core so transports that didn't know about prefixes got the right behavior for free. The downside: transports that DID want to render the prefix differently (separate color, separate JSON field, structured forwarding to underlying loggers) couldn't, because by the time they saw the message it was already mangled. Pulling the prefix into a first-class field unblocks every smarter rendering, at the cost of a one-time import-path migration. +The new contract also keeps the core out of the business of mutating caller-owned input: in v1, the prefix-prepend silently rewrote the user's `Messages` slice before any transport saw it; in v2, the core passes the slice through untouched and exposes the prefix on its own field. + ## Step 1: bump every import path to `/v2` The main module and every sub-module are now versioned at `v2`. Update your `go.mod` requires and your source-file imports. ```sh -go get go.loglayer.dev/v2 \ - go.loglayer.dev/transports/cli/v2 \ - go.loglayer.dev/transports/zerolog/v2 \ - go.loglayer.dev/plugins/redact/v2 - # ... whichever sub-modules you import +# Run for each sub-module you import +go get go.loglayer.dev/v2 +go get go.loglayer.dev/transports/cli/v2 +go get go.loglayer.dev/transports/zerolog/v2 +go get go.loglayer.dev/plugins/redact/v2 ``` In source files: @@ -53,7 +55,8 @@ For users of the built-in transports who don't write custom transports, nothing The exceptions to "nothing else changes": - The **cli transport** opts into smart prefix rendering: the user prefix renders in dim grey while the level prefix and message body keep the level color. If you were using cli with `WithPrefix`, the rendered output is now visually layered. See the [cli transport doc](/transports/cli) for an example. -- The **blank transport** intentionally passes raw v2 params through to your `ShipToLogger` function. The prefix is on `params.Prefix`, not in `Messages[0]`; if you were extracting the prefix from `Messages[0]`, switch to reading `params.Prefix`. +- The **blank transport** hands `params` straight to your `ShipToLogger` function. If your callback was reading the prefix out of `Messages[0]`, read `params.Prefix` instead. +- If you assert on `testing.LogLine` in tests, the unmangled prefix is also available on `LogLine.Prefix` (new field in v2). Existing assertions on `Messages[0]` keep working because the testing transport calls `JoinPrefixAndMessages` internally. ## Step 3: custom transports diff --git a/docs/src/public/llms-full.txt b/docs/src/public/llms-full.txt index 78c7c89..ef68258 100644 --- a/docs/src/public/llms-full.txt +++ b/docs/src/public/llms-full.txt @@ -17,6 +17,7 @@ LogLayer is multi-module: most transports, plugins, and integrations ship as the go get go.loglayer.dev/transports/structured/v2 go get go.loglayer.dev/transports/console/v2 go get go.loglayer.dev/transports/pretty/v2 +go get go.loglayer.dev/transports/cli/v2 go get go.loglayer.dev/transports/testing/v2 go get go.loglayer.dev/transports/blank/v2 @@ -97,8 +98,8 @@ Seven levels, integer-typed, in priority order: - `loglayer.LogLevelInfo` (20) - `loglayer.LogLevelWarn` (30) - `loglayer.LogLevelError` (40) -- `loglayer.LogLevelFatal` (50) — dispatches then `os.Exit(1)` unless `DisableFatalExit` is set -- `loglayer.LogLevelPanic` (60) — dispatches then panics with the joined message string (recoverable; matches zerolog/zap/logrus) +- `loglayer.LogLevelFatal` (50): dispatches then `os.Exit(1)` unless `DisableFatalExit` is set +- `loglayer.LogLevelPanic` (60): dispatches then panics with the joined message string (recoverable; matches zerolog/zap/logrus) ```go log.Trace("detailed debugging") @@ -189,7 +190,7 @@ Callbacks may be invoked concurrently across goroutines if the same `*LogLayer` ## Fields (persistent data across all log entries) -Fields ride on every emission from the logger they're set on. `WithFields` returns a new `*LogLayer` — always assign the result. +Fields ride on every emission from the logger they're set on. `WithFields` returns a new `*LogLayer`; always assign the result. ```go log = log.WithFields(loglayer.Fields{ @@ -366,7 +367,7 @@ prefixed.Info("login") // "[Auth] login" parent := loglayer.New(loglayer.Config{Transport: t}) parent = parent.WithFields(loglayer.F{"service": "api"}) -// Independent clone — mutations don't bleed back to parent +// Independent clone (mutations don't bleed back to parent) child := parent.Child() child = child.WithFields(loglayer.F{"handler": "users"}) child.Info("request received") // emits with service AND handler @@ -378,9 +379,9 @@ child.Info("request received") // emits with service AND handler Three independent tiers; a log must pass all that apply: -1. **LogLayer (global)** — `SetLevel`, `EnableLevel`, `DisableLevel`, `EnableLogging`, `DisableLogging`. Checked first, before any processing. -2. **Group** — `Routing.Groups[name].Level`. Only applies to grouped logs. -3. **Transport** — `transport.BaseConfig{Level: ...}` per transport, checked at dispatch time. +1. **LogLayer (global)**: `SetLevel`, `EnableLevel`, `DisableLevel`, `EnableLogging`, `DisableLogging`. Checked first, before any processing. +2. **Group**: `Routing.Groups[name].Level`. Only applies to grouped logs. +3. **Transport**: `transport.BaseConfig{Level: ...}` per transport, checked at dispatch time. ```go log.SetLevel(loglayer.LogLevelWarn) // raise threshold; only Warn+ logs @@ -391,7 +392,7 @@ log.DisableLogging() log.IsLevelEnabled(loglayer.LogLevelDebug) ``` -Lock-free internally — safe to call concurrently with emission. Mirrors `zap.AtomicLevel`. +Lock-free internally; safe to call concurrently with emission. Mirrors `zap.AtomicLevel`. ## Raw Logging @@ -485,7 +486,7 @@ A group's `Level` filters out entries below that level for that group's transpor ```go Ungrouped: loglayer.UngroupedRouting{ - Mode: loglayer.UngroupedToAll, // default — every transport gets ungrouped logs + Mode: loglayer.UngroupedToAll, // default: every transport gets ungrouped logs // Mode: loglayer.UngroupedToNone, // drop ungrouped logs entirely // Mode: loglayer.UngroupedToTransports, Transports: []string{"console"}, } @@ -550,7 +551,7 @@ log.Info("hi") // {"level":"info","msg":"hi","source":{"function":"main.foo","file":"foo.go","line":42}} ``` -`*loglayer.Source` has `json` tags matching slog convention plus `String()` and `slog.LogValuer` so non-JSON transports render readably. `loglayer.SourceFromPC(pc)` builds a Source from a captured PC. The `integrations/sloghandler` forwards `slog.Record.PC` automatically — no `Source.Enabled` needed on the loglayer side. +`*loglayer.Source` has `json` tags matching slog convention plus `String()` and `slog.LogValuer` so non-JSON transports render readably. `loglayer.SourceFromPC(pc)` builds a Source from a captured PC. The `integrations/sloghandler` forwards `slog.Record.PC` automatically; no `Source.Enabled` needed on the loglayer side. ## Stdlib log Bridge @@ -636,9 +637,23 @@ pretty.New(pretty.Config{ }) ``` -### Testing Transport (lltest) +### CLI Transport -In-memory capture for assertion tests. +Tuned for command-line application output rather than diagnostic logging. Short cargo/eslint-style level prefixes (`warning:`, `error:`, `fatal:`), stdout for info/debug and stderr for warn+, TTY-detected ANSI color, no timestamps. Renders the `WithPrefix` value in dim grey, separate from the level color. Fields/metadata dropped by default; opt in via `Config.ShowFields`. + +```go +import "go.loglayer.dev/transports/cli/v2" + +cli.New(cli.Config{ + // Writer: os.Stdout, // override (defaults: stdout for info/debug, stderr for warn+) + // Color: cli.ColorAuto, // ColorNever / ColorAlways + // ShowFields: false, // append fields/metadata after the message +}) +``` + +### Testing Transport + +In-memory capture for assertion tests. Public package is `transports/testing`; `lltest` is the conventional import alias. ```go import lltest "go.loglayer.dev/transports/testing/v2" @@ -649,7 +664,7 @@ log := loglayer.New(loglayer.Config{ }) log.Info("hello", loglayer.F{"k": "v"}) -lines := lib.Lines() // []lltest.LogLine — assert on Level, Messages, Data, Metadata, Ctx +lines := lib.Lines() // []lltest.LogLine; assert on Level, Messages, Data, Metadata, Ctx last := lib.GetLastLine() popped := lib.PopLine() ``` @@ -721,7 +736,7 @@ defer tr.Close() // flush pending entries ### File (Lumberjack) -One JSON object per log entry written to a rotating file. Render path matches `transports/structured`. Rotation delegated to `lumberjack.v2`. The package name `lumberjack` shadows the upstream `gopkg.in/natefinch/lumberjack.v2`; alias one of them when both are imported. The shorter `transports/file` import path is reserved for a future rolled-our-own implementation. +One JSON object per log entry written to a rotating file. Render path matches `transports/structured`. Rotation delegated to `lumberjack.v2`. The package name `lumberjack` shadows the upstream `gopkg.in/natefinch/lumberjack.v2`; alias one of them when both are imported. The shorter `transports/file` import path is reserved for a future roll-our-own implementation. ```go import "go.loglayer.dev/transports/lumberjack/v2" @@ -741,7 +756,7 @@ _ = tr.Rotate() `lumberjack.Build` returns `ErrFilenameRequired` instead of panicking when `Filename` is empty. -To pretty-print to a file, plug `*lumberjack.Logger` directly into the pretty/console transport's `Writer` field — no need for the file transport. +To pretty-print to a file, plug `*lumberjack.Logger` directly into the pretty/console transport's `Writer` field; no need for the file transport. ## Wrapper Transports @@ -898,7 +913,7 @@ func (t *myTransport) SendToLogger(p loglayer.TransportParams) { `TransportParams` carries: `LogLevel`, `Messages` (the raw message slice; the prefix is exposed separately on `Prefix` below), `Data` (assembled fields + error map; nil when both absent, use `len(Data) > 0`), `Metadata` (raw `WithMetadata` value; transport decides serialization), `Err`, `Fields` (raw persistent bag), `Ctx` (per-call `WithContext`, nil when unset), `Groups` (merged persistent + per-call `WithGroup` tags; nil when no groups apply, routing has already consumed it before this point, so the slice is exposed for wire-payload tagging only), `Schema` (resolved assembly shape: FieldsKey, MetadataFieldName, ErrorFieldName, SourceFieldName), `Prefix` (the value attached via `WithPrefix` or `Config.Prefix`, exposed verbatim so transports can render it independently from the message text; empty when no prefix was set). Transports that want a "prefix folded into Messages[0]" rendering call `transport.JoinPrefixAndMessages(p.Prefix, p.Messages)` at the top of `SendToLogger`. -The `transport/transporttest` package exports `RunContract(t, ContractCase{...})` — a 14-test contract suite that verifies the wrapper-transport conventions (level filtering, struct vs map metadata, error serialization, fatal handling, etc.). +The `transport/transporttest` package exports `RunContract(t, ContractCase{...})`: a 14-test contract suite that verifies the wrapper-transport conventions (level filtering, struct vs map metadata, error serialization, fatal handling, etc.). ## Plugins @@ -913,7 +928,7 @@ Six lifecycle hooks. A plugin implements any subset of these interfaces: | `TransformLogLevel` | Decide whether to override the entry's level | Log-level escalation | | `ShouldSend` | Per-transport gate; returning false skips that transport for this emission| Sampling, group filtering | -Hook panics are recovered centrally — each hook returns its no-op value on panic, and `ShouldSend` fails open. Set `Plugin.OnError` to observe recovered panics. +Hook panics are recovered centrally: each hook returns its no-op value on panic, and `ShouldSend` fails open. Set `Plugin.OnError` to observe recovered panics. The four dispatch-time hook param structs (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`) all carry a `Ctx context.Context` (per-call `WithContext` value, nil if unset) and a `Groups []string` (merged persistent + per-call `WithGroup` tags, nil when none apply). Routing decisions consume `Groups` before any hook fires; the slice is exposed so plugins can drive group-aware transformations. `OnFieldsCalled` and `OnMetadataCalled` fire at builder time (before the chain is finalized) so they don't see either field. @@ -962,7 +977,7 @@ log.AddPlugin(sampling.FixedRatePerLevel(map[loglayer.LogLevel]float64{ // Burst limiting: keep the first N per rolling window, drop the rest log.AddPlugin(sampling.Burst(100, time.Second)) -// Strategies compose — every gate must pass for emission +// Strategies compose: every gate must pass for emission ``` ### Format Strings Plugin (fmtlog) @@ -979,7 +994,7 @@ log.Info("user %d logged in from %s", 42, "1.2.3.4") ### Datadog APM Trace Injector -Tracer-agnostic — supply a small `Extract` function for your tracer (dd-trace-go v1 or v2). +Tracer-agnostic: supply a small `Extract` function for your tracer (dd-trace-go v1 or v2). ```go import ( @@ -1016,13 +1031,13 @@ import "go.loglayer.dev/plugins/oteltrace/v2" log.AddPlugin(oteltrace.New(oteltrace.Config{ TraceIDKey: "trace_id", // default SpanIDKey: "span_id", // default - TraceFlagsKey: "", // optional — omit to skip + TraceFlagsKey: "", // optional; omit to skip TraceStateKey: "", // optional W3C trace_state BaggageKeyPrefix: "", // optional W3C baggage; e.g. "baggage." })) ``` -Baggage rides independently of the span — contexts with baggage but no span still surface baggage attributes. `transports/otellog` does trace correlation natively, so this plugin is mainly for non-OTel transports. +Baggage rides independently of the span: contexts with baggage but no span still surface baggage attributes. `transports/otellog` does trace correlation natively, so this plugin is mainly for non-OTel transports. ## Integrations @@ -1058,18 +1073,18 @@ slog.SetDefault(slog.New(sloghandler.New(log))) slog.Info("from somewhere deep", "userId", 42) ``` -Levels above `slog.LevelError` pin to `LogLevelError` (slog can't trigger Fatal exit through this handler). `slog.Record.PC` becomes a `*loglayer.Source` automatically — no `Source.Enabled` needed. +Levels above `slog.LevelError` pin to `LogLevelError` (slog can't trigger Fatal exit through this handler). `slog.Record.PC` becomes a `*loglayer.Source` automatically; no `Source.Enabled` needed. ## Testing / Mocking -### NewMock — silent logger +### NewMock: silent logger ```go log := loglayer.NewMock() // same API, emits nothing, Fatal does not exit log.Info("invisible") ``` -### Capture entries with lltest +### Capture entries with the testing transport ```go import lltest "go.loglayer.dev/transports/testing/v2" @@ -1108,7 +1123,7 @@ require.Equal(t, "[REDACTED]", md["pw"]) ## Multi-Module Versioning -`go.loglayer.dev/v2` is the main module; every transport, plugin, and integration ships as its own Go module. Tags use the prefix form (`transports//v`, `plugins//v`). A breaking change in any one sub-module bumps only that sub-module's major version — `go.loglayer.dev/v2`'s import path stays stable. +`go.loglayer.dev/v2` is the main module; every transport, plugin, and integration ships as its own Go module. Tags use the prefix form (`transports//v`, `plugins//v`). A breaking change in any one sub-module bumps only that sub-module's major version, so `go.loglayer.dev/v2`'s import path stays stable. Full module list: [`monorel.toml`](https://github.com/loglayer/loglayer-go/blob/main/monorel.toml). diff --git a/docs/src/public/llms.txt b/docs/src/public/llms.txt index 73bf21d..b5bd246 100644 --- a/docs/src/public/llms.txt +++ b/docs/src/public/llms.txt @@ -8,7 +8,7 @@ go get go.loglayer.dev/v2 ``` -Most transports and plugins ship as their own modules — install only what you import: +Most transports and plugins ship as their own modules. Install only what you import: ```sh go get go.loglayer.dev/transports/structured/v2 @@ -91,7 +91,7 @@ A panicking callback substitutes `loglayer.LazyEvalError` and the rest of the en ## Fields (persistent data across all log entries) -Fields ride on every emission from the logger they're set on. Always assign the result — `WithFields` returns a new `*LogLayer`. +Fields ride on every emission from the logger they're set on. Always assign the result; `WithFields` returns a new `*LogLayer`. ```go log = log.WithFields(loglayer.Fields{ @@ -164,7 +164,7 @@ log := loglayer.New(loglayer.Config{ Transports: []loglayer.Transport{t1, t2}, // multi-transport (mutually exclusive with Transport) // Optional - Prefix: "[auth]", // prepended to every message + Prefix: "[auth]", // surfaced to transports as TransportParams.Prefix Disabled: false, // master on/off ErrorSerializer: loglayer.UnwrappingErrorSerializer, ErrorFieldName: "err", // default @@ -249,7 +249,7 @@ The `WithPrefix` value (or `Config.Prefix`) is surfaced to transports as `Transp parent := loglayer.New(loglayer.Config{Transport: structured.New(structured.Config{})}) parent = parent.WithFields(loglayer.F{"service": "api"}) -// Independent clone — mutations don't affect the parent +// Independent clone (mutations don't affect the parent) child := parent.Child() child = child.WithFields(loglayer.F{"handler": "users"}) child.Info("request received") // emits with both service and handler @@ -273,9 +273,9 @@ prefixed.Info("login") // "[Auth] login" Three independent tiers; a log must pass all that apply: -1. **LogLayer (global)** — `SetLevel`, `EnableLevel`, `DisableLevel`, `EnableLogging`, `DisableLogging` -2. **Group** — `Routing.Groups[name].Level` for grouped logs only -3. **Transport** — `transport.BaseConfig{Level: ...}` per transport, checked at dispatch +1. **LogLayer (global)**: `SetLevel`, `EnableLevel`, `DisableLevel`, `EnableLogging`, `DisableLogging` +2. **Group**: `Routing.Groups[name].Level` for grouped logs only +3. **Transport**: `transport.BaseConfig{Level: ...}` per transport, checked at dispatch ```go log.SetLevel(loglayer.LogLevelWarn) // only Warn+ will log @@ -304,7 +304,7 @@ log.SetTransports(t1, t2) ## Go context.Context -Distinct from "context" in TS LogLayer — Go's `context.Context` carries trace IDs, deadlines, request-scoped values. Use `WithContext` to attach it; transports and plugins read it via `TransportParams.Ctx`. +Distinct from "context" in TS LogLayer: Go's `context.Context` carries trace IDs, deadlines, request-scoped values. Use `WithContext` to attach it; transports and plugins read it via `TransportParams.Ctx`. ```go // Per-call attachment @@ -334,7 +334,7 @@ The slog handler (`integrations/sloghandler`) forwards `slog.Record.PC` automati ## Testing / Mocking ```go -// Silent mock — same API, emits nothing, Fatal does not exit +// Silent mock: same API, emits nothing, Fatal does not exit log := loglayer.NewMock() // Capture entries for assertion @@ -346,43 +346,44 @@ log := loglayer.New(loglayer.Config{ }) log.Info("hello", loglayer.F{"k": "v"}) -lines := lib.Lines() // []lltest.LogLine — assert on Level, Messages, Data, Metadata, Ctx +lines := lib.Lines() // []lltest.LogLine; assert on Level, Messages, Data, Metadata, Ctx ``` ## Available Transports **Renderers** (format and write to an `io.Writer`): -- `transports/console` — plain `fmt.Println`-style -- `transports/structured` — one JSON object per entry (production) -- `transports/pretty` — colorized terminal output (local dev) -- `transports/testing` — in-memory capture for tests -- `transports/blank` — user-supplied dispatch function +- `transports/console`: plain `fmt.Println`-style +- `transports/structured`: one JSON object per entry (production) +- `transports/pretty`: colorized terminal output (local dev) +- `transports/cli`: tuned for command-line apps (short level prefixes, stdout/stderr routing, TTY-detected color, no timestamps) +- `transports/testing`: in-memory capture for tests +- `transports/blank`: user-supplied dispatch function **Cloud** (managed log services): -- `transports/datadog` — Datadog Logs HTTP intake -- `transports/gcplogging` — wraps a caller-supplied `*logging.Logger` from `cloud.google.com/go/logging` -- `transports/sentry` — wraps a caller-supplied `sentry.Logger` +- `transports/datadog`: Datadog Logs HTTP intake +- `transports/gcplogging`: wraps a caller-supplied `*logging.Logger` from `cloud.google.com/go/logging` +- `transports/sentry`: wraps a caller-supplied `sentry.Logger` **Other transports**: -- `transports/http` — generic batched HTTP POST -- `transports/lumberjack` — one JSON object per line, rotating file via `lumberjack.v2` -- `transports/otellog` — emits to an OTel `log.Logger`; forwards `WithContext` for trace correlation +- `transports/http`: generic batched HTTP POST +- `transports/lumberjack`: one JSON object per line, rotating file via `lumberjack.v2` +- `transports/otellog`: emits to an OTel `log.Logger`; forwards `WithContext` for trace correlation **Wrappers around third-party loggers**: - `transports/zerolog`, `transports/zap`, `transports/slog`, `transports/phuslu`, `transports/logrus`, `transports/charmlog` ## Available Plugins -- `plugins/redact` — replace values for configured keys/patterns -- `plugins/sampling` — drop a fraction of emissions (`FixedRate`, `FixedRatePerLevel`, `Burst`) -- `plugins/fmtlog` — `fmt.Sprintf` semantics for multi-arg messages -- `plugins/datadogtrace` — inject `dd.trace_id` / `dd.span_id` (tracer-agnostic; bring your own dd-trace-go) -- `plugins/oteltrace` — inject OTel `trace_id` / `span_id` / `trace_flags` / W3C `trace_state` and baggage +- `plugins/redact`: replace values for configured keys/patterns +- `plugins/sampling`: drop a fraction of emissions (`FixedRate`, `FixedRatePerLevel`, `Burst`) +- `plugins/fmtlog`: `fmt.Sprintf` semantics for multi-arg messages +- `plugins/datadogtrace`: inject `dd.trace_id` / `dd.span_id` (tracer-agnostic; bring your own dd-trace-go) +- `plugins/oteltrace`: inject OTel `trace_id` / `span_id` / `trace_flags` / W3C `trace_state` and baggage ## Available Integrations -- `integrations/loghttp` — HTTP middleware. Per-request logger with `requestId`/`method`/`path`, auto request-completed log, request-context binding. Works with chi, gorilla, gin, echo, stdlib. -- `integrations/sloghandler` — `log/slog.Handler` backed by a loglayer logger. `slog.SetDefault(slog.New(sloghandler.New(log)))` makes every `slog.Info(...)` flow through loglayer's plugin pipeline and group routing. +- `integrations/loghttp`: HTTP middleware. Per-request logger with `requestId`/`method`/`path`, auto request-completed log, request-context binding. Works with chi, gorilla, gin, echo, stdlib. +- `integrations/sloghandler`: `log/slog.Handler` backed by a loglayer logger. `slog.SetDefault(slog.New(sloghandler.New(log)))` makes every `slog.Info(...)` flow through loglayer's plugin pipeline and group routing. ## Documentation diff --git a/docs/src/transports/creating-transports.md b/docs/src/transports/creating-transports.md index 52a00f2..a0495c9 100644 --- a/docs/src/transports/creating-transports.md +++ b/docs/src/transports/creating-transports.md @@ -68,7 +68,7 @@ That's the whole shape. From here it's a question of how you want to render the ```go type TransportParams struct { LogLevel LogLevel - Messages []any // already prefix-applied (see Prefix below) + Messages []any // raw message slice; the prefix is exposed separately on Prefix below Data Data // assembled fields + error map; nil when both are absent. Use len(Data) > 0 to check. Metadata any // raw value passed to WithMetadata, your transport decides serialization Err error diff --git a/examples/pretty-modes/main.go b/examples/pretty-modes/main.go index fae87a5..4d26d92 100644 --- a/examples/pretty-modes/main.go +++ b/examples/pretty-modes/main.go @@ -7,7 +7,7 @@ // // Run: // -// go run go.loglayer.dev/examples/pretty-modes +// go run go.loglayer.dev/v2/examples/pretty-modes // // Or from a clone: // diff --git a/transports/cli/cli.go b/transports/cli/cli.go index f61d739..1df86e7 100644 --- a/transports/cli/cli.go +++ b/transports/cli/cli.go @@ -2,7 +2,7 @@ // output rather than diagnostic logging. // // What makes it different from the other terminal-shaped transports -// ([go.loglayer.dev/transports/console], [go.loglayer.dev/transports/pretty]): +// ([go.loglayer.dev/transports/console/v2], [go.loglayer.dev/transports/pretty/v2]): // // - No timestamp, no log-id, no level label embedded in info/debug // output. The message string is printed as-is. @@ -22,18 +22,18 @@ // What this transport is NOT: // // - A diagnostic logger. If you want timestamps and structured -// fields, use [go.loglayer.dev/transports/console] or -// [go.loglayer.dev/transports/pretty]. +// fields, use [go.loglayer.dev/transports/console/v2] or +// [go.loglayer.dev/transports/pretty/v2]. // - A JSON formatter. Pair this transport with a swap to -// [go.loglayer.dev/transports/structured] when the CLI's +// [go.loglayer.dev/transports/structured/v2] when the CLI's // `--json` flag is set. // // Recommended plugin pairings: // -// - [go.loglayer.dev/plugins/fmtlog] for fmt.Sprintf-style format +// - [go.loglayer.dev/plugins/fmtlog/v2] for fmt.Sprintf-style format // strings (`log.Info("Applied %d release(s) at %s:", n, sha)`). // CLI output almost always wants format-string semantics. -// - [go.loglayer.dev/plugins/redact] when log values may include +// - [go.loglayer.dev/plugins/redact/v2] when log values may include // tokens or other secrets that shouldn't reach stdout / stderr. // // See https://go.loglayer.dev for usage guides and the full API diff --git a/transports/otellog/otellog.go b/transports/otellog/otellog.go index 74c4f3c..3a2018c 100644 --- a/transports/otellog/otellog.go +++ b/transports/otellog/otellog.go @@ -9,8 +9,8 @@ // entry with the active span automatically). // // The package name is otellog (not otel) to avoid a name collision with -// go.opentelemetry.io/otel. Import path remains -// go.loglayer.dev/transports/otellog. +// go.opentelemetry.io/otel. Import path is +// go.loglayer.dev/transports/otellog/v2. // // Wiring with the global LoggerProvider (most common): //