From c7e2652e409e4712df2dccd330b44054b6ff202b Mon Sep 17 00:00:00 2001 From: Theo Gravity Date: Sat, 2 May 2026 14:54:42 -0700 Subject: [PATCH 1/8] feat(loglayer): remove applyPrefix, add transport.JoinPrefixAndMessages Phase 1 of the v2 cascade. Core changes: - Remove applyPrefix from loglayer.go and the three call sites in builder.go, dispatch.go, log.go. The core no longer mutates Messages[0]; the prefix flows through TransportParams.Prefix and each transport renders it however it likes. - Add transport.JoinPrefixAndMessages helper for transports that want the v1 'prefix folded into Messages[0]' rendering. Early- return on empty prefix or non-string Messages[0]; only allocates when there's an actual prefix to merge. Transport updates (preserving v1 user-visible behavior): - console, pretty, structured, testing, zerolog, zap, slog, logrus, phuslu, charmlog, http, sentry, otellog, gcplogging: each calls the helper at the top of SendToLogger before its existing rendering. - testing.LogLine gained a Prefix field for tests that want the unmangled signal. - blank intentionally left as-is (it's a raw-passthrough transport for advanced users). - lumberjack inherits behavior from structured via delegation. Test fixture updates: - example_test.go's exampleTransport calls the helper. - TestPrefix and TestPrefixSurfacedOnTransportParams updated for the new contract (prefix on params.Prefix, not in Messages[0]). Phase 2 (smart rendering opt-ins for cli/structured/pretty), Phase 3 (module path bumps to /v2), and Phase 4 (changesets + docs) follow. --- builder.go | 6 ++++- dispatch.go | 16 +++++++----- example_test.go | 11 +++++--- log.go | 1 - loglayer.go | 9 ------- loglayer_test.go | 21 ++++++++++------ transport/helpers.go | 39 +++++++++++++++++++++++++++++ transports/charmlog/charmlog.go | 3 +++ transports/console/console.go | 3 +++ transports/gcplogging/gcplogging.go | 3 +++ transports/http/http.go | 6 ++++- transports/logrus/logrus.go | 3 +++ transports/otellog/otellog.go | 3 +++ transports/phuslu/phuslu.go | 3 +++ transports/pretty/pretty.go | 3 +++ transports/sentry/sentry.go | 3 +++ transports/slog/slog.go | 3 +++ transports/structured/structured.go | 3 +++ transports/testing/testing.go | 14 +++++++++-- transports/zap/zap.go | 3 +++ transports/zerolog/zerolog.go | 3 +++ 21 files changed, 129 insertions(+), 30 deletions(-) diff --git a/builder.go b/builder.go index 8777344..e051bf0 100644 --- a/builder.go +++ b/builder.go @@ -167,7 +167,11 @@ func (b *LogBuilder) Panic(messages ...any) { } func (b *LogBuilder) dispatch(level LogLevel, messages []any, source *Source) { - applyPrefix(b.layer.prefix, messages) + // Prefix is no longer prepended into messages here — it flows + // through TransportParams.Prefix and each transport renders it + // however it wants (most call transport.JoinPrefixAndMessages + // to preserve the v1 prepended-into-messages shape). + // // Hot path: builder has no per-call groups, so pass the layer's // assigned groups straight through. mergeGroups is out-of-line and // would be a measurable hit per emission for the dominant case. diff --git a/dispatch.go b/dispatch.go index c7cb558..2f7d49e 100644 --- a/dispatch.go +++ b/dispatch.go @@ -10,14 +10,18 @@ import ( // tests to verify the pre-exit flush without terminating the test runner. var osExit = os.Exit -// formatLog applies the prefix to messages then hands the entry to processLog -// using the logger's persistent fields. Per-call goCtx overrides the -// logger's bound ctx (when one is provided), otherwise the bound ctx is -// passed through. source carries pre-captured call-site info from the -// emission entry point (nil if Config.Source.Enabled is off and no adapter +// formatLog hands the entry to processLog using the logger's +// persistent fields. The prefix is propagated through +// TransportParams.Prefix; transports decide how to render it (most +// call transport.JoinPrefixAndMessages to preserve the v1 prepended- +// into-messages shape). +// +// Per-call goCtx overrides the logger's bound ctx (when one is +// provided), otherwise the bound ctx is passed through. source +// carries pre-captured call-site info from the emission entry +// point (nil if Config.Source.Enabled is off and no adapter // supplied one). func (l *LogLayer) formatLog(level LogLevel, messages []any, goCtx context.Context, metadata any, err error, source *Source, plugins *pluginSet) { - applyPrefix(l.prefix, messages) if goCtx == nil { goCtx = l.boundCtx } diff --git a/example_test.go b/example_test.go index 2f0b9ce..859198d 100644 --- a/example_test.go +++ b/example_test.go @@ -23,6 +23,7 @@ import ( "strings" "go.loglayer.dev" + "go.loglayer.dev/transport" ) // fixedTime returns a deterministic timestamp for example output. @@ -42,10 +43,14 @@ func (exampleTransport) SendToLogger(p loglayer.TransportParams) { parts = append(parts, fmt.Sprintf(`"level":%q`, p.LogLevel.String())) parts = append(parts, fmt.Sprintf(`"time":%q`, fixedTime())) + // Preserve the v1 "prefix folded into the message" rendering + // for these examples; in v2 the prefix arrives on p.Prefix and + // each transport decides how to render it. + msgs := transport.JoinPrefixAndMessages(p.Prefix, p.Messages) msg := "" - if len(p.Messages) > 0 { - bits := make([]string, len(p.Messages)) - for i, m := range p.Messages { + if len(msgs) > 0 { + bits := make([]string, len(msgs)) + for i, m := range msgs { bits[i] = fmt.Sprint(m) } msg = strings.Join(bits, " ") diff --git a/log.go b/log.go index 495872d..6b03222 100644 --- a/log.go +++ b/log.go @@ -191,7 +191,6 @@ func (l *LogLayer) Raw(entry RawLogEntry) { if !l.levels.isEnabled(entry.LogLevel) { return } - applyPrefix(l.prefix, entry.Messages) fields := entry.Fields fromLayer := false if fields == nil { diff --git a/loglayer.go b/loglayer.go index ea1689f..8497846 100644 --- a/loglayer.go +++ b/loglayer.go @@ -275,15 +275,6 @@ func (l *LogLayer) WithPrefix(prefix string) *LogLayer { return child } -func applyPrefix(prefix string, messages []any) { - if prefix == "" || len(messages) == 0 { - return - } - if s, ok := messages[0].(string); ok { - messages[0] = prefix + " " + s - } -} - // copyFields returns a shallow copy of src, or nil when src is empty. // Returning nil saves an allocation per Child() call on loggers that // haven't accumulated any fields yet (the dominant case for fresh diff --git a/loglayer_test.go b/loglayer_test.go index ca71370..821d402 100644 --- a/loglayer_test.go +++ b/loglayer_test.go @@ -108,7 +108,14 @@ func TestPrefix(t *testing.T) { log, lib := setup(t) prefixed := log.WithPrefix("[app]") prefixed.Info("started") - assertLine(t, lib, loglayer.LogLevelInfo, "[app] started") + // v2: the prefix is no longer mutated into Messages[0]; it + // flows through TransportParams.Prefix and the transport + // renders it however it likes. Assert the message arrives + // untouched plus the prefix is exposed on params.Prefix. + line := assertLine(t, lib, loglayer.LogLevelInfo, "started") + if line.Prefix != "[app]" { + t.Errorf("Prefix = %q, want %q", line.Prefix, "[app]") + } } func TestPrefixDoesNotAffectParent(t *testing.T) { @@ -120,10 +127,10 @@ func TestPrefixDoesNotAffectParent(t *testing.T) { } func TestPrefixSurfacedOnTransportParams(t *testing.T) { - // Prefix is exposed verbatim on TransportParams.Prefix so - // transports can render it independently. The legacy - // "messages[0] has prefix prepended" behavior is retained for - // backwards compatibility; both signals must be present. + // v2: Prefix is exposed verbatim on TransportParams.Prefix and + // is NO LONGER prepended into Messages[0]. Transports that + // want the v1 "prefix prepended into the message" behavior + // call transport.JoinPrefixAndMessages explicitly. log, lib := setup(t) prefixed := log.WithPrefix("[auth]") prefixed.Info("starting") @@ -132,8 +139,8 @@ func TestPrefixSurfacedOnTransportParams(t *testing.T) { if line.Prefix != "[auth]" { t.Errorf("Prefix = %q, want %q", line.Prefix, "[auth]") } - if got, _ := line.Messages[0].(string); got != "[auth] starting" { - t.Errorf("Messages[0] = %q, want %q (legacy compat)", got, "[auth] starting") + if got, _ := line.Messages[0].(string); got != "starting" { + t.Errorf("Messages[0] = %q, want %q (prefix no longer auto-prepended)", got, "starting") } } diff --git a/transport/helpers.go b/transport/helpers.go index 4fd96ea..fc28277 100644 --- a/transport/helpers.go +++ b/transport/helpers.go @@ -29,6 +29,45 @@ func WriterOrStdout(w io.Writer) io.Writer { return os.Stdout } +// JoinPrefixAndMessages preserves the legacy "prefix folded into the +// first message" rendering for transports that don't have a smart +// place to surface params.Prefix on its own. Returns messages +// unchanged when prefix is empty or messages[0] is not a string; +// otherwise returns a fresh slice whose first element is +// `prefix + " " + messages[0]`. +// +// Use case: most renderer/wrapper transports just want the v1 +// behavior where every log line shows `[prefix] message` in one +// blob. Pre-v2 the loglayer core mutated messages[0] before +// dispatch; from v2 onward it's the transport's job. Call this +// helper at the top of SendToLogger to keep the same user-visible +// output: +// +// func (t *Transport) SendToLogger(p loglayer.TransportParams) { +// if !t.ShouldProcess(p.LogLevel) { return } +// p.Messages = transport.JoinPrefixAndMessages(p.Prefix, p.Messages) +// // ... existing rendering logic ... +// } +// +// Transports that want to render the prefix differently (cli's +// dim-color treatment, structured's separate JSON field, wrapper +// transports forwarding to the underlying logger's structured-field +// API) should NOT call this helper; instead consume p.Prefix +// directly and emit messages without the prefix prepended. +func JoinPrefixAndMessages(prefix string, messages []any) []any { + if prefix == "" || len(messages) == 0 { + return messages + } + s, ok := messages[0].(string) + if !ok { + return messages + } + out := make([]any, len(messages)) + copy(out, messages) + out[0] = prefix + " " + s + return out +} + // JoinMessages concatenates a slice of values into a single space-separated // string. Strings are passed through; other types use fmt.Sprintf("%v", ...). // diff --git a/transports/charmlog/charmlog.go b/transports/charmlog/charmlog.go index 6876fda..4d4b9af 100644 --- a/transports/charmlog/charmlog.go +++ b/transports/charmlog/charmlog.go @@ -58,6 +58,9 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) keyvals := make([]any, 0, transport.FieldEstimate(params)*2) if len(params.Data) > 0 { diff --git a/transports/console/console.go b/transports/console/console.go index 7c6c7b6..c396209 100644 --- a/transports/console/console.go +++ b/transports/console/console.go @@ -78,6 +78,9 @@ func (c *Transport) SendToLogger(params loglayer.TransportParams) { if !c.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) messages := buildMessages(params, c.cfg) fmt.Fprintln(c.writer(params.LogLevel), messages...) } diff --git a/transports/gcplogging/gcplogging.go b/transports/gcplogging/gcplogging.go index 082c9d4..8aa11fc 100644 --- a/transports/gcplogging/gcplogging.go +++ b/transports/gcplogging/gcplogging.go @@ -126,6 +126,9 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) entry := t.buildEntry(params) if t.cfg.Sync { ctx := params.Ctx diff --git a/transports/http/http.go b/transports/http/http.go index 9ef782b..b4fece7 100644 --- a/transports/http/http.go +++ b/transports/http/http.go @@ -210,10 +210,14 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { t.cfg.OnError(ErrClosed, nil) return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + // Encoders that want the prefix as a separate field can read + // it from params.Prefix in a future Entry.Prefix addition. entry := Entry{ Level: params.LogLevel, Time: time.Now(), - Messages: params.Messages, + Messages: transport.JoinPrefixAndMessages(params.Prefix, params.Messages), Metadata: params.Metadata, Groups: params.Groups, Schema: params.Schema, diff --git a/transports/logrus/logrus.go b/transports/logrus/logrus.go index b1b8d15..d335fa7 100644 --- a/transports/logrus/logrus.go +++ b/transports/logrus/logrus.go @@ -83,6 +83,9 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) fields := logrus.Fields{} if len(params.Data) > 0 { diff --git a/transports/otellog/otellog.go b/transports/otellog/otellog.go index ed373aa..18b463c 100644 --- a/transports/otellog/otellog.go +++ b/transports/otellog/otellog.go @@ -148,6 +148,9 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) var rec otellog.Record rec.SetTimestamp(time.Now()) diff --git a/transports/phuslu/phuslu.go b/transports/phuslu/phuslu.go index 53253c5..3ce195c 100644 --- a/transports/phuslu/phuslu.go +++ b/transports/phuslu/phuslu.go @@ -65,6 +65,9 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) entry := t.logger.WithLevel(toPhusluLevel(params.LogLevel)) if entry == nil { return diff --git a/transports/pretty/pretty.go b/transports/pretty/pretty.go index ca79976..c35447c 100644 --- a/transports/pretty/pretty.go +++ b/transports/pretty/pretty.go @@ -110,6 +110,9 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) combined := combineData(params) timestamp := t.formatTimestamp() diff --git a/transports/sentry/sentry.go b/transports/sentry/sentry.go index 829a45b..7f22357 100644 --- a/transports/sentry/sentry.go +++ b/transports/sentry/sentry.go @@ -73,6 +73,9 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) entry := entryForLevel(t.cfg.Logger, params.LogLevel) if params.Ctx != nil { diff --git a/transports/slog/slog.go b/transports/slog/slog.go index 71e4334..d363173 100644 --- a/transports/slog/slog.go +++ b/transports/slog/slog.go @@ -60,6 +60,9 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) attrs := make([]slog.Attr, 0, transport.FieldEstimate(params)) diff --git a/transports/structured/structured.go b/transports/structured/structured.go index b348807..cfc6e36 100644 --- a/transports/structured/structured.go +++ b/transports/structured/structured.go @@ -125,6 +125,9 @@ func (s *Transport) SendToLogger(params loglayer.TransportParams) { if !s.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) messages := params.Messages if s.cfg.MessageFn != nil { messages = []any{s.cfg.MessageFn(params)} diff --git a/transports/testing/testing.go b/transports/testing/testing.go index 3cfa3a4..177fe33 100644 --- a/transports/testing/testing.go +++ b/transports/testing/testing.go @@ -23,6 +23,10 @@ type LogLine struct { Metadata any // Ctx is the per-call context.Context attached via WithContext. Nil if not set. Ctx context.Context + // Prefix mirrors [loglayer.TransportParams.Prefix]: the value + // attached via WithPrefix or Config.Prefix. Empty when none was + // set on the emitting logger. + Prefix string } // TestLoggingLibrary captures log lines for assertion in tests. @@ -126,13 +130,19 @@ func (t *TestTransport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - messages := make([]any, len(params.Messages)) - copy(messages, params.Messages) + // Preserve the v1 "prefix folded into Messages[0]" rendering so + // existing test fixtures keep their assertions. The Prefix field + // is also exposed on LogLine for tests that want the unmangled + // signal. + src := transport.JoinPrefixAndMessages(params.Prefix, params.Messages) + messages := make([]any, len(src)) + copy(messages, src) t.Library.Log(LogLine{ Level: params.LogLevel, Messages: messages, Data: params.Data, Metadata: params.Metadata, Ctx: params.Ctx, + Prefix: params.Prefix, }) } diff --git a/transports/zap/zap.go b/transports/zap/zap.go index 45da64c..c09876e 100644 --- a/transports/zap/zap.go +++ b/transports/zap/zap.go @@ -65,6 +65,9 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) fields := make([]zap.Field, 0, transport.FieldEstimate(params)) if len(params.Data) > 0 { diff --git a/transports/zerolog/zerolog.go b/transports/zerolog/zerolog.go index 2c47128..a1adba9 100644 --- a/transports/zerolog/zerolog.go +++ b/transports/zerolog/zerolog.go @@ -62,6 +62,9 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } + // Preserve the v1 "prefix folded into Messages[0]" rendering; + // the core no longer mutates messages, transports own it now. + params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) event := t.logger.WithLevel(toZerologLevel(params.LogLevel)) if event == nil { return From 37e6d341da7d20f490a9abbb352709312b1cc86b Mon Sep 17 00:00:00 2001 From: Theo Gravity Date: Sat, 2 May 2026 15:02:02 -0700 Subject: [PATCH 2/8] feat(loglayer)!: bump every module to /v2 Phase 3 of the v2 cascade. Module path changes: - Main module: go.loglayer.dev -> go.loglayer.dev/v2. - Every transport sub-module: go.loglayer.dev/transports/ -> go.loglayer.dev/transports//v2. - Every plugin sub-module: same pattern (/plugins//v2). - Every integration sub-module: same (/integrations//v2). - All 6 example sub-modules: same. - plugins/datadogtrace/livetest: nested module also bumped. Import path updates (mechanical): - All Go file imports now resolve via the /v2 path. - Each sub-module's go.mod has its replace/require lines pointed at the /v2 path. - The placeholder version on require lines was bumped from v0.0.0-00010101000000-000000000000 to v2.0.0-00010101000000-000000000000 because Go module rules require the require version to match the major (v2.x.y for /v2 modules). This is a BREAKING CHANGE for every consumer: import paths must be updated to /v2 across the board. Phase 4 (changesets, per-module docs, migration guide, whats-new entry) follows. --- bench_test.go | 4 +- concurrency_test.go | 6 +- coverage_test.go | 2 +- dispatch_edge_test.go | 6 +- doc.go | 4 +- error_serializer_test.go | 4 +- errors_test.go | 4 +- example_test.go | 4 +- examples/custom-plugin/go.mod | 10 +-- examples/custom-plugin/main.go | 6 +- examples/custom-transport-attribute/main.go | 4 +- examples/custom-transport/main.go | 4 +- examples/datadog-shipping/go.mod | 18 ++-- examples/datadog-shipping/main.go | 10 +-- examples/http-server/go.mod | 16 ++-- examples/http-server/main.go | 6 +- examples/multi-transport/go.mod | 14 +-- examples/multi-transport/main.go | 8 +- examples/otel-end-to-end/go.mod | 18 ++-- examples/otel-end-to-end/main.go | 6 +- examples/pretty-modes/go.mod | 10 +-- examples/pretty-modes/main.go | 6 +- fields_test.go | 2 +- from_context_test.go | 2 +- go.mod | 2 +- groups_test.go | 6 +- integrations/loghttp/go.mod | 10 +-- integrations/loghttp/loghttp.go | 6 +- integrations/loghttp/loghttp_test.go | 10 +-- integrations/sloghandler/bench_test.go | 4 +- integrations/sloghandler/go.mod | 10 +-- integrations/sloghandler/sloghandler.go | 2 +- integrations/sloghandler/sloghandler_test.go | 6 +- internal/lltest/lltest.go | 4 +- internal/lltest/lltest_test.go | 6 +- lazy_test.go | 2 +- levels_test.go | 2 +- log_writer_test.go | 2 +- loglayer_test.go | 8 +- metadata_test.go | 2 +- mock_test.go | 2 +- plugin.go | 2 +- plugin_test.go | 6 +- plugin_wrapper_test.go | 6 +- plugins/datadogtrace/datadogtrace.go | 8 +- plugins/datadogtrace/datadogtrace_test.go | 6 +- plugins/datadogtrace/example_test.go | 6 +- plugins/datadogtrace/go.mod | 14 +-- plugins/datadogtrace/livetest/go.mod | 16 ++-- .../datadogtrace/livetest/livetest_test.go | 8 +- plugins/fmtlog/example_test.go | 6 +- plugins/fmtlog/fmtlog.go | 2 +- plugins/fmtlog/fmtlog_test.go | 8 +- plugins/fmtlog/go.mod | 10 +-- plugins/oteltrace/example_test.go | 6 +- plugins/oteltrace/go.mod | 14 +-- plugins/oteltrace/livetest_test.go | 8 +- plugins/oteltrace/oteltrace.go | 8 +- plugins/oteltrace/oteltrace_test.go | 6 +- plugins/plugintest/go.mod | 10 +-- plugins/plugintest/plugintest.go | 8 +- plugins/plugintest/plugintest_test.go | 4 +- plugins/redact/example_test.go | 6 +- plugins/redact/go.mod | 14 +-- plugins/redact/redact.go | 4 +- plugins/redact/redact_test.go | 6 +- plugins/sampling/example_test.go | 6 +- plugins/sampling/go.mod | 14 +-- plugins/sampling/sampling.go | 2 +- plugins/sampling/sampling_test.go | 6 +- source_test.go | 4 +- transport/benchtest/benchtest.go | 2 +- transport/concurrency_test.go | 6 +- transport/helpers.go | 4 +- transport/helpers_test.go | 4 +- transport/transport.go | 4 +- transport/transporttest/contract.go | 2 +- transport/transporttest/livetest.go | 2 +- transport/transporttest/transporttest.go | 2 +- transport_panic_test.go | 6 +- transports/blank/blank.go | 4 +- transports/blank/blank_test.go | 6 +- transports/blank/example_test.go | 4 +- transports/blank/go.mod | 6 +- transports/central/central.go | 4 +- transports/central/central_test.go | 8 +- transports/central/example_test.go | 4 +- transports/central/go.mod | 10 +-- transports/charmlog/bench_test.go | 8 +- transports/charmlog/charmlog.go | 4 +- transports/charmlog/charmlog_test.go | 8 +- transports/charmlog/example_test.go | 4 +- transports/charmlog/go.mod | 6 +- transports/cli/cli.go | 87 +++++++++++++------ transports/cli/cli_test.go | 4 +- transports/cli/example_test.go | 4 +- transports/cli/go.mod | 6 +- transports/console/bench_test.go | 8 +- transports/console/console.go | 6 +- transports/console/console_test.go | 6 +- transports/console/example_test.go | 4 +- transports/console/go.mod | 6 +- transports/console/routing_test.go | 2 +- transports/datadog/datadog.go | 6 +- transports/datadog/datadog_test.go | 8 +- transports/datadog/example_test.go | 4 +- transports/datadog/go.mod | 10 +-- transports/datadog/livetest_test.go | 8 +- transports/gcplogging/example_test.go | 4 +- transports/gcplogging/gcplogging.go | 4 +- transports/gcplogging/gcplogging_test.go | 2 +- transports/gcplogging/go.mod | 6 +- transports/gcplogging/livetest_test.go | 6 +- transports/http/example_test.go | 4 +- transports/http/go.mod | 6 +- transports/http/http.go | 4 +- transports/http/http_test.go | 6 +- transports/logrus/bench_test.go | 8 +- transports/logrus/example_test.go | 4 +- transports/logrus/go.mod | 6 +- transports/logrus/logrus.go | 4 +- transports/logrus/logrus_test.go | 8 +- transports/lumberjack/example_test.go | 4 +- transports/lumberjack/go.mod | 10 +-- transports/lumberjack/lumberjack.go | 6 +- transports/lumberjack/lumberjack_test.go | 8 +- transports/otellog/example_test.go | 4 +- transports/otellog/go.mod | 6 +- transports/otellog/livetest_test.go | 4 +- transports/otellog/otellog.go | 8 +- transports/otellog/otellog_test.go | 6 +- transports/phuslu/bench_test.go | 8 +- transports/phuslu/example_test.go | 4 +- transports/phuslu/go.mod | 6 +- transports/phuslu/phuslu.go | 4 +- transports/phuslu/phuslu_test.go | 8 +- transports/pretty/bench_test.go | 8 +- transports/pretty/example_test.go | 4 +- transports/pretty/go.mod | 6 +- transports/pretty/pretty.go | 6 +- transports/pretty/pretty_test.go | 6 +- transports/pretty/render.go | 2 +- transports/sentry/example_test.go | 4 +- transports/sentry/go.mod | 6 +- transports/sentry/livetest_test.go | 6 +- transports/sentry/sentry.go | 4 +- transports/sentry/sentry_test.go | 6 +- transports/slog/example_test.go | 4 +- transports/slog/go.mod | 6 +- transports/slog/slog.go | 4 +- transports/slog/slog_test.go | 8 +- transports/structured/bench_test.go | 8 +- transports/structured/example_test.go | 4 +- transports/structured/go.mod | 6 +- transports/structured/structured.go | 4 +- transports/structured/structured_test.go | 8 +- transports/testing/bench_test.go | 8 +- transports/testing/example_test.go | 4 +- transports/testing/go.mod | 6 +- transports/testing/testing.go | 4 +- transports/testing/testing_test.go | 6 +- transports/zap/bench_test.go | 8 +- transports/zap/example_test.go | 4 +- transports/zap/go.mod | 6 +- transports/zap/zap.go | 4 +- transports/zap/zap_test.go | 8 +- transports/zerolog/bench_test.go | 8 +- transports/zerolog/example_test.go | 4 +- transports/zerolog/go.mod | 6 +- transports/zerolog/zerolog.go | 4 +- transports/zerolog/zerolog_test.go | 8 +- transports_test.go | 6 +- utils/maputil/cloner_test.go | 2 +- utils/sanitize/sanitize_test.go | 2 +- 174 files changed, 580 insertions(+), 545 deletions(-) diff --git a/bench_test.go b/bench_test.go index d019c91..85a72d9 100644 --- a/bench_test.go +++ b/bench_test.go @@ -15,8 +15,8 @@ package loglayer_test import ( "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport/benchtest" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport/benchtest" ) type noopTransport struct{} diff --git a/concurrency_test.go b/concurrency_test.go index f372af1..1e668fe 100644 --- a/concurrency_test.go +++ b/concurrency_test.go @@ -13,9 +13,9 @@ import ( "sync/atomic" "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" + "go.loglayer.dev/v2/transport" ) func TestConcurrentEmission_SimpleMessage(t *testing.T) { diff --git a/coverage_test.go b/coverage_test.go index fdec7cf..ef8c3a2 100644 --- a/coverage_test.go +++ b/coverage_test.go @@ -9,7 +9,7 @@ import ( "errors" "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) func TestBuild_NoTransport(t *testing.T) { diff --git a/dispatch_edge_test.go b/dispatch_edge_test.go index 3b3975d..2d1cbec 100644 --- a/dispatch_edge_test.go +++ b/dispatch_edge_test.go @@ -4,9 +4,9 @@ import ( "errors" "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" + "go.loglayer.dev/v2/transport" ) // dispatch_edge_test.go covers edge cases of the processLog dispatch path diff --git a/doc.go b/doc.go index 6f8a135..7b70508 100644 --- a/doc.go +++ b/doc.go @@ -9,8 +9,8 @@ // # Quickstart // // import ( -// "go.loglayer.dev" -// "go.loglayer.dev/transports/structured" +// "go.loglayer.dev/v2" +// "go.loglayer.dev/transports/structured/v2" // ) // // log := loglayer.New(loglayer.Config{ diff --git a/error_serializer_test.go b/error_serializer_test.go index 979bcb1..665d503 100644 --- a/error_serializer_test.go +++ b/error_serializer_test.go @@ -5,8 +5,8 @@ import ( "fmt" "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" ) func newUnwrapLogger(t *testing.T) (*loglayer.LogLayer, *lltest.TestLoggingLibrary) { diff --git a/errors_test.go b/errors_test.go index f23dfaf..7c8f675 100644 --- a/errors_test.go +++ b/errors_test.go @@ -4,8 +4,8 @@ import ( "errors" "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport/transporttest" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport/transporttest" ) func TestWithError(t *testing.T) { diff --git a/example_test.go b/example_test.go index 859198d..6ffa495 100644 --- a/example_test.go +++ b/example_test.go @@ -22,8 +22,8 @@ import ( "sort" "strings" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // fixedTime returns a deterministic timestamp for example output. diff --git a/examples/custom-plugin/go.mod b/examples/custom-plugin/go.mod index c595dfc..8c29a64 100644 --- a/examples/custom-plugin/go.mod +++ b/examples/custom-plugin/go.mod @@ -1,15 +1,15 @@ -module go.loglayer.dev/examples/custom-plugin +module go.loglayer.dev/examples/custom-plugin/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/transports/pretty => ../../transports/pretty + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/transports/pretty/v2 => ../../transports/pretty ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/pretty v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/pretty/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/examples/custom-plugin/main.go b/examples/custom-plugin/main.go index 53b81a1..099efbd 100644 --- a/examples/custom-plugin/main.go +++ b/examples/custom-plugin/main.go @@ -25,9 +25,9 @@ import ( "strings" "sync/atomic" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transports/pretty" + "go.loglayer.dev/transports/pretty/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // hostInfoPlugin tags every entry with the host name and PID, and diff --git a/examples/custom-transport-attribute/main.go b/examples/custom-transport-attribute/main.go index 8c89ac2..e61fb3b 100644 --- a/examples/custom-transport-attribute/main.go +++ b/examples/custom-transport-attribute/main.go @@ -21,8 +21,8 @@ import ( "fmt" "os" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // fakeBackend is a stand-in for a real attribute-aware logger. It accepts diff --git a/examples/custom-transport/main.go b/examples/custom-transport/main.go index 2bda060..f739699 100644 --- a/examples/custom-transport/main.go +++ b/examples/custom-transport/main.go @@ -20,8 +20,8 @@ import ( "strings" "time" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // pipeTransport renders entries as `LEVEL | msg | k=v k=v ...`. diff --git a/examples/datadog-shipping/go.mod b/examples/datadog-shipping/go.mod index a3539f8..bdfa640 100644 --- a/examples/datadog-shipping/go.mod +++ b/examples/datadog-shipping/go.mod @@ -1,19 +1,19 @@ -module go.loglayer.dev/examples/datadog-shipping +module go.loglayer.dev/examples/datadog-shipping/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/transports/datadog => ../../transports/datadog - go.loglayer.dev/transports/http => ../../transports/http - go.loglayer.dev/transports/pretty => ../../transports/pretty + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/transports/datadog/v2 => ../../transports/datadog + go.loglayer.dev/transports/http/v2 => ../../transports/http + go.loglayer.dev/transports/pretty/v2 => ../../transports/pretty ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/datadog v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/http v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/pretty v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/datadog/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/http/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/pretty/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/examples/datadog-shipping/main.go b/examples/datadog-shipping/main.go index d6afe0b..3f8271b 100644 --- a/examples/datadog-shipping/main.go +++ b/examples/datadog-shipping/main.go @@ -17,11 +17,11 @@ import ( "os" "time" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transports/datadog" - httptr "go.loglayer.dev/transports/http" - "go.loglayer.dev/transports/pretty" + "go.loglayer.dev/transports/datadog/v2" + httptr "go.loglayer.dev/transports/http/v2" + "go.loglayer.dev/transports/pretty/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) func main() { diff --git a/examples/http-server/go.mod b/examples/http-server/go.mod index 625dab9..2aeb143 100644 --- a/examples/http-server/go.mod +++ b/examples/http-server/go.mod @@ -1,18 +1,18 @@ -module go.loglayer.dev/examples/http-server +module go.loglayer.dev/examples/http-server/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/integrations/loghttp => ../../integrations/loghttp - go.loglayer.dev/transports/structured => ../../transports/structured - go.loglayer.dev/transports/testing => ../../transports/testing + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/integrations/loghttp/v2 => ../../integrations/loghttp + go.loglayer.dev/transports/structured/v2 => ../../transports/structured + go.loglayer.dev/transports/testing/v2 => ../../transports/testing ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/integrations/loghttp v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/structured v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/integrations/loghttp/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/structured/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/examples/http-server/main.go b/examples/http-server/main.go index 9611db1..bd896b4 100644 --- a/examples/http-server/main.go +++ b/examples/http-server/main.go @@ -13,9 +13,9 @@ package main import ( "net/http" - "go.loglayer.dev" - "go.loglayer.dev/integrations/loghttp" - "go.loglayer.dev/transports/structured" + "go.loglayer.dev/integrations/loghttp/v2" + "go.loglayer.dev/transports/structured/v2" + "go.loglayer.dev/v2" ) var serverLog = loglayer.New(loglayer.Config{ diff --git a/examples/multi-transport/go.mod b/examples/multi-transport/go.mod index 7222743..9a09ccf 100644 --- a/examples/multi-transport/go.mod +++ b/examples/multi-transport/go.mod @@ -1,17 +1,17 @@ -module go.loglayer.dev/examples/multi-transport +module go.loglayer.dev/examples/multi-transport/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/transports/pretty => ../../transports/pretty - go.loglayer.dev/transports/structured => ../../transports/structured + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/transports/pretty/v2 => ../../transports/pretty + go.loglayer.dev/transports/structured/v2 => ../../transports/structured ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/pretty v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/structured v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/pretty/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/structured/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/examples/multi-transport/main.go b/examples/multi-transport/main.go index 3affcf7..415efd1 100644 --- a/examples/multi-transport/main.go +++ b/examples/multi-transport/main.go @@ -15,10 +15,10 @@ import ( "errors" "os" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transports/pretty" - "go.loglayer.dev/transports/structured" + "go.loglayer.dev/transports/pretty/v2" + "go.loglayer.dev/transports/structured/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) func main() { diff --git a/examples/otel-end-to-end/go.mod b/examples/otel-end-to-end/go.mod index 5bfab76..64f8d03 100644 --- a/examples/otel-end-to-end/go.mod +++ b/examples/otel-end-to-end/go.mod @@ -1,19 +1,19 @@ -module go.loglayer.dev/examples/otel-end-to-end +module go.loglayer.dev/examples/otel-end-to-end/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/plugins/oteltrace => ../../plugins/oteltrace - go.loglayer.dev/plugins/plugintest => ../../plugins/plugintest - go.loglayer.dev/transports/otellog => ../../transports/otellog - go.loglayer.dev/transports/testing => ../../transports/testing + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/plugins/oteltrace/v2 => ../../plugins/oteltrace + go.loglayer.dev/plugins/plugintest/v2 => ../../plugins/plugintest + go.loglayer.dev/transports/otellog/v2 => ../../transports/otellog + go.loglayer.dev/transports/testing/v2 => ../../transports/testing ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/plugins/oteltrace v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/otellog v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/plugins/oteltrace/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/otellog/v2 v2.0.0-00010101000000-000000000000 go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 diff --git a/examples/otel-end-to-end/main.go b/examples/otel-end-to-end/main.go index e3809c7..7ea71a9 100644 --- a/examples/otel-end-to-end/main.go +++ b/examples/otel-end-to-end/main.go @@ -24,9 +24,9 @@ import ( "fmt" "os" - "go.loglayer.dev" - "go.loglayer.dev/plugins/oteltrace" - "go.loglayer.dev/transports/otellog" + "go.loglayer.dev/plugins/oteltrace/v2" + "go.loglayer.dev/transports/otellog/v2" + "go.loglayer.dev/v2" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" diff --git a/examples/pretty-modes/go.mod b/examples/pretty-modes/go.mod index 4b51e93..73e1193 100644 --- a/examples/pretty-modes/go.mod +++ b/examples/pretty-modes/go.mod @@ -1,15 +1,15 @@ -module go.loglayer.dev/examples/pretty-modes +module go.loglayer.dev/examples/pretty-modes/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/transports/pretty => ../../transports/pretty + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/transports/pretty/v2 => ../../transports/pretty ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/pretty v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/pretty/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/examples/pretty-modes/main.go b/examples/pretty-modes/main.go index 0ec641c..fae87a5 100644 --- a/examples/pretty-modes/main.go +++ b/examples/pretty-modes/main.go @@ -25,9 +25,9 @@ import ( "log" "os" - "go.loglayer.dev" - "go.loglayer.dev/transport/transporttest" - "go.loglayer.dev/transports/pretty" + "go.loglayer.dev/transports/pretty/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport/transporttest" ) func main() { diff --git a/fields_test.go b/fields_test.go index 3aa33a8..d7ba702 100644 --- a/fields_test.go +++ b/fields_test.go @@ -3,7 +3,7 @@ package loglayer_test import ( "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) func TestWithFields(t *testing.T) { diff --git a/from_context_test.go b/from_context_test.go index b027ce5..b89c8fb 100644 --- a/from_context_test.go +++ b/from_context_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) func TestNewContextAndFromContext_RoundTrip(t *testing.T) { diff --git a/go.mod b/go.mod index 8c9bb1e..a734b17 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module go.loglayer.dev +module go.loglayer.dev/v2 go 1.25.0 diff --git a/groups_test.go b/groups_test.go index bda6a70..47ec4c8 100644 --- a/groups_test.go +++ b/groups_test.go @@ -6,9 +6,9 @@ import ( "slices" "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" + "go.loglayer.dev/v2/transport" ) // twoTransports builds two named TestLoggingLibrary-backed transports for diff --git a/integrations/loghttp/go.mod b/integrations/loghttp/go.mod index 51bb498..d7b9f19 100644 --- a/integrations/loghttp/go.mod +++ b/integrations/loghttp/go.mod @@ -1,15 +1,15 @@ -module go.loglayer.dev/integrations/loghttp +module go.loglayer.dev/integrations/loghttp/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/transports/testing => ../../transports/testing + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/transports/testing/v2 => ../../transports/testing ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/testing v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/integrations/loghttp/loghttp.go b/integrations/loghttp/loghttp.go index 7a28bf2..7ec1014 100644 --- a/integrations/loghttp/loghttp.go +++ b/integrations/loghttp/loghttp.go @@ -23,9 +23,9 @@ import ( "strings" "time" - "go.loglayer.dev" - "go.loglayer.dev/utils/idgen" - "go.loglayer.dev/utils/sanitize" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/utils/idgen" + "go.loglayer.dev/v2/utils/sanitize" ) // FieldNames customizes the keys emitted by the middleware. Empty values fall diff --git a/integrations/loghttp/loghttp_test.go b/integrations/loghttp/loghttp_test.go index 54fd4c7..b3970a6 100644 --- a/integrations/loghttp/loghttp_test.go +++ b/integrations/loghttp/loghttp_test.go @@ -7,11 +7,11 @@ import ( "strings" "testing" - "go.loglayer.dev" - "go.loglayer.dev/integrations/loghttp" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/transporttest" - lltest "go.loglayer.dev/transports/testing" + "go.loglayer.dev/integrations/loghttp/v2" + lltest "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/transporttest" ) func setupLogger(t *testing.T) (*loglayer.LogLayer, *lltest.TestLoggingLibrary) { diff --git a/integrations/sloghandler/bench_test.go b/integrations/sloghandler/bench_test.go index 43dc6b1..175c00f 100644 --- a/integrations/sloghandler/bench_test.go +++ b/integrations/sloghandler/bench_test.go @@ -6,8 +6,8 @@ import ( "log/slog" "testing" - "go.loglayer.dev" - "go.loglayer.dev/integrations/sloghandler" + "go.loglayer.dev/integrations/sloghandler/v2" + "go.loglayer.dev/v2" ) // noopTransport drops everything; used to isolate handler dispatch cost diff --git a/integrations/sloghandler/go.mod b/integrations/sloghandler/go.mod index c4ed461..5b2229b 100644 --- a/integrations/sloghandler/go.mod +++ b/integrations/sloghandler/go.mod @@ -1,15 +1,15 @@ -module go.loglayer.dev/integrations/sloghandler +module go.loglayer.dev/integrations/sloghandler/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/transports/testing => ../../transports/testing + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/transports/testing/v2 => ../../transports/testing ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/testing v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/integrations/sloghandler/sloghandler.go b/integrations/sloghandler/sloghandler.go index cc7c717..a0c4be6 100644 --- a/integrations/sloghandler/sloghandler.go +++ b/integrations/sloghandler/sloghandler.go @@ -45,7 +45,7 @@ import ( "log/slog" "slices" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) // Handler is a slog.Handler that emits records through a loglayer logger. diff --git a/integrations/sloghandler/sloghandler_test.go b/integrations/sloghandler/sloghandler_test.go index 7bf669b..edb8b81 100644 --- a/integrations/sloghandler/sloghandler_test.go +++ b/integrations/sloghandler/sloghandler_test.go @@ -9,9 +9,9 @@ import ( "testing" "time" - "go.loglayer.dev" - "go.loglayer.dev/integrations/sloghandler" - lltest "go.loglayer.dev/transports/testing" + "go.loglayer.dev/integrations/sloghandler/v2" + lltest "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" ) func newSlog(t *testing.T) (*slog.Logger, *lltest.TestLoggingLibrary, *loglayer.LogLayer) { diff --git a/internal/lltest/lltest.go b/internal/lltest/lltest.go index d696a41..d9e95c5 100644 --- a/internal/lltest/lltest.go +++ b/internal/lltest/lltest.go @@ -12,8 +12,8 @@ import ( "context" "sync" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // LogLine is a single captured log entry. Fields are exposed directly so tests diff --git a/internal/lltest/lltest_test.go b/internal/lltest/lltest_test.go index 421d58a..6a6b929 100644 --- a/internal/lltest/lltest_test.go +++ b/internal/lltest/lltest_test.go @@ -3,9 +3,9 @@ package lltest_test import ( "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" + "go.loglayer.dev/v2/transport" ) func newLogger() (*loglayer.LogLayer, *lltest.TestLoggingLibrary) { diff --git a/lazy_test.go b/lazy_test.go index ef58a7e..620dc7d 100644 --- a/lazy_test.go +++ b/lazy_test.go @@ -4,7 +4,7 @@ import ( "sync/atomic" "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) // Lazy in WithFields resolves at emit time and the result lands in diff --git a/levels_test.go b/levels_test.go index 212b1b6..67f43f1 100644 --- a/levels_test.go +++ b/levels_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) func TestSetLevel(t *testing.T) { diff --git a/log_writer_test.go b/log_writer_test.go index 11caed8..e4e3b8d 100644 --- a/log_writer_test.go +++ b/log_writer_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) func TestWriter_BasicEmission(t *testing.T) { diff --git a/loglayer_test.go b/loglayer_test.go index 821d402..e615549 100644 --- a/loglayer_test.go +++ b/loglayer_test.go @@ -11,10 +11,10 @@ package loglayer_test import ( "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/transporttest" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/transporttest" ) func setup(t *testing.T) (*loglayer.LogLayer, *lltest.TestLoggingLibrary) { diff --git a/metadata_test.go b/metadata_test.go index a6808fe..a6ce93f 100644 --- a/metadata_test.go +++ b/metadata_test.go @@ -3,7 +3,7 @@ package loglayer_test import ( "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) func TestWithMetadataMap(t *testing.T) { diff --git a/mock_test.go b/mock_test.go index 6d3bdd3..b3c0a10 100644 --- a/mock_test.go +++ b/mock_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) func TestNewMockReturnsUsableLogger(t *testing.T) { diff --git a/plugin.go b/plugin.go index 13a3e54..82d6b5f 100644 --- a/plugin.go +++ b/plugin.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - "go.loglayer.dev/utils/idgen" + "go.loglayer.dev/v2/utils/idgen" ) // Plugin is the base contract every plugin satisfies. A plugin participates diff --git a/plugin_test.go b/plugin_test.go index fbf9894..78fd62f 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -9,9 +9,9 @@ import ( "sync/atomic" "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" + "go.loglayer.dev/v2/transport" ) func TestPlugin_OnBeforeDataOut_AddsKeys(t *testing.T) { diff --git a/plugin_wrapper_test.go b/plugin_wrapper_test.go index 0b2da52..71d20b6 100644 --- a/plugin_wrapper_test.go +++ b/plugin_wrapper_test.go @@ -3,9 +3,9 @@ package loglayer_test import ( "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" + "go.loglayer.dev/v2/transport" ) // A wrapped DataHook plugin must NOT register for unrelated hooks. If diff --git a/plugins/datadogtrace/datadogtrace.go b/plugins/datadogtrace/datadogtrace.go index ac531ff..819242b 100644 --- a/plugins/datadogtrace/datadogtrace.go +++ b/plugins/datadogtrace/datadogtrace.go @@ -18,9 +18,9 @@ // import ( // "context" // ddtracer "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" -// "go.loglayer.dev" -// "go.loglayer.dev/plugins/datadogtrace" -// "go.loglayer.dev/transports/structured" +// "go.loglayer.dev/v2" +// "go.loglayer.dev/plugins/datadogtrace/v2" +// "go.loglayer.dev/transports/structured/v2" // ) // // ddtracer.Start(ddtracer.WithService("checkout-api")) @@ -56,7 +56,7 @@ import ( "context" "strconv" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) // Config holds plugin configuration. diff --git a/plugins/datadogtrace/datadogtrace_test.go b/plugins/datadogtrace/datadogtrace_test.go index 06d3d91..d372c57 100644 --- a/plugins/datadogtrace/datadogtrace_test.go +++ b/plugins/datadogtrace/datadogtrace_test.go @@ -6,9 +6,9 @@ import ( "strings" "testing" - "go.loglayer.dev" - "go.loglayer.dev/plugins/datadogtrace" - "go.loglayer.dev/plugins/plugintest" + "go.loglayer.dev/plugins/datadogtrace/v2" + "go.loglayer.dev/plugins/plugintest/v2" + "go.loglayer.dev/v2" ) // fakeExtract returns a deterministic extractor for tests. diff --git a/plugins/datadogtrace/example_test.go b/plugins/datadogtrace/example_test.go index 9d7aa5e..21f789b 100644 --- a/plugins/datadogtrace/example_test.go +++ b/plugins/datadogtrace/example_test.go @@ -3,9 +3,9 @@ package datadogtrace_test import ( "context" - "go.loglayer.dev" - "go.loglayer.dev/plugins/datadogtrace" - lltesting "go.loglayer.dev/transports/testing" + "go.loglayer.dev/plugins/datadogtrace/v2" + lltesting "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" ) // New returns a plugin that injects dd.trace_id and dd.span_id onto diff --git a/plugins/datadogtrace/go.mod b/plugins/datadogtrace/go.mod index 4e5abb6..79860e9 100644 --- a/plugins/datadogtrace/go.mod +++ b/plugins/datadogtrace/go.mod @@ -1,17 +1,17 @@ -module go.loglayer.dev/plugins/datadogtrace +module go.loglayer.dev/plugins/datadogtrace/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/plugins/plugintest => ../plugintest - go.loglayer.dev/transports/testing => ../../transports/testing + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/plugins/plugintest/v2 => ../plugintest + go.loglayer.dev/transports/testing/v2 => ../../transports/testing ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/plugins/plugintest v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/testing v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/plugins/plugintest/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/plugins/datadogtrace/livetest/go.mod b/plugins/datadogtrace/livetest/go.mod index 977d521..f9e0227 100644 --- a/plugins/datadogtrace/livetest/go.mod +++ b/plugins/datadogtrace/livetest/go.mod @@ -1,19 +1,19 @@ -module go.loglayer.dev/plugins/datadogtrace/livetest +module go.loglayer.dev/plugins/datadogtrace/livetest/v2 go 1.25.0 replace ( - go.loglayer.dev => ../../.. - go.loglayer.dev/plugins/datadogtrace => .. - go.loglayer.dev/plugins/plugintest => ../../plugintest - go.loglayer.dev/transports/testing => ../../../transports/testing + go.loglayer.dev/v2 => ../../.. + go.loglayer.dev/plugins/datadogtrace/v2 => .. + go.loglayer.dev/plugins/plugintest/v2 => ../../plugintest + go.loglayer.dev/transports/testing/v2 => ../../../transports/testing ) require ( github.com/DataDog/dd-trace-go/v2 v2.7.3 - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/plugins/datadogtrace v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/testing v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/plugins/datadogtrace/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/plugins/datadogtrace/livetest/livetest_test.go b/plugins/datadogtrace/livetest/livetest_test.go index 13b4db3..0a6ef34 100644 --- a/plugins/datadogtrace/livetest/livetest_test.go +++ b/plugins/datadogtrace/livetest/livetest_test.go @@ -18,10 +18,10 @@ import ( "strconv" "testing" - "go.loglayer.dev" - "go.loglayer.dev/plugins/datadogtrace" - "go.loglayer.dev/transport" - lltest "go.loglayer.dev/transports/testing" + "go.loglayer.dev/plugins/datadogtrace/v2" + lltest "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ddmocktracer "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" ddtracer "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" diff --git a/plugins/fmtlog/example_test.go b/plugins/fmtlog/example_test.go index 6340ed1..2c80e8c 100644 --- a/plugins/fmtlog/example_test.go +++ b/plugins/fmtlog/example_test.go @@ -3,9 +3,9 @@ package fmtlog_test import ( "fmt" - "go.loglayer.dev" - "go.loglayer.dev/plugins/fmtlog" - lltesting "go.loglayer.dev/transports/testing" + "go.loglayer.dev/plugins/fmtlog/v2" + lltesting "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" ) // New returns a plugin that rewrites multi-argument log messages via diff --git a/plugins/fmtlog/fmtlog.go b/plugins/fmtlog/fmtlog.go index a5c8b93..d54b71f 100644 --- a/plugins/fmtlog/fmtlog.go +++ b/plugins/fmtlog/fmtlog.go @@ -21,7 +21,7 @@ package fmtlog import ( "fmt" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) // New returns a plugin that resolves multi-argument log messages via diff --git a/plugins/fmtlog/fmtlog_test.go b/plugins/fmtlog/fmtlog_test.go index b71640f..de226c6 100644 --- a/plugins/fmtlog/fmtlog_test.go +++ b/plugins/fmtlog/fmtlog_test.go @@ -4,10 +4,10 @@ import ( "errors" "testing" - "go.loglayer.dev" - "go.loglayer.dev/plugins/fmtlog" - "go.loglayer.dev/transport" - lltest "go.loglayer.dev/transports/testing" + "go.loglayer.dev/plugins/fmtlog/v2" + lltest "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) func newLogger(t *testing.T) (*loglayer.LogLayer, *lltest.TestLoggingLibrary) { diff --git a/plugins/fmtlog/go.mod b/plugins/fmtlog/go.mod index 868f364..dd6fa23 100644 --- a/plugins/fmtlog/go.mod +++ b/plugins/fmtlog/go.mod @@ -1,15 +1,15 @@ -module go.loglayer.dev/plugins/fmtlog +module go.loglayer.dev/plugins/fmtlog/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/transports/testing => ../../transports/testing + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/transports/testing/v2 => ../../transports/testing ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/testing v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/plugins/oteltrace/example_test.go b/plugins/oteltrace/example_test.go index 430f5d2..02bb6fd 100644 --- a/plugins/oteltrace/example_test.go +++ b/plugins/oteltrace/example_test.go @@ -1,9 +1,9 @@ package oteltrace_test import ( - "go.loglayer.dev" - "go.loglayer.dev/plugins/oteltrace" - lltesting "go.loglayer.dev/transports/testing" + "go.loglayer.dev/plugins/oteltrace/v2" + lltesting "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" ) // New returns a plugin that injects the active OTel span's trace_id diff --git a/plugins/oteltrace/go.mod b/plugins/oteltrace/go.mod index 502ebbf..0a43421 100644 --- a/plugins/oteltrace/go.mod +++ b/plugins/oteltrace/go.mod @@ -1,17 +1,17 @@ -module go.loglayer.dev/plugins/oteltrace +module go.loglayer.dev/plugins/oteltrace/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/plugins/plugintest => ../plugintest - go.loglayer.dev/transports/testing => ../../transports/testing + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/plugins/plugintest/v2 => ../plugintest + go.loglayer.dev/transports/testing/v2 => ../../transports/testing ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/plugins/plugintest v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/testing v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/plugins/plugintest/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/sdk v1.43.0 go.opentelemetry.io/otel/trace v1.43.0 diff --git a/plugins/oteltrace/livetest_test.go b/plugins/oteltrace/livetest_test.go index 9470522..904a418 100644 --- a/plugins/oteltrace/livetest_test.go +++ b/plugins/oteltrace/livetest_test.go @@ -14,10 +14,10 @@ import ( "context" "testing" - "go.loglayer.dev" - "go.loglayer.dev/plugins/oteltrace" - "go.loglayer.dev/plugins/plugintest" - lltest "go.loglayer.dev/transports/testing" + "go.loglayer.dev/plugins/oteltrace/v2" + "go.loglayer.dev/plugins/plugintest/v2" + lltest "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" "go.opentelemetry.io/otel/baggage" otrace "go.opentelemetry.io/otel/trace" diff --git a/plugins/oteltrace/oteltrace.go b/plugins/oteltrace/oteltrace.go index 25063f0..1df8f29 100644 --- a/plugins/oteltrace/oteltrace.go +++ b/plugins/oteltrace/oteltrace.go @@ -18,9 +18,9 @@ // Usage: // // import ( -// "go.loglayer.dev" -// "go.loglayer.dev/plugins/oteltrace" -// "go.loglayer.dev/transports/structured" +// "go.loglayer.dev/v2" +// "go.loglayer.dev/plugins/oteltrace/v2" +// "go.loglayer.dev/transports/structured/v2" // ) // // log := loglayer.New(loglayer.Config{ @@ -37,7 +37,7 @@ package oteltrace import ( - "go.loglayer.dev" + "go.loglayer.dev/v2" "go.opentelemetry.io/otel/baggage" "go.opentelemetry.io/otel/trace" ) diff --git a/plugins/oteltrace/oteltrace_test.go b/plugins/oteltrace/oteltrace_test.go index 31793e3..54ee2ec 100644 --- a/plugins/oteltrace/oteltrace_test.go +++ b/plugins/oteltrace/oteltrace_test.go @@ -4,9 +4,9 @@ import ( "context" "testing" - "go.loglayer.dev" - "go.loglayer.dev/plugins/oteltrace" - "go.loglayer.dev/plugins/plugintest" + "go.loglayer.dev/plugins/oteltrace/v2" + "go.loglayer.dev/plugins/plugintest/v2" + "go.loglayer.dev/v2" "go.opentelemetry.io/otel/baggage" otrace "go.opentelemetry.io/otel/trace" ) diff --git a/plugins/plugintest/go.mod b/plugins/plugintest/go.mod index 9c57cd8..c3bbd6b 100644 --- a/plugins/plugintest/go.mod +++ b/plugins/plugintest/go.mod @@ -1,15 +1,15 @@ -module go.loglayer.dev/plugins/plugintest +module go.loglayer.dev/plugins/plugintest/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/transports/testing => ../../transports/testing + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/transports/testing/v2 => ../../transports/testing ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/testing v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/plugins/plugintest/plugintest.go b/plugins/plugintest/plugintest.go index 3648e98..bbcab9a 100644 --- a/plugins/plugintest/plugintest.go +++ b/plugins/plugintest/plugintest.go @@ -18,10 +18,10 @@ import ( "reflect" "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - lltest "go.loglayer.dev/transports/testing" - "go.loglayer.dev/utils/maputil" + lltest "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/utils/maputil" ) // Install builds a fresh *loglayer.LogLayer with p installed and the diff --git a/plugins/plugintest/plugintest_test.go b/plugins/plugintest/plugintest_test.go index c3f8f96..9debd4c 100644 --- a/plugins/plugintest/plugintest_test.go +++ b/plugins/plugintest/plugintest_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" - "go.loglayer.dev" - "go.loglayer.dev/plugins/plugintest" + "go.loglayer.dev/plugins/plugintest/v2" + "go.loglayer.dev/v2" ) func TestInstall_PluginRunsAndCaptures(t *testing.T) { diff --git a/plugins/redact/example_test.go b/plugins/redact/example_test.go index 23aa849..b35ebaa 100644 --- a/plugins/redact/example_test.go +++ b/plugins/redact/example_test.go @@ -3,9 +3,9 @@ package redact_test import ( "fmt" - "go.loglayer.dev" - "go.loglayer.dev/plugins/redact" - lltesting "go.loglayer.dev/transports/testing" + "go.loglayer.dev/plugins/redact/v2" + lltesting "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" ) // New returns a plugin that replaces values for keys listed in diff --git a/plugins/redact/go.mod b/plugins/redact/go.mod index 7dc0d83..d1f18a3 100644 --- a/plugins/redact/go.mod +++ b/plugins/redact/go.mod @@ -1,17 +1,17 @@ -module go.loglayer.dev/plugins/redact +module go.loglayer.dev/plugins/redact/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/plugins/plugintest => ../plugintest - go.loglayer.dev/transports/testing => ../../transports/testing + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/plugins/plugintest/v2 => ../plugintest + go.loglayer.dev/transports/testing/v2 => ../../transports/testing ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/plugins/plugintest v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/testing v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/plugins/plugintest/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/plugins/redact/redact.go b/plugins/redact/redact.go index 2970c6c..5618eb2 100644 --- a/plugins/redact/redact.go +++ b/plugins/redact/redact.go @@ -28,8 +28,8 @@ package redact import ( "regexp" - "go.loglayer.dev" - "go.loglayer.dev/utils/maputil" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/utils/maputil" ) // Config holds redactor configuration. diff --git a/plugins/redact/redact_test.go b/plugins/redact/redact_test.go index b7ab6be..a88f8a0 100644 --- a/plugins/redact/redact_test.go +++ b/plugins/redact/redact_test.go @@ -5,9 +5,9 @@ import ( "regexp" "testing" - "go.loglayer.dev" - "go.loglayer.dev/plugins/plugintest" - "go.loglayer.dev/plugins/redact" + "go.loglayer.dev/plugins/plugintest/v2" + "go.loglayer.dev/plugins/redact/v2" + "go.loglayer.dev/v2" ) func TestRedact_MetadataMapKey(t *testing.T) { diff --git a/plugins/sampling/example_test.go b/plugins/sampling/example_test.go index 78313fe..6a94a37 100644 --- a/plugins/sampling/example_test.go +++ b/plugins/sampling/example_test.go @@ -3,9 +3,9 @@ package sampling_test import ( "fmt" - "go.loglayer.dev" - "go.loglayer.dev/plugins/sampling" - lltesting "go.loglayer.dev/transports/testing" + "go.loglayer.dev/plugins/sampling/v2" + lltesting "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" ) // FixedRate keeps the given fraction of emissions. rate >= 1 keeps diff --git a/plugins/sampling/go.mod b/plugins/sampling/go.mod index 9dab673..5f5531e 100644 --- a/plugins/sampling/go.mod +++ b/plugins/sampling/go.mod @@ -1,17 +1,17 @@ -module go.loglayer.dev/plugins/sampling +module go.loglayer.dev/plugins/sampling/v2 go 1.25.0 replace ( - go.loglayer.dev => ../.. - go.loglayer.dev/plugins/plugintest => ../plugintest - go.loglayer.dev/transports/testing => ../../transports/testing + go.loglayer.dev/v2 => ../.. + go.loglayer.dev/plugins/plugintest/v2 => ../plugintest + go.loglayer.dev/transports/testing/v2 => ../../transports/testing ) require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/plugins/plugintest v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/testing v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/plugins/plugintest/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/plugins/sampling/sampling.go b/plugins/sampling/sampling.go index e1ab3f2..f5d789f 100644 --- a/plugins/sampling/sampling.go +++ b/plugins/sampling/sampling.go @@ -22,7 +22,7 @@ import ( "sync" "time" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) // FixedRate keeps the given fraction of emissions and drops the rest. diff --git a/plugins/sampling/sampling_test.go b/plugins/sampling/sampling_test.go index 175d231..328899e 100644 --- a/plugins/sampling/sampling_test.go +++ b/plugins/sampling/sampling_test.go @@ -5,9 +5,9 @@ import ( "testing" "time" - "go.loglayer.dev" - "go.loglayer.dev/plugins/plugintest" - "go.loglayer.dev/plugins/sampling" + "go.loglayer.dev/plugins/plugintest/v2" + "go.loglayer.dev/plugins/sampling/v2" + "go.loglayer.dev/v2" ) func TestFixedRate_KeepAll(t *testing.T) { diff --git a/source_test.go b/source_test.go index 7f496aa..db60feb 100644 --- a/source_test.go +++ b/source_test.go @@ -6,8 +6,8 @@ import ( "strings" "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" ) func newSourceLogger(t *testing.T, addSource bool) (*loglayer.LogLayer, *lltest.TestLoggingLibrary) { diff --git a/transport/benchtest/benchtest.go b/transport/benchtest/benchtest.go index 7915817..c9d476b 100644 --- a/transport/benchtest/benchtest.go +++ b/transport/benchtest/benchtest.go @@ -8,7 +8,7 @@ package benchtest import ( "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) // Msg is the standard benchmark message. Use it as the argument to diff --git a/transport/concurrency_test.go b/transport/concurrency_test.go index 87400c0..19ce9b5 100644 --- a/transport/concurrency_test.go +++ b/transport/concurrency_test.go @@ -4,9 +4,9 @@ import ( "sync" "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" + "go.loglayer.dev/v2/transport" ) // TestSetEnabledNoRace exercises the contract that BaseTransport.SetEnabled diff --git a/transport/helpers.go b/transport/helpers.go index fc28277..28dcd2b 100644 --- a/transport/helpers.go +++ b/transport/helpers.go @@ -7,8 +7,8 @@ import ( "os" "strings" - "go.loglayer.dev" - "go.loglayer.dev/utils/maputil" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/utils/maputil" ) // WriterOrStderr returns w if non-nil, otherwise os.Stderr. Used by wrapper diff --git a/transport/helpers_test.go b/transport/helpers_test.go index 79c87a5..6c99b8d 100644 --- a/transport/helpers_test.go +++ b/transport/helpers_test.go @@ -6,8 +6,8 @@ import ( "reflect" "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) func TestWriterOrStderr(t *testing.T) { diff --git a/transport/transport.go b/transport/transport.go index acc3146..efc9fec 100644 --- a/transport/transport.go +++ b/transport/transport.go @@ -5,8 +5,8 @@ package transport import ( "sync/atomic" - "go.loglayer.dev" - "go.loglayer.dev/utils/idgen" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/utils/idgen" ) // BaseTransport provides common fields and level-filtering logic for transports. diff --git a/transport/transporttest/contract.go b/transport/transporttest/contract.go index 861da5d..efb90e3 100644 --- a/transport/transporttest/contract.go +++ b/transport/transporttest/contract.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) // FactoryOpts lets the contract drive a wrapper's Config knobs without diff --git a/transport/transporttest/livetest.go b/transport/transporttest/livetest.go index 7c601cf..d86e37c 100644 --- a/transport/transporttest/livetest.go +++ b/transport/transporttest/livetest.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) // EmitLivetestSurface emits a representative sample of the LogLayer API diff --git a/transport/transporttest/transporttest.go b/transport/transporttest/transporttest.go index c15a823..6429c2d 100644 --- a/transport/transporttest/transporttest.go +++ b/transport/transporttest/transporttest.go @@ -19,7 +19,7 @@ import ( "strings" "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) // NewLogger wraps the supplied transport in a *loglayer.LogLayer with diff --git a/transport_panic_test.go b/transport_panic_test.go index a91ff39..aa699dc 100644 --- a/transport_panic_test.go +++ b/transport_panic_test.go @@ -5,9 +5,9 @@ import ( "sync" "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" + "go.loglayer.dev/v2/transport" ) // panickingTransport panics on every SendToLogger. diff --git a/transports/blank/blank.go b/transports/blank/blank.go index e3ac5d5..e553456 100644 --- a/transports/blank/blank.go +++ b/transports/blank/blank.go @@ -12,8 +12,8 @@ package blank import ( - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration for the blank transport. diff --git a/transports/blank/blank_test.go b/transports/blank/blank_test.go index 9c7529d..b504d0b 100644 --- a/transports/blank/blank_test.go +++ b/transports/blank/blank_test.go @@ -4,9 +4,9 @@ import ( "sync/atomic" "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transports/blank" + "go.loglayer.dev/transports/blank/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) func TestBlank_CallsShipToLogger(t *testing.T) { diff --git a/transports/blank/example_test.go b/transports/blank/example_test.go index 7a72673..3538be5 100644 --- a/transports/blank/example_test.go +++ b/transports/blank/example_test.go @@ -3,8 +3,8 @@ package blank_test import ( "fmt" - "go.loglayer.dev" - "go.loglayer.dev/transports/blank" + "go.loglayer.dev/transports/blank/v2" + "go.loglayer.dev/v2" ) // New wraps a callback. ShipToLogger receives every TransportParams diff --git a/transports/blank/go.mod b/transports/blank/go.mod index 2b750d9..d10e22f 100644 --- a/transports/blank/go.mod +++ b/transports/blank/go.mod @@ -1,9 +1,9 @@ -module go.loglayer.dev/transports/blank +module go.loglayer.dev/transports/blank/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. -require go.loglayer.dev v0.0.0-00010101000000-000000000000 +require go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 require github.com/goccy/go-json v0.10.6 // indirect diff --git a/transports/central/central.go b/transports/central/central.go index 49401c0..04c8867 100644 --- a/transports/central/central.go +++ b/transports/central/central.go @@ -15,8 +15,8 @@ import ( "github.com/goccy/go-json" - "go.loglayer.dev/transport" - httptr "go.loglayer.dev/transports/http" + httptr "go.loglayer.dev/transports/http/v2" + "go.loglayer.dev/v2/transport" ) // DefaultPort is the port the Central server listens on by default. diff --git a/transports/central/central_test.go b/transports/central/central_test.go index 9495e39..98f4449 100644 --- a/transports/central/central_test.go +++ b/transports/central/central_test.go @@ -10,10 +10,10 @@ import ( "testing" "time" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transports/central" - httptr "go.loglayer.dev/transports/http" + "go.loglayer.dev/transports/central/v2" + httptr "go.loglayer.dev/transports/http/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) type capture struct { diff --git a/transports/central/example_test.go b/transports/central/example_test.go index 2d8d092..89081b0 100644 --- a/transports/central/example_test.go +++ b/transports/central/example_test.go @@ -1,8 +1,8 @@ package central_test import ( - "go.loglayer.dev" - "go.loglayer.dev/transports/central" + "go.loglayer.dev/transports/central/v2" + "go.loglayer.dev/v2" ) // New ships log entries to the LogLayer Central server's HTTP intake. diff --git a/transports/central/go.mod b/transports/central/go.mod index 92e5592..f7577de 100644 --- a/transports/central/go.mod +++ b/transports/central/go.mod @@ -1,14 +1,14 @@ -module go.loglayer.dev/transports/central +module go.loglayer.dev/transports/central/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. -replace go.loglayer.dev/transports/http => ../http +replace go.loglayer.dev/transports/http/v2 => ../http require ( github.com/goccy/go-json v0.10.6 - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/http v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/http/v2 v2.0.0-00010101000000-000000000000 go.uber.org/goleak v1.3.0 ) diff --git a/transports/charmlog/bench_test.go b/transports/charmlog/bench_test.go index f524624..1903661 100644 --- a/transports/charmlog/bench_test.go +++ b/transports/charmlog/bench_test.go @@ -5,10 +5,10 @@ import ( clog "github.com/charmbracelet/log" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/benchtest" - llcharm "go.loglayer.dev/transports/charmlog" + llcharm "go.loglayer.dev/transports/charmlog/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/benchtest" ) func newDirect() *clog.Logger { diff --git a/transports/charmlog/charmlog.go b/transports/charmlog/charmlog.go index 4d4b9af..50d81cc 100644 --- a/transports/charmlog/charmlog.go +++ b/transports/charmlog/charmlog.go @@ -8,8 +8,8 @@ import ( clog "github.com/charmbracelet/log" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration options for the charmbracelet/log transport. diff --git a/transports/charmlog/charmlog_test.go b/transports/charmlog/charmlog_test.go index 0afeca9..7013e6b 100644 --- a/transports/charmlog/charmlog_test.go +++ b/transports/charmlog/charmlog_test.go @@ -6,10 +6,10 @@ import ( clog "github.com/charmbracelet/log" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/transporttest" - llcharm "go.loglayer.dev/transports/charmlog" + llcharm "go.loglayer.dev/transports/charmlog/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/transporttest" ) func factory(opts transporttest.FactoryOpts) (*loglayer.LogLayer, *bytes.Buffer) { diff --git a/transports/charmlog/example_test.go b/transports/charmlog/example_test.go index 45cc868..9a2cf6c 100644 --- a/transports/charmlog/example_test.go +++ b/transports/charmlog/example_test.go @@ -3,8 +3,8 @@ package charmlog_test import ( "io" - "go.loglayer.dev" - "go.loglayer.dev/transports/charmlog" + "go.loglayer.dev/transports/charmlog/v2" + "go.loglayer.dev/v2" ) // New wraps a *charmbracelet/log.Logger. When Logger is nil a default diff --git a/transports/charmlog/go.mod b/transports/charmlog/go.mod index 4580428..d4fbf69 100644 --- a/transports/charmlog/go.mod +++ b/transports/charmlog/go.mod @@ -1,12 +1,12 @@ -module go.loglayer.dev/transports/charmlog +module go.loglayer.dev/transports/charmlog/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( github.com/charmbracelet/log v1.0.0 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/transports/cli/cli.go b/transports/cli/cli.go index e309b2d..63cf1b4 100644 --- a/transports/cli/cli.go +++ b/transports/cli/cli.go @@ -53,9 +53,9 @@ import ( "github.com/fatih/color" "github.com/mattn/go-isatty" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/utils/sanitize" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/utils/sanitize" ) // ColorMode controls ANSI color output. @@ -150,10 +150,11 @@ type Config struct { // Transport renders log entries as plain CLI output. type Transport struct { transport.BaseTransport - cfg Config - useANSI bool - prefix map[loglayer.LogLevel]string - colors map[loglayer.LogLevel]*color.Color + cfg Config + useANSI bool + prefix map[loglayer.LogLevel]string + colors map[loglayer.LogLevel]*color.Color + userPrefixColor *color.Color } // New constructs a Transport from cfg. The TTY detection for @@ -161,10 +162,11 @@ type Transport struct { // cfg.Stdout is nil); subsequent writes don't re-check. func New(cfg Config) *Transport { t := &Transport{ - BaseTransport: transport.NewBaseTransport(cfg.BaseConfig), - cfg: cfg, - prefix: defaultPrefixes(), - colors: defaultColors(), + BaseTransport: transport.NewBaseTransport(cfg.BaseConfig), + cfg: cfg, + prefix: defaultPrefixes(), + colors: defaultColors(), + userPrefixColor: color.New(color.FgHiBlack), } maps.Copy(t.prefix, cfg.LevelPrefix) // Sanitize user-supplied prefixes once at construction so a @@ -199,6 +201,16 @@ func New(cfg Config) *Transport { } t.colors[level] = &cp } + // Same shallow-copy + per-instance flag dance for the user- + // prefix color so a transport with ColorAlways doesn't share + // the global NoColor with another transport. + upc := *t.userPrefixColor + if t.useANSI { + upc.EnableColor() + } else { + upc.DisableColor() + } + t.userPrefixColor = &upc return t } @@ -222,41 +234,64 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { fmt.Fprintln(t.writer(params.LogLevel), body) } -// format builds the line(s) to print: optional level prefix + -// sanitized message + (table OR optional logfmt fields). Color is -// applied to the headline (prefix + message + logfmt) only; a table -// body, when present, renders neutral so its rows aren't tinted by -// the level color. +// format builds the line(s) to print: +// +// [level prefix][user prefix from WithPrefix][message] [logfmt fields] +// [table body, if metadata is slice-of-map] +// +// Color: the level prefix and message share the level color +// (yellow / red / etc.). The user prefix gets its own dim-grey +// color so it reads as caller-context rather than urgency. Tables +// render neutral. func (t *Transport) format(params loglayer.TransportParams) string { msg := transport.JoinMessages(sanitizeMessages(params.Messages)) - var head strings.Builder + levelPrefix := "" if !t.cfg.DisableLevelPrefix { - if p := t.prefix[params.LogLevel]; p != "" { - head.WriteString(p) - } + levelPrefix = t.prefix[params.LogLevel] } - head.WriteString(msg) + userPrefix := "" + if params.Prefix != "" { + userPrefix = params.Prefix + " " + } + + // Append optional logfmt or capture a table. + body := msg var table string switch { case isTableMetadata(params.Metadata): table = renderTable(asTableRows(params.Metadata)) case t.cfg.ShowFields: if fields := renderLogfmt(transport.MergeFieldsAndMetadata(params)); fields != "" { - if head.Len() > 0 { - head.WriteByte(' ') + if body != "" { + body = body + " " + fields + } else { + body = fields } - head.WriteString(fields) } } - headline := head.String() + // Compose the headline. Level color tints the level prefix and + // the message body together; the user prefix gets dim-grey. + var levelPart, userPart, bodyPart string if t.useANSI { if c, ok := t.colors[params.LogLevel]; ok && c != nil { - headline = c.Sprint(headline) + levelPart = c.Sprint(levelPrefix) + bodyPart = c.Sprint(body) + } else { + levelPart = levelPrefix + bodyPart = body + } + if userPrefix != "" { + userPart = t.userPrefixColor.Sprint(userPrefix) } + } else { + levelPart = levelPrefix + userPart = userPrefix + bodyPart = body } + headline := levelPart + userPart + bodyPart switch { case table == "": diff --git a/transports/cli/cli_test.go b/transports/cli/cli_test.go index 6f58edd..f800c48 100644 --- a/transports/cli/cli_test.go +++ b/transports/cli/cli_test.go @@ -7,8 +7,8 @@ import ( "github.com/fatih/color" - "go.loglayer.dev" - clitr "go.loglayer.dev/transports/cli" + clitr "go.loglayer.dev/transports/cli/v2" + "go.loglayer.dev/v2" ) // makeLogger constructs a logger backed by a cli.Transport whose diff --git a/transports/cli/example_test.go b/transports/cli/example_test.go index 70ba717..3d9ebb9 100644 --- a/transports/cli/example_test.go +++ b/transports/cli/example_test.go @@ -5,8 +5,8 @@ import ( "github.com/fatih/color" - "go.loglayer.dev" - clitr "go.loglayer.dev/transports/cli" + clitr "go.loglayer.dev/transports/cli/v2" + "go.loglayer.dev/v2" ) // The package-level Example shows the canonical wiring: a CLI app's diff --git a/transports/cli/go.mod b/transports/cli/go.mod index 27b133d..f51410b 100644 --- a/transports/cli/go.mod +++ b/transports/cli/go.mod @@ -1,13 +1,13 @@ -module go.loglayer.dev/transports/cli +module go.loglayer.dev/transports/cli/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( github.com/fatih/color v1.19.0 github.com/mattn/go-isatty v0.0.20 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/transports/console/bench_test.go b/transports/console/bench_test.go index f658ae2..b39f1ad 100644 --- a/transports/console/bench_test.go +++ b/transports/console/bench_test.go @@ -7,10 +7,10 @@ package console_test import ( "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/benchtest" - "go.loglayer.dev/transports/console" + "go.loglayer.dev/transports/console/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/benchtest" ) func BenchmarkRender_Console_SimpleMessage(b *testing.B) { diff --git a/transports/console/console.go b/transports/console/console.go index c396209..c4663de 100644 --- a/transports/console/console.go +++ b/transports/console/console.go @@ -15,9 +15,9 @@ import ( "github.com/goccy/go-json" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/utils/sanitize" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/utils/sanitize" ) // Config holds configuration options for Transport. diff --git a/transports/console/console_test.go b/transports/console/console_test.go index 37705a5..1651b83 100644 --- a/transports/console/console_test.go +++ b/transports/console/console_test.go @@ -5,9 +5,9 @@ import ( "strings" "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transports/console" + "go.loglayer.dev/transports/console/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) func newLogger(cfg console.Config) (*loglayer.LogLayer, *bytes.Buffer) { diff --git a/transports/console/example_test.go b/transports/console/example_test.go index 7cab088..a642282 100644 --- a/transports/console/example_test.go +++ b/transports/console/example_test.go @@ -3,8 +3,8 @@ package console_test import ( "os" - "go.loglayer.dev" - "go.loglayer.dev/transports/console" + "go.loglayer.dev/transports/console/v2" + "go.loglayer.dev/v2" ) // New builds a logfmt-style console transport. DateFn returns a fixed diff --git a/transports/console/go.mod b/transports/console/go.mod index 6671e7a..cb6fd80 100644 --- a/transports/console/go.mod +++ b/transports/console/go.mod @@ -1,10 +1,10 @@ -module go.loglayer.dev/transports/console +module go.loglayer.dev/transports/console/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( github.com/goccy/go-json v0.10.6 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) diff --git a/transports/console/routing_test.go b/transports/console/routing_test.go index e7342e7..8b2124a 100644 --- a/transports/console/routing_test.go +++ b/transports/console/routing_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) func TestWriterRouting(t *testing.T) { diff --git a/transports/datadog/datadog.go b/transports/datadog/datadog.go index ef2c6e6..6c42271 100644 --- a/transports/datadog/datadog.go +++ b/transports/datadog/datadog.go @@ -19,9 +19,9 @@ import ( "github.com/goccy/go-json" - "go.loglayer.dev" - "go.loglayer.dev/transport" - httptr "go.loglayer.dev/transports/http" + httptr "go.loglayer.dev/transports/http/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Site identifies the Datadog region. Affects only the intake URL. diff --git a/transports/datadog/datadog_test.go b/transports/datadog/datadog_test.go index b9982dc..40ec49c 100644 --- a/transports/datadog/datadog_test.go +++ b/transports/datadog/datadog_test.go @@ -13,10 +13,10 @@ import ( "testing" "time" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transports/datadog" - httptr "go.loglayer.dev/transports/http" + "go.loglayer.dev/transports/datadog/v2" + httptr "go.loglayer.dev/transports/http/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) type capture struct { diff --git a/transports/datadog/example_test.go b/transports/datadog/example_test.go index 50d775b..2bb7ca7 100644 --- a/transports/datadog/example_test.go +++ b/transports/datadog/example_test.go @@ -1,8 +1,8 @@ package datadog_test import ( - "go.loglayer.dev" - "go.loglayer.dev/transports/datadog" + "go.loglayer.dev/transports/datadog/v2" + "go.loglayer.dev/v2" ) // New ships log entries to the Datadog Logs HTTP intake. APIKey is diff --git a/transports/datadog/go.mod b/transports/datadog/go.mod index b1e225a..1d9c2e5 100644 --- a/transports/datadog/go.mod +++ b/transports/datadog/go.mod @@ -1,14 +1,14 @@ -module go.loglayer.dev/transports/datadog +module go.loglayer.dev/transports/datadog/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. -replace go.loglayer.dev/transports/http => ../http +replace go.loglayer.dev/transports/http/v2 => ../http require ( github.com/goccy/go-json v0.10.6 - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/http v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/http/v2 v2.0.0-00010101000000-000000000000 go.uber.org/goleak v1.3.0 ) diff --git a/transports/datadog/livetest_test.go b/transports/datadog/livetest_test.go index 6ca81eb..bf221f9 100644 --- a/transports/datadog/livetest_test.go +++ b/transports/datadog/livetest_test.go @@ -31,10 +31,10 @@ import ( "testing" "time" - "go.loglayer.dev/transport/transporttest" - "go.loglayer.dev/transports/datadog" - httptr "go.loglayer.dev/transports/http" - "go.loglayer.dev/utils/idgen" + "go.loglayer.dev/transports/datadog/v2" + httptr "go.loglayer.dev/transports/http/v2" + "go.loglayer.dev/v2/transport/transporttest" + "go.loglayer.dev/v2/utils/idgen" ) func TestLive_Datadog_SendsLog(t *testing.T) { diff --git a/transports/gcplogging/example_test.go b/transports/gcplogging/example_test.go index 4ebe6d0..7034d5f 100644 --- a/transports/gcplogging/example_test.go +++ b/transports/gcplogging/example_test.go @@ -3,8 +3,8 @@ package gcplogging_test import ( "cloud.google.com/go/logging" - "go.loglayer.dev" - "go.loglayer.dev/transports/gcplogging" + "go.loglayer.dev/transports/gcplogging/v2" + "go.loglayer.dev/v2" ) // New forwards entries to a caller-supplied *logging.Logger from diff --git a/transports/gcplogging/gcplogging.go b/transports/gcplogging/gcplogging.go index 8aa11fc..cec1c80 100644 --- a/transports/gcplogging/gcplogging.go +++ b/transports/gcplogging/gcplogging.go @@ -43,8 +43,8 @@ import ( "cloud.google.com/go/logging" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration options for the GCP Cloud Logging transport. diff --git a/transports/gcplogging/gcplogging_test.go b/transports/gcplogging/gcplogging_test.go index 35977fb..665a3f0 100644 --- a/transports/gcplogging/gcplogging_test.go +++ b/transports/gcplogging/gcplogging_test.go @@ -7,7 +7,7 @@ import ( "cloud.google.com/go/logging" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) func TestSeverityFor(t *testing.T) { diff --git a/transports/gcplogging/go.mod b/transports/gcplogging/go.mod index bb26e04..bbf8370 100644 --- a/transports/gcplogging/go.mod +++ b/transports/gcplogging/go.mod @@ -1,12 +1,12 @@ -module go.loglayer.dev/transports/gcplogging +module go.loglayer.dev/transports/gcplogging/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( cloud.google.com/go/logging v1.13.0 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/transports/gcplogging/livetest_test.go b/transports/gcplogging/livetest_test.go index 7b0411d..5e713b1 100644 --- a/transports/gcplogging/livetest_test.go +++ b/transports/gcplogging/livetest_test.go @@ -28,9 +28,9 @@ import ( "cloud.google.com/go/logging" - "go.loglayer.dev/transport/transporttest" - "go.loglayer.dev/transports/gcplogging" - "go.loglayer.dev/utils/idgen" + "go.loglayer.dev/transports/gcplogging/v2" + "go.loglayer.dev/v2/transport/transporttest" + "go.loglayer.dev/v2/utils/idgen" ) func TestLive_GCPLogging_SendsLog(t *testing.T) { diff --git a/transports/http/example_test.go b/transports/http/example_test.go index 9ca0d3a..a46be9f 100644 --- a/transports/http/example_test.go +++ b/transports/http/example_test.go @@ -1,8 +1,8 @@ package httptransport_test import ( - "go.loglayer.dev" - httptransport "go.loglayer.dev/transports/http" + httptransport "go.loglayer.dev/transports/http/v2" + "go.loglayer.dev/v2" ) // New POSTs JSON batches to URL. The worker goroutine starts at diff --git a/transports/http/go.mod b/transports/http/go.mod index c6cbff4..69fa0d7 100644 --- a/transports/http/go.mod +++ b/transports/http/go.mod @@ -1,11 +1,11 @@ -module go.loglayer.dev/transports/http +module go.loglayer.dev/transports/http/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( github.com/goccy/go-json v0.10.6 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.uber.org/goleak v1.3.0 ) diff --git a/transports/http/http.go b/transports/http/http.go index b4fece7..7b63939 100644 --- a/transports/http/http.go +++ b/transports/http/http.go @@ -22,8 +22,8 @@ import ( "github.com/goccy/go-json" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) const ( diff --git a/transports/http/http_test.go b/transports/http/http_test.go index f63fc77..62ae628 100644 --- a/transports/http/http_test.go +++ b/transports/http/http_test.go @@ -13,9 +13,9 @@ import ( "testing" "time" - "go.loglayer.dev" - "go.loglayer.dev/transport" - httptr "go.loglayer.dev/transports/http" + httptr "go.loglayer.dev/transports/http/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // captureServer accumulates request bodies for assertion. It supports an diff --git a/transports/logrus/bench_test.go b/transports/logrus/bench_test.go index 64b8587..835dc38 100644 --- a/transports/logrus/bench_test.go +++ b/transports/logrus/bench_test.go @@ -5,10 +5,10 @@ import ( logrusbase "github.com/sirupsen/logrus" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/benchtest" - lllogrus "go.loglayer.dev/transports/logrus" + lllogrus "go.loglayer.dev/transports/logrus/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/benchtest" ) func newDirect() *logrusbase.Logger { diff --git a/transports/logrus/example_test.go b/transports/logrus/example_test.go index 224c505..7be2ac4 100644 --- a/transports/logrus/example_test.go +++ b/transports/logrus/example_test.go @@ -3,8 +3,8 @@ package logrus_test import ( "io" - "go.loglayer.dev" - "go.loglayer.dev/transports/logrus" + "go.loglayer.dev/transports/logrus/v2" + "go.loglayer.dev/v2" ) // New wraps a *logrus.Logger. When Logger is nil a default logger is diff --git a/transports/logrus/go.mod b/transports/logrus/go.mod index a650a24..8611d7d 100644 --- a/transports/logrus/go.mod +++ b/transports/logrus/go.mod @@ -1,12 +1,12 @@ -module go.loglayer.dev/transports/logrus +module go.loglayer.dev/transports/logrus/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( github.com/sirupsen/logrus v1.9.4 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/transports/logrus/logrus.go b/transports/logrus/logrus.go index d335fa7..f30e2c9 100644 --- a/transports/logrus/logrus.go +++ b/transports/logrus/logrus.go @@ -9,8 +9,8 @@ import ( "github.com/sirupsen/logrus" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration options for the logrus transport. diff --git a/transports/logrus/logrus_test.go b/transports/logrus/logrus_test.go index 5f6587a..ab83c2d 100644 --- a/transports/logrus/logrus_test.go +++ b/transports/logrus/logrus_test.go @@ -6,10 +6,10 @@ import ( logrusbase "github.com/sirupsen/logrus" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/transporttest" - lllogrus "go.loglayer.dev/transports/logrus" + lllogrus "go.loglayer.dev/transports/logrus/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/transporttest" ) func factory(opts transporttest.FactoryOpts) (*loglayer.LogLayer, *bytes.Buffer) { diff --git a/transports/lumberjack/example_test.go b/transports/lumberjack/example_test.go index 58d998f..2309b95 100644 --- a/transports/lumberjack/example_test.go +++ b/transports/lumberjack/example_test.go @@ -1,8 +1,8 @@ package lumberjack_test import ( - "go.loglayer.dev" - "go.loglayer.dev/transports/lumberjack" + "go.loglayer.dev/transports/lumberjack/v2" + "go.loglayer.dev/v2" ) // New writes one JSON object per entry to a rotating file. Filename is diff --git a/transports/lumberjack/go.mod b/transports/lumberjack/go.mod index 1adfe46..8ae42d6 100644 --- a/transports/lumberjack/go.mod +++ b/transports/lumberjack/go.mod @@ -1,14 +1,14 @@ -module go.loglayer.dev/transports/lumberjack +module go.loglayer.dev/transports/lumberjack/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. -replace go.loglayer.dev/transports/structured => ../structured +replace go.loglayer.dev/transports/structured/v2 => ../structured require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 - go.loglayer.dev/transports/structured v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/transports/structured/v2 v2.0.0-00010101000000-000000000000 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) diff --git a/transports/lumberjack/lumberjack.go b/transports/lumberjack/lumberjack.go index 991aa70..848c7f8 100644 --- a/transports/lumberjack/lumberjack.go +++ b/transports/lumberjack/lumberjack.go @@ -23,9 +23,9 @@ import ( lj "gopkg.in/natefinch/lumberjack.v2" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transports/structured" + "go.loglayer.dev/transports/structured/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration options for Transport. diff --git a/transports/lumberjack/lumberjack_test.go b/transports/lumberjack/lumberjack_test.go index baa0082..a0995b0 100644 --- a/transports/lumberjack/lumberjack_test.go +++ b/transports/lumberjack/lumberjack_test.go @@ -10,10 +10,10 @@ import ( "sync/atomic" "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/transporttest" - "go.loglayer.dev/transports/lumberjack" + "go.loglayer.dev/transports/lumberjack/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/transporttest" ) // readFileBuffer reads path into a *bytes.Buffer so we can reuse the diff --git a/transports/otellog/example_test.go b/transports/otellog/example_test.go index e403b5b..b84eb7f 100644 --- a/transports/otellog/example_test.go +++ b/transports/otellog/example_test.go @@ -1,8 +1,8 @@ package otellog_test import ( - "go.loglayer.dev" - "go.loglayer.dev/transports/otellog" + "go.loglayer.dev/transports/otellog/v2" + "go.loglayer.dev/v2" ) // New emits log entries to an OpenTelemetry log.Logger. Name is the diff --git a/transports/otellog/go.mod b/transports/otellog/go.mod index d2fbe54..83994ff 100644 --- a/transports/otellog/go.mod +++ b/transports/otellog/go.mod @@ -1,11 +1,11 @@ -module go.loglayer.dev/transports/otellog +module go.loglayer.dev/transports/otellog/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.opentelemetry.io/otel/log v0.19.0 go.opentelemetry.io/otel/log/logtest v0.19.0 go.opentelemetry.io/otel/sdk v1.43.0 diff --git a/transports/otellog/livetest_test.go b/transports/otellog/livetest_test.go index 1e95497..23d3048 100644 --- a/transports/otellog/livetest_test.go +++ b/transports/otellog/livetest_test.go @@ -18,8 +18,8 @@ import ( "sync" "testing" - "go.loglayer.dev" - "go.loglayer.dev/transports/otellog" + "go.loglayer.dev/transports/otellog/v2" + "go.loglayer.dev/v2" otelapi "go.opentelemetry.io/otel/log" sdklog "go.opentelemetry.io/otel/sdk/log" sdktrace "go.opentelemetry.io/otel/sdk/trace" diff --git a/transports/otellog/otellog.go b/transports/otellog/otellog.go index 18b463c..0a6ea7f 100644 --- a/transports/otellog/otellog.go +++ b/transports/otellog/otellog.go @@ -15,8 +15,8 @@ // Wiring with the global LoggerProvider (most common): // // import ( -// "go.loglayer.dev" -// "go.loglayer.dev/transports/otellog" +// "go.loglayer.dev/v2" +// "go.loglayer.dev/transports/otellog/v2" // ) // // tr := otellog.New(otellog.Config{Name: "checkout-api"}) @@ -44,8 +44,8 @@ import ( "fmt" "time" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" otellog "go.opentelemetry.io/otel/log" "go.opentelemetry.io/otel/log/global" ) diff --git a/transports/otellog/otellog_test.go b/transports/otellog/otellog_test.go index 353ea6b..d54f495 100644 --- a/transports/otellog/otellog_test.go +++ b/transports/otellog/otellog_test.go @@ -5,9 +5,9 @@ import ( "errors" "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transports/otellog" + "go.loglayer.dev/transports/otellog/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" otelapi "go.opentelemetry.io/otel/log" "go.opentelemetry.io/otel/log/logtest" ) diff --git a/transports/phuslu/bench_test.go b/transports/phuslu/bench_test.go index 390d5f7..5f56874 100644 --- a/transports/phuslu/bench_test.go +++ b/transports/phuslu/bench_test.go @@ -5,10 +5,10 @@ import ( plog "github.com/phuslu/log" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/benchtest" - llphuslu "go.loglayer.dev/transports/phuslu" + llphuslu "go.loglayer.dev/transports/phuslu/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/benchtest" ) func newDirect() *plog.Logger { diff --git a/transports/phuslu/example_test.go b/transports/phuslu/example_test.go index e4fa126..4a8626d 100644 --- a/transports/phuslu/example_test.go +++ b/transports/phuslu/example_test.go @@ -3,8 +3,8 @@ package phuslu_test import ( "io" - "go.loglayer.dev" - "go.loglayer.dev/transports/phuslu" + "go.loglayer.dev/transports/phuslu/v2" + "go.loglayer.dev/v2" ) // New wraps a *phuslu/log.Logger. When Logger is nil a default logger diff --git a/transports/phuslu/go.mod b/transports/phuslu/go.mod index 4257ca5..98059bd 100644 --- a/transports/phuslu/go.mod +++ b/transports/phuslu/go.mod @@ -1,12 +1,12 @@ -module go.loglayer.dev/transports/phuslu +module go.loglayer.dev/transports/phuslu/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( github.com/phuslu/log v1.0.124 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/transports/phuslu/phuslu.go b/transports/phuslu/phuslu.go index 3ce195c..724472c 100644 --- a/transports/phuslu/phuslu.go +++ b/transports/phuslu/phuslu.go @@ -8,8 +8,8 @@ import ( plog "github.com/phuslu/log" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration options for the phuslu transport. diff --git a/transports/phuslu/phuslu_test.go b/transports/phuslu/phuslu_test.go index 76ef6a8..d6d7bcf 100644 --- a/transports/phuslu/phuslu_test.go +++ b/transports/phuslu/phuslu_test.go @@ -6,10 +6,10 @@ import ( plog "github.com/phuslu/log" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/transporttest" - llphuslu "go.loglayer.dev/transports/phuslu" + llphuslu "go.loglayer.dev/transports/phuslu/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/transporttest" ) func factory(opts transporttest.FactoryOpts) (*loglayer.LogLayer, *bytes.Buffer) { diff --git a/transports/pretty/bench_test.go b/transports/pretty/bench_test.go index 6566aad..8605e08 100644 --- a/transports/pretty/bench_test.go +++ b/transports/pretty/bench_test.go @@ -3,10 +3,10 @@ package pretty_test import ( "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/benchtest" - "go.loglayer.dev/transports/pretty" + "go.loglayer.dev/transports/pretty/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/benchtest" ) func newPrettyLogger() *loglayer.LogLayer { diff --git a/transports/pretty/example_test.go b/transports/pretty/example_test.go index 2afd0fd..fa68cfd 100644 --- a/transports/pretty/example_test.go +++ b/transports/pretty/example_test.go @@ -4,8 +4,8 @@ import ( "os" "time" - "go.loglayer.dev" - "go.loglayer.dev/transports/pretty" + "go.loglayer.dev/transports/pretty/v2" + "go.loglayer.dev/v2" ) // New builds the colorized terminal transport. NoColor and a fixed diff --git a/transports/pretty/go.mod b/transports/pretty/go.mod index 12c5246..8a83981 100644 --- a/transports/pretty/go.mod +++ b/transports/pretty/go.mod @@ -1,13 +1,13 @@ -module go.loglayer.dev/transports/pretty +module go.loglayer.dev/transports/pretty/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( github.com/fatih/color v1.19.0 github.com/goccy/go-json v0.10.6 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/transports/pretty/pretty.go b/transports/pretty/pretty.go index c35447c..5ab7d9a 100644 --- a/transports/pretty/pretty.go +++ b/transports/pretty/pretty.go @@ -11,9 +11,9 @@ import ( "strings" "time" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/utils/sanitize" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/utils/sanitize" ) // ViewMode controls how each log entry is rendered. diff --git a/transports/pretty/pretty_test.go b/transports/pretty/pretty_test.go index e920652..00d50da 100644 --- a/transports/pretty/pretty_test.go +++ b/transports/pretty/pretty_test.go @@ -9,9 +9,9 @@ import ( "github.com/fatih/color" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transports/pretty" + "go.loglayer.dev/transports/pretty/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) const fixedTime = "12:34:56.789" diff --git a/transports/pretty/render.go b/transports/pretty/render.go index 5140ae9..c920624 100644 --- a/transports/pretty/render.go +++ b/transports/pretty/render.go @@ -9,7 +9,7 @@ import ( "github.com/goccy/go-json" - "go.loglayer.dev" + "go.loglayer.dev/v2" ) // combineData merges Data (fields + error) and Metadata into a single map for diff --git a/transports/sentry/example_test.go b/transports/sentry/example_test.go index d87d6d3..3fc9047 100644 --- a/transports/sentry/example_test.go +++ b/transports/sentry/example_test.go @@ -5,8 +5,8 @@ import ( "github.com/getsentry/sentry-go" - "go.loglayer.dev" - sentrytransport "go.loglayer.dev/transports/sentry" + sentrytransport "go.loglayer.dev/transports/sentry/v2" + "go.loglayer.dev/v2" ) // New forwards entries to a caller-supplied sentry.Logger. The Logger diff --git a/transports/sentry/go.mod b/transports/sentry/go.mod index a596f6e..bd27897 100644 --- a/transports/sentry/go.mod +++ b/transports/sentry/go.mod @@ -1,13 +1,13 @@ -module go.loglayer.dev/transports/sentry +module go.loglayer.dev/transports/sentry/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( github.com/getsentry/sentry-go v0.46.1 github.com/goccy/go-json v0.10.6 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/transports/sentry/livetest_test.go b/transports/sentry/livetest_test.go index a2056cb..6bc04d7 100644 --- a/transports/sentry/livetest_test.go +++ b/transports/sentry/livetest_test.go @@ -26,9 +26,9 @@ import ( "github.com/getsentry/sentry-go" - "go.loglayer.dev/transport/transporttest" - sentrytransport "go.loglayer.dev/transports/sentry" - "go.loglayer.dev/utils/idgen" + sentrytransport "go.loglayer.dev/transports/sentry/v2" + "go.loglayer.dev/v2/transport/transporttest" + "go.loglayer.dev/v2/utils/idgen" ) func TestLive_Sentry_SendsLog(t *testing.T) { diff --git a/transports/sentry/sentry.go b/transports/sentry/sentry.go index 7f22357..63c8fbc 100644 --- a/transports/sentry/sentry.go +++ b/transports/sentry/sentry.go @@ -21,8 +21,8 @@ import ( "github.com/getsentry/sentry-go" "github.com/goccy/go-json" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration options for the Sentry transport. diff --git a/transports/sentry/sentry_test.go b/transports/sentry/sentry_test.go index c824f61..627f492 100644 --- a/transports/sentry/sentry_test.go +++ b/transports/sentry/sentry_test.go @@ -9,9 +9,9 @@ import ( "github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go/attribute" - "go.loglayer.dev" - "go.loglayer.dev/transport" - sentrytransport "go.loglayer.dev/transports/sentry" + sentrytransport "go.loglayer.dev/transports/sentry/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // fakeLogger satisfies sentry.Logger and records every entry built diff --git a/transports/slog/example_test.go b/transports/slog/example_test.go index 14339da..14a0a1f 100644 --- a/transports/slog/example_test.go +++ b/transports/slog/example_test.go @@ -3,8 +3,8 @@ package slog_test import ( "io" - "go.loglayer.dev" - llslog "go.loglayer.dev/transports/slog" + llslog "go.loglayer.dev/transports/slog/v2" + "go.loglayer.dev/v2" ) // New wraps a *slog.Logger. When Logger is nil a default logger is diff --git a/transports/slog/go.mod b/transports/slog/go.mod index 91ad6eb..c64cce4 100644 --- a/transports/slog/go.mod +++ b/transports/slog/go.mod @@ -1,9 +1,9 @@ -module go.loglayer.dev/transports/slog +module go.loglayer.dev/transports/slog/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. -require go.loglayer.dev v0.0.0-00010101000000-000000000000 +require go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 require github.com/goccy/go-json v0.10.6 // indirect diff --git a/transports/slog/slog.go b/transports/slog/slog.go index d363173..91e6a87 100644 --- a/transports/slog/slog.go +++ b/transports/slog/slog.go @@ -13,8 +13,8 @@ import ( "io" "log/slog" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration options for the slog transport. diff --git a/transports/slog/slog_test.go b/transports/slog/slog_test.go index 058708a..50b3802 100644 --- a/transports/slog/slog_test.go +++ b/transports/slog/slog_test.go @@ -6,10 +6,10 @@ import ( stdlibslog "log/slog" "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/transporttest" - llslog "go.loglayer.dev/transports/slog" + llslog "go.loglayer.dev/transports/slog/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/transporttest" ) func factory(opts transporttest.FactoryOpts) (*loglayer.LogLayer, *bytes.Buffer) { diff --git a/transports/structured/bench_test.go b/transports/structured/bench_test.go index 2add6fe..f7da3bb 100644 --- a/transports/structured/bench_test.go +++ b/transports/structured/bench_test.go @@ -7,10 +7,10 @@ package structured_test import ( "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/benchtest" - "go.loglayer.dev/transports/structured" + "go.loglayer.dev/transports/structured/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/benchtest" ) func BenchmarkRender_Structured_SimpleMessage(b *testing.B) { diff --git a/transports/structured/example_test.go b/transports/structured/example_test.go index 9d536fd..02b37c6 100644 --- a/transports/structured/example_test.go +++ b/transports/structured/example_test.go @@ -1,8 +1,8 @@ package structured_test import ( - "go.loglayer.dev" - "go.loglayer.dev/transports/structured" + "go.loglayer.dev/transports/structured/v2" + "go.loglayer.dev/v2" ) // New builds a structured-JSON transport. DateFn returns a fixed diff --git a/transports/structured/go.mod b/transports/structured/go.mod index 1816e05..7f5ffe3 100644 --- a/transports/structured/go.mod +++ b/transports/structured/go.mod @@ -1,10 +1,10 @@ -module go.loglayer.dev/transports/structured +module go.loglayer.dev/transports/structured/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( github.com/goccy/go-json v0.10.6 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) diff --git a/transports/structured/structured.go b/transports/structured/structured.go index cfc6e36..72d9d48 100644 --- a/transports/structured/structured.go +++ b/transports/structured/structured.go @@ -12,8 +12,8 @@ import ( "github.com/goccy/go-json" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration options for Transport. diff --git a/transports/structured/structured_test.go b/transports/structured/structured_test.go index f8f0b50..8a56f04 100644 --- a/transports/structured/structured_test.go +++ b/transports/structured/structured_test.go @@ -6,10 +6,10 @@ import ( "strings" "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/transporttest" - "go.loglayer.dev/transports/structured" + "go.loglayer.dev/transports/structured/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/transporttest" ) func newLogger(cfg structured.Config) (*loglayer.LogLayer, *bytes.Buffer) { diff --git a/transports/testing/bench_test.go b/transports/testing/bench_test.go index 0258001..4647496 100644 --- a/transports/testing/bench_test.go +++ b/transports/testing/bench_test.go @@ -7,10 +7,10 @@ package testing_test import ( "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/benchtest" - lltest "go.loglayer.dev/transports/testing" + lltest "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/benchtest" ) func BenchmarkRender_Testing_SimpleMessage(b *testing.B) { diff --git a/transports/testing/example_test.go b/transports/testing/example_test.go index aa5eb4a..779987e 100644 --- a/transports/testing/example_test.go +++ b/transports/testing/example_test.go @@ -3,8 +3,8 @@ package testing_test import ( "fmt" - "go.loglayer.dev" - lltesting "go.loglayer.dev/transports/testing" + lltesting "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" ) // New builds an in-memory capture transport. Tests drive the logger, diff --git a/transports/testing/go.mod b/transports/testing/go.mod index b56e7df..950092e 100644 --- a/transports/testing/go.mod +++ b/transports/testing/go.mod @@ -1,9 +1,9 @@ -module go.loglayer.dev/transports/testing +module go.loglayer.dev/transports/testing/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. -require go.loglayer.dev v0.0.0-00010101000000-000000000000 +require go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 require github.com/goccy/go-json v0.10.6 // indirect diff --git a/transports/testing/testing.go b/transports/testing/testing.go index 177fe33..287a1a3 100644 --- a/transports/testing/testing.go +++ b/transports/testing/testing.go @@ -8,8 +8,8 @@ import ( "context" "sync" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // LogLine is a single captured log entry. Fields are exposed directly so tests diff --git a/transports/testing/testing_test.go b/transports/testing/testing_test.go index 9b1c1d7..0045de8 100644 --- a/transports/testing/testing_test.go +++ b/transports/testing/testing_test.go @@ -3,9 +3,9 @@ package testing_test import ( "testing" - "go.loglayer.dev" - "go.loglayer.dev/transport" - lltest "go.loglayer.dev/transports/testing" + lltest "go.loglayer.dev/transports/testing/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) func newLogger() (*loglayer.LogLayer, *lltest.TestLoggingLibrary) { diff --git a/transports/zap/bench_test.go b/transports/zap/bench_test.go index e5fe63a..307c43c 100644 --- a/transports/zap/bench_test.go +++ b/transports/zap/bench_test.go @@ -6,10 +6,10 @@ import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/benchtest" - llzap "go.loglayer.dev/transports/zap" + llzap "go.loglayer.dev/transports/zap/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/benchtest" ) func newDirect() *zap.Logger { diff --git a/transports/zap/example_test.go b/transports/zap/example_test.go index 0cc0df6..2b6648c 100644 --- a/transports/zap/example_test.go +++ b/transports/zap/example_test.go @@ -3,8 +3,8 @@ package zap_test import ( "io" - "go.loglayer.dev" - "go.loglayer.dev/transports/zap" + "go.loglayer.dev/transports/zap/v2" + "go.loglayer.dev/v2" ) // New wraps a *zap.Logger. When Logger is nil a default logger is diff --git a/transports/zap/go.mod b/transports/zap/go.mod index 2b96ccb..a5c625d 100644 --- a/transports/zap/go.mod +++ b/transports/zap/go.mod @@ -1,11 +1,11 @@ -module go.loglayer.dev/transports/zap +module go.loglayer.dev/transports/zap/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.uber.org/zap v1.27.1 ) diff --git a/transports/zap/zap.go b/transports/zap/zap.go index c09876e..a99b0c3 100644 --- a/transports/zap/zap.go +++ b/transports/zap/zap.go @@ -9,8 +9,8 @@ import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration options for the zap transport. diff --git a/transports/zap/zap_test.go b/transports/zap/zap_test.go index 86f72be..8bab565 100644 --- a/transports/zap/zap_test.go +++ b/transports/zap/zap_test.go @@ -7,10 +7,10 @@ import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/transporttest" - llzap "go.loglayer.dev/transports/zap" + llzap "go.loglayer.dev/transports/zap/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/transporttest" ) func factory(opts transporttest.FactoryOpts) (*loglayer.LogLayer, *bytes.Buffer) { diff --git a/transports/zerolog/bench_test.go b/transports/zerolog/bench_test.go index 28bf181..77aad76 100644 --- a/transports/zerolog/bench_test.go +++ b/transports/zerolog/bench_test.go @@ -5,10 +5,10 @@ import ( zlog "github.com/rs/zerolog" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/benchtest" - llzero "go.loglayer.dev/transports/zerolog" + llzero "go.loglayer.dev/transports/zerolog/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/benchtest" ) func newWrapped() *loglayer.LogLayer { diff --git a/transports/zerolog/example_test.go b/transports/zerolog/example_test.go index 1b732d6..d6cd794 100644 --- a/transports/zerolog/example_test.go +++ b/transports/zerolog/example_test.go @@ -3,8 +3,8 @@ package zerolog_test import ( "io" - "go.loglayer.dev" - "go.loglayer.dev/transports/zerolog" + "go.loglayer.dev/transports/zerolog/v2" + "go.loglayer.dev/v2" ) // New wraps a *zerolog.Logger. When Logger is nil a default logger is diff --git a/transports/zerolog/go.mod b/transports/zerolog/go.mod index dda821a..a925deb 100644 --- a/transports/zerolog/go.mod +++ b/transports/zerolog/go.mod @@ -1,12 +1,12 @@ -module go.loglayer.dev/transports/zerolog +module go.loglayer.dev/transports/zerolog/v2 go 1.25.0 -replace go.loglayer.dev => ../.. +replace go.loglayer.dev/v2 => ../.. require ( github.com/rs/zerolog v1.35.1 - go.loglayer.dev v0.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/transports/zerolog/zerolog.go b/transports/zerolog/zerolog.go index a1adba9..bd4d527 100644 --- a/transports/zerolog/zerolog.go +++ b/transports/zerolog/zerolog.go @@ -14,8 +14,8 @@ import ( zlog "github.com/rs/zerolog" - "go.loglayer.dev" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" ) // Config holds configuration options for the zerolog transport. diff --git a/transports/zerolog/zerolog_test.go b/transports/zerolog/zerolog_test.go index 62eef62..1a1d130 100644 --- a/transports/zerolog/zerolog_test.go +++ b/transports/zerolog/zerolog_test.go @@ -6,10 +6,10 @@ import ( zlog "github.com/rs/zerolog" - "go.loglayer.dev" - "go.loglayer.dev/transport" - "go.loglayer.dev/transport/transporttest" - llzero "go.loglayer.dev/transports/zerolog" + llzero "go.loglayer.dev/transports/zerolog/v2" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/transport" + "go.loglayer.dev/v2/transport/transporttest" ) func factory(opts transporttest.FactoryOpts) (*loglayer.LogLayer, *bytes.Buffer) { diff --git a/transports_test.go b/transports_test.go index 2b2542a..c01b002 100644 --- a/transports_test.go +++ b/transports_test.go @@ -3,9 +3,9 @@ package loglayer_test import ( "testing" - "go.loglayer.dev" - "go.loglayer.dev/internal/lltest" - "go.loglayer.dev/transport" + "go.loglayer.dev/v2" + "go.loglayer.dev/v2/internal/lltest" + "go.loglayer.dev/v2/transport" ) func TestMultipleTransports(t *testing.T) { diff --git a/utils/maputil/cloner_test.go b/utils/maputil/cloner_test.go index f04b28a..3e59861 100644 --- a/utils/maputil/cloner_test.go +++ b/utils/maputil/cloner_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "go.loglayer.dev/utils/maputil" + "go.loglayer.dev/v2/utils/maputil" ) func keyIn(set ...string) func(string) bool { diff --git a/utils/sanitize/sanitize_test.go b/utils/sanitize/sanitize_test.go index 6ad48ae..f1a9767 100644 --- a/utils/sanitize/sanitize_test.go +++ b/utils/sanitize/sanitize_test.go @@ -3,7 +3,7 @@ package sanitize_test import ( "testing" - "go.loglayer.dev/utils/sanitize" + "go.loglayer.dev/v2/utils/sanitize" ) // Message on a typical clean log string. The fast-path should short-circuit From 7414a2621c8bde036ce50fba6391ad3c1c84d542 Mon Sep 17 00:00:00 2001 From: Theo Gravity Date: Sat, 2 May 2026 15:05:04 -0700 Subject: [PATCH 3/8] docs(v2): migration guide, whats-new entry, multi-package :major changeset Phase 4 of the v2 cascade: docs + changesets. - New docs/src/migrating-to-v2.md walking the import-path bump, the prefix flow change, and the two transport strategies (preserve via JoinPrefixAndMessages or smart render). - Sidebar entry under Introduction. - whats-new.md gets a v2.0.0 entry at the top of May 02, 2026. - Multi-package changeset bumps every monorel-managed module to :major (27 packages: main + 19 transports + 6 plugins + 2 integrations). - creating-transports.md, creating-plugins.md, cheatsheet.md, llms.txt, llms-full.txt updated to remove the 'legacy auto- prepend' caveats and document the v2 contract. --- .changeset/v2-prefix-passthrough.md | 76 ++++++++++++++++++ docs/.vitepress/config.ts | 1 + docs/src/cheatsheet.md | 2 +- docs/src/migrating-to-v2.md | 92 ++++++++++++++++++++++ docs/src/plugins/creating-plugins.md | 4 +- docs/src/public/llms-full.txt | 2 +- docs/src/public/llms.txt | 2 +- docs/src/transports/creating-transports.md | 21 +++-- docs/src/whats-new.md | 4 + 9 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 .changeset/v2-prefix-passthrough.md create mode 100644 docs/src/migrating-to-v2.md diff --git a/.changeset/v2-prefix-passthrough.md b/.changeset/v2-prefix-passthrough.md new file mode 100644 index 0000000..0c5ffda --- /dev/null +++ b/.changeset/v2-prefix-passthrough.md @@ -0,0 +1,76 @@ +--- +"go.loglayer.dev": major +"transports/blank": major +"transports/charmlog": major +"transports/cli": major +"transports/console": major +"transports/datadog": major +"transports/gcplogging": major +"transports/http": major +"transports/logrus": major +"transports/lumberjack": major +"transports/otellog": major +"transports/phuslu": major +"transports/pretty": major +"transports/sentry": major +"transports/slog": major +"transports/structured": major +"transports/testing": major +"transports/zap": major +"transports/zerolog": major +"plugins/datadogtrace": major +"plugins/fmtlog": major +"plugins/oteltrace": major +"plugins/plugintest": major +"plugins/redact": major +"plugins/sampling": major +"integrations/loghttp": major +"integrations/sloghandler": major +--- + +**Breaking: import paths bump to `/v2`.** + +The loglayer core no longer mutates `Messages[0]` to fold the `WithPrefix` value into the message text. The prefix flows through `TransportParams.Prefix` (and the matching field on every dispatch-time plugin hook param struct). Each transport decides how to render the prefix: + +- Most built-in transports call `transport.JoinPrefixAndMessages(params.Prefix, params.Messages)` at the top of `SendToLogger` to preserve the v1 user-visible output exactly. +- The cli transport opts into smart rendering: the level prefix and message body keep the level color (yellow / red), while the `WithPrefix` value gets its own dim-grey color, visually separating caller-context from urgency. +- The `blank` transport intentionally passes raw v2 params through to the user-supplied `ShipToLogger` function, so advanced users can decide their own rendering. + +## Migration + +Every consumer must update import paths to `/v2`: + +```sh +go get go.loglayer.dev/v2 \ + go.loglayer.dev/transports/cli/v2 \ + go.loglayer.dev/transports/zerolog/v2 \ + # ... whichever sub-modules you import +``` + +In source files: + +```diff +-import ( +- "go.loglayer.dev" +- "go.loglayer.dev/transports/zerolog" +-) ++import ( ++ "go.loglayer.dev/v2" ++ "go.loglayer.dev/transports/zerolog/v2" ++) +``` + +For most users no other changes are needed: the built-in transports preserve v1 user-visible output. Custom transports that consumed `params.Messages[0]` and assumed the prefix was already prepended must either: + +1. Call `transport.JoinPrefixAndMessages(params.Prefix, params.Messages)` at the top of `SendToLogger` (legacy behavior preserved), or +2. Read `params.Prefix` directly and render it however you like (e.g. as a separate JSON field, in its own color, forwarded to the underlying logger's structured-field API). + +The new `transport.JoinPrefixAndMessages` helper has fast-path early returns when the prefix is empty, when messages is empty, or when `messages[0]` isn't a string; the per-call cost for any logger that hasn't called `WithPrefix` is one string compare. + +## Plugin authors + +Plugin hooks (`OnBeforeDataOut`, `OnBeforeMessageOut`, `TransformLogLevel`, `ShouldSend`) gained a `Prefix string` field on their respective params structs (was added additively in v1.7.0). The field is read-only from the plugin's perspective. With v2, `params.Messages[0]` no longer carries the prefix — plugins that read messages directly should be aware that the prefix is now ONLY on `params.Prefix`. + +## See also + +The prior v1.7.0 release added `Prefix` to the param structs as an additive field; this release removes the auto-prepend. diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index db33f9d..97d9f10 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -115,6 +115,7 @@ gtag('config', '${gaMeasurementId}');`, { text: 'For TypeScript Developers', link: '/for-typescript-developers' }, { text: 'Use with AI / LLMs', link: '/llms' }, { text: "What's New", link: '/whats-new' }, + { text: 'Migrating to v2', link: '/migrating-to-v2' }, ], }, { diff --git a/docs/src/cheatsheet.md b/docs/src/cheatsheet.md index 879b537..54f96e2 100644 --- a/docs/src/cheatsheet.md +++ b/docs/src/cheatsheet.md @@ -190,7 +190,7 @@ prefixed := log.WithPrefix("[auth]") // child with a prefix prepended Mutations on the child do not affect the parent. -The prefix is also surfaced to transports via `TransportParams.Prefix` and to all four dispatch-time plugin hooks (`BeforeDataOutParams.Prefix`, `BeforeMessageOutParams.Prefix`, `TransformLogLevelParams.Prefix`, `ShouldSendParams.Prefix`) so transports and plugins can render or react to the prefix independently from the message text. The legacy auto-prepend into `Messages[0]` is preserved unchanged for backwards compatibility; future major version will drop it. +The prefix is surfaced to transports via `TransportParams.Prefix` and to all four dispatch-time plugin hooks (`BeforeDataOutParams.Prefix`, `BeforeMessageOutParams.Prefix`, `TransformLogLevelParams.Prefix`, `ShouldSendParams.Prefix`) so transports and plugins can render or react to the prefix independently from the message text. As of v2 the prefix is NOT folded into `Messages[0]`; transports that want the v1 "prefix folded into message" rendering call `transport.JoinPrefixAndMessages(params.Prefix, params.Messages)`. ## Level Control diff --git a/docs/src/migrating-to-v2.md b/docs/src/migrating-to-v2.md new file mode 100644 index 0000000..dd3ceda --- /dev/null +++ b/docs/src/migrating-to-v2.md @@ -0,0 +1,92 @@ +--- +title: Migrating to v2 +description: "Upgrade guide for loglayer-go v2: import paths bump to /v2, the prefix is now exposed on TransportParams.Prefix instead of being folded into Messages[0]." +--- + +# 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. + +This page is the upgrade checklist. + +## 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 +``` + +In source files: + +```diff + import ( +- "go.loglayer.dev" +- "go.loglayer.dev/transports/zerolog" +- "go.loglayer.dev/plugins/redact" ++ "go.loglayer.dev/v2" ++ "go.loglayer.dev/transports/zerolog/v2" ++ "go.loglayer.dev/plugins/redact/v2" + ) +``` + +The package import name (`loglayer`, `zerolog`, `redact`) does not change; only the import path does. + +## Step 2: most users are done + +For users of the built-in transports who don't write custom transports, nothing else changes. Every built-in transport preserves the v1 user-visible output: `log.WithPrefix("[auth]").Info("hi")` still produces `"[auth] hi"` through every renderer / wrapper / network transport, just like it did in v1. + +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 — so the prefix is on `params.Prefix`, not in `Messages[0]`. If you were extracting the prefix from `Messages[0]`, switch to reading `params.Prefix`. + +## Step 3: custom transports + +If you wrote a custom transport that reads `params.Messages[0]` and relied on the prefix being baked in, you have two paths: + +### Path A: preserve v1 behavior (simplest) + +Call `transport.JoinPrefixAndMessages` at the top of `SendToLogger`: + +```go +import "go.loglayer.dev/v2/transport" + +func (t *Transport) SendToLogger(p loglayer.TransportParams) { + if !t.ShouldProcess(p.LogLevel) { + return + } + p.Messages = transport.JoinPrefixAndMessages(p.Prefix, p.Messages) + // ... your existing rendering logic, unchanged +} +``` + +The helper has fast-path early returns when the prefix is empty, when messages is empty, or when `messages[0]` isn't a string. Per-call cost on a no-prefix logger is one string compare. + +### Path B: smart rendering + +Read `params.Prefix` directly and render it however suits your transport: + +- A renderer transport could color the prefix differently from the message body (see `transports/cli` for an example). +- A structured / JSON transport could emit the prefix as a separate top-level field instead of embedding it in `msg`. +- A wrapper transport could forward the prefix to the underlying logger's structured-field API (`zerolog.Event.Str("prefix", p.Prefix)`, `zap.Field`, etc.). + +## Step 4: custom plugins + +The dispatch-time plugin hook param structs (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`) gained a `Prefix string` field in v1.7.0 — that part is unchanged in v2. The only difference: in v1, `params.Messages[0]` carried the prefix folded in; in v2 it doesn't. Plugins that read the message string directly should be aware. + +The prefix is read-only from the plugin's perspective; hooks that return modified data / messages / level / send-decision can act on the prefix value but don't propagate a modified prefix back to downstream hooks. + +## Why + +`v0.x.x` and `v1.x.x` of loglayer-go folded the prefix into `Messages[0]` so transports that didn't know about the prefix concept got the right behavior for free. The downside: transports that DID want to render the prefix differently (different color, separate field, structured forwarding) couldn't, because by the time they saw the message it was already mangled. Pulling the prefix into a first-class field unblocks that, at the cost of a one-time import-path migration. + +## See also + +- The full [release notes for v2](/whats-new) cover every package's bump and any other v2-only changes. +- [`creating-transports.md`](/transports/creating-transports#reading-params-prefix) documents the `params.Prefix` contract for transport authors. +- [`creating-plugins.md`](/plugins/creating-plugins#reading-params-prefix) documents it for plugin authors. diff --git a/docs/src/plugins/creating-plugins.md b/docs/src/plugins/creating-plugins.md index 6cc38b9..1ef5edc 100644 --- a/docs/src/plugins/creating-plugins.md +++ b/docs/src/plugins/creating-plugins.md @@ -269,7 +269,9 @@ If multiple plugins implement `SendGate`, the entry goes only when **every** plu Every dispatch-time hook param struct (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`) carries the value attached via `WithPrefix` on the emitting logger (or set on `Config.Prefix` at construction) as `params.Prefix`. Empty string when no prefix was set. -The prefix is intentionally read-only from the plugin's perspective: hooks that return modified data / messages / level / send-decision can act on the prefix value, but they don't propagate a modified prefix back to downstream hooks. Plugins that want to mutate the user-visible prefix today have to do it via `OnBeforeMessageOut` (rewriting `Messages[0]`); a future major version may expose the prefix as a writable signal once the legacy auto-prepend is removed. +The prefix is intentionally read-only from the plugin's perspective: hooks that return modified data / messages / level / send-decision can act on the prefix value, but they don't propagate a modified prefix back to downstream hooks. Plugins that want to mutate the user-visible prefix have to do it via `OnBeforeMessageOut` (rewriting `Messages[0]`). + +In v2, `params.Messages[0]` no longer carries the prefix — it's only on `params.Prefix`. Plugins reading the message string directly should be aware that the prefix won't be there. Use cases: diff --git a/docs/src/public/llms-full.txt b/docs/src/public/llms-full.txt index d0c90f6..ed0e428 100644 --- a/docs/src/public/llms-full.txt +++ b/docs/src/public/llms-full.txt @@ -896,7 +896,7 @@ func (t *myTransport) SendToLogger(p loglayer.TransportParams) { } ``` -`TransportParams` carries: `LogLevel`, `Messages` (with the prefix prepended into `Messages[0]` for backwards compat; see `Prefix` below for the unmangled value), `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; the legacy auto-prepend into `Messages[0]` is also performed for backwards compatibility, and will be removed in a future major version). +`TransportParams` carries: `LogLevel`, `Messages` (the raw message slice; the prefix is NOT prepended in v2 — see `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 the v1 "prefix folded into Messages[0]" behavior 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.). diff --git a/docs/src/public/llms.txt b/docs/src/public/llms.txt index bd45812..9936354 100644 --- a/docs/src/public/llms.txt +++ b/docs/src/public/llms.txt @@ -241,7 +241,7 @@ loglayer.New(loglayer.Config{ The merged group slice for an entry is also surfaced to transports as `TransportParams.Groups` and to all four dispatch-time plugin hooks (`BeforeDataOutParams.Groups`, `BeforeMessageOutParams.Groups`, `TransformLogLevelParams.Groups`, `ShouldSendParams.Groups`). Use it to ship groups in a transport's wire payload, or to drive group-aware transformations. -The `WithPrefix` value (or `Config.Prefix`) is also surfaced to transports as `TransportParams.Prefix` and to the same four dispatch-time plugin hooks. Transports can render the prefix independently from the message body (e.g. tinted differently, emitted as a structured field). The core also prepends `prefix + " "` into `Messages[0]` for backwards compatibility; that auto-prepend will be removed in a future major version. +The `WithPrefix` value (or `Config.Prefix`) is surfaced to transports as `TransportParams.Prefix` and to the same four dispatch-time plugin hooks. Transports can render the prefix independently from the message body (e.g. tinted differently, emitted as a structured field). As of v2 the core does NOT prepend the prefix into `Messages[0]`; transports that want the v1 "prefix folded into the message" rendering call `transport.JoinPrefixAndMessages(p.Prefix, p.Messages)` at the top of `SendToLogger`. ## Child Loggers diff --git a/docs/src/transports/creating-transports.md b/docs/src/transports/creating-transports.md index b2beb17..fe8a893 100644 --- a/docs/src/transports/creating-transports.md +++ b/docs/src/transports/creating-transports.md @@ -185,13 +185,24 @@ func (t *Transport) SendToLogger(p loglayer.TransportParams) { `params.Prefix` is the value attached via `WithPrefix` on the emitting logger (or set on `Config.Prefix` at construction), exposed verbatim so transports can render it independently from the message. Empty string when no prefix was set. -::: warning Legacy compat: Prefix is also baked into Messages\[0\] -For backwards compatibility with transports written before `Prefix` existed as a field, the core ALSO prepends `prefix + " "` to `Messages[0]` when `Messages[0]` is a string (non-string first arguments are left untouched). New transports that consume `params.Prefix` must therefore choose: +As of v2, the core does NOT prepend `params.Prefix` into `Messages[0]`. Each transport decides how to render the prefix: -- **Ignore the field, render `Messages` as-is**: preserves legacy behavior. The CLI tool sees `"warning: [auth] retrying"` because the prefix is in the message. -- **Use the field, strip the duplicate**: the transport checks whether `Messages[0]` is a string starting with `params.Prefix + " "` and removes that prefix before its own rendering. Lets the transport color, layout, or structure the prefix differently from the message body. Skip the strip when `Messages[0]` isn't a string (the core didn't prepend in that case). +- **Preserve v1 behavior** (simplest): call `transport.JoinPrefixAndMessages(params.Prefix, params.Messages)` at the top of your `SendToLogger`. The helper returns `Messages` unchanged when `Prefix` is empty (fast path) or when `Messages[0]` isn't a string; otherwise it returns a fresh slice with `prefix + " "` prepended to `Messages[0]`. Use this when your transport should keep the v1 "prefix folded into the message" rendering. +- **Smart rendering**: read `params.Prefix` directly and render it however suits your transport. A renderer can color the prefix differently from the message body; a structured transport can emit it as its own top-level field; a wrapper transport can forward it to the underlying logger's structured-field API (`zerolog.Event.Str("prefix", p.Prefix)`, etc.). Don't call `JoinPrefixAndMessages` in this path. -The duplicated signal is a known wart that will be cleaned up in a future major version (the auto-prepend will be removed; transports that want the legacy behavior may get a `transport.JoinPrefixAndMessages`-style helper at that time). For now, the additive shape preserves every existing transport's user-visible output. +```go +func (t *Transport) SendToLogger(p loglayer.TransportParams) { + if !t.ShouldProcess(p.LogLevel) { + return + } + // Path A: preserve v1 behavior + p.Messages = transport.JoinPrefixAndMessages(p.Prefix, p.Messages) + // ... existing rendering ... +} +``` + +::: tip Pre-v1.7.0 readers +Pre-v2 versions of loglayer auto-prepended the prefix into `Messages[0]` from the core. Transports that haven't migrated will see `Messages[0]` arrive WITHOUT the prefix in v2; if you want the v1 user-visible output, you must call the helper as shown above. ::: Use cases for reading `params.Prefix`: diff --git a/docs/src/whats-new.md b/docs/src/whats-new.md index 954dd47..735c7c0 100644 --- a/docs/src/whats-new.md +++ b/docs/src/whats-new.md @@ -9,6 +9,10 @@ description: Latest features and improvements in LogLayer for Go. ## May 02, 2026 +`v2.0.0`: + +**Breaking: import paths bump to `/v2`.** The loglayer core no longer mutates `Messages[0]` to fold the `WithPrefix` value into the message text. The prefix flows through `TransportParams.Prefix` and each transport decides how to render it. Built-in transports preserve v1 user-visible output via the new `transport.JoinPrefixAndMessages` helper; the cli transport opts into smart rendering (dim-grey user prefix separate from level color). See [Migrating to v2](/migrating-to-v2) for the upgrade checklist. + `loglayer`: `Prefix` is now exposed as a separate field on `TransportParams` and on every dispatch-time plugin hook param struct (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`). Transports and plugins can render or react to the prefix independently from the message string. The legacy "prepend prefix into `Messages[0]`" behavior is preserved unchanged for backwards compatibility; a future major version will remove the auto-prepend in favor of the field. From 5400cd4c827fc8027eeaafe61e35c25e11ca0050 Mon Sep 17 00:00:00 2001 From: Theo Gravity Date: Sat, 2 May 2026 15:06:13 -0700 Subject: [PATCH 4/8] chore: re-tidy go.mod files after v2 path bump Lefthook's pre-push tidy reordered the require blocks on some sub-modules (lumberjack, others) so all go.loglayer.dev-prefixed requires are alphabetically sorted. --- examples/custom-plugin/go.mod | 4 ++-- examples/datadog-shipping/go.mod | 4 ++-- examples/http-server/go.mod | 4 ++-- examples/multi-transport/go.mod | 4 ++-- examples/otel-end-to-end/go.mod | 4 ++-- examples/pretty-modes/go.mod | 4 ++-- integrations/loghttp/go.mod | 4 ++-- integrations/sloghandler/go.mod | 4 ++-- plugins/datadogtrace/go.mod | 4 ++-- plugins/datadogtrace/livetest/go.mod | 4 ++-- plugins/fmtlog/go.mod | 4 ++-- plugins/oteltrace/go.mod | 4 ++-- plugins/plugintest/go.mod | 4 ++-- plugins/redact/go.mod | 4 ++-- plugins/sampling/go.mod | 4 ++-- transports/central/go.mod | 2 +- transports/datadog/go.mod | 2 +- transports/lumberjack/go.mod | 2 +- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/examples/custom-plugin/go.mod b/examples/custom-plugin/go.mod index 8c29a64..f74d65b 100644 --- a/examples/custom-plugin/go.mod +++ b/examples/custom-plugin/go.mod @@ -3,13 +3,13 @@ module go.loglayer.dev/examples/custom-plugin/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/transports/pretty/v2 => ../../transports/pretty + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/pretty/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/examples/datadog-shipping/go.mod b/examples/datadog-shipping/go.mod index bdfa640..c6dbc1a 100644 --- a/examples/datadog-shipping/go.mod +++ b/examples/datadog-shipping/go.mod @@ -3,17 +3,17 @@ module go.loglayer.dev/examples/datadog-shipping/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/transports/datadog/v2 => ../../transports/datadog go.loglayer.dev/transports/http/v2 => ../../transports/http go.loglayer.dev/transports/pretty/v2 => ../../transports/pretty + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/datadog/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/http/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/pretty/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/examples/http-server/go.mod b/examples/http-server/go.mod index 2aeb143..96d3e03 100644 --- a/examples/http-server/go.mod +++ b/examples/http-server/go.mod @@ -3,16 +3,16 @@ module go.loglayer.dev/examples/http-server/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/integrations/loghttp/v2 => ../../integrations/loghttp go.loglayer.dev/transports/structured/v2 => ../../transports/structured go.loglayer.dev/transports/testing/v2 => ../../transports/testing + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/integrations/loghttp/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/structured/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/examples/multi-transport/go.mod b/examples/multi-transport/go.mod index 9a09ccf..a01bee3 100644 --- a/examples/multi-transport/go.mod +++ b/examples/multi-transport/go.mod @@ -3,15 +3,15 @@ module go.loglayer.dev/examples/multi-transport/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/transports/pretty/v2 => ../../transports/pretty go.loglayer.dev/transports/structured/v2 => ../../transports/structured + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/pretty/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/structured/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/examples/otel-end-to-end/go.mod b/examples/otel-end-to-end/go.mod index 64f8d03..2bfe332 100644 --- a/examples/otel-end-to-end/go.mod +++ b/examples/otel-end-to-end/go.mod @@ -3,17 +3,17 @@ module go.loglayer.dev/examples/otel-end-to-end/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/plugins/oteltrace/v2 => ../../plugins/oteltrace go.loglayer.dev/plugins/plugintest/v2 => ../../plugins/plugintest go.loglayer.dev/transports/otellog/v2 => ../../transports/otellog go.loglayer.dev/transports/testing/v2 => ../../transports/testing + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/plugins/oteltrace/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/otellog/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 diff --git a/examples/pretty-modes/go.mod b/examples/pretty-modes/go.mod index 73e1193..bb0f023 100644 --- a/examples/pretty-modes/go.mod +++ b/examples/pretty-modes/go.mod @@ -3,13 +3,13 @@ module go.loglayer.dev/examples/pretty-modes/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/transports/pretty/v2 => ../../transports/pretty + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/pretty/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/integrations/loghttp/go.mod b/integrations/loghttp/go.mod index d7b9f19..8cb0d0e 100644 --- a/integrations/loghttp/go.mod +++ b/integrations/loghttp/go.mod @@ -3,13 +3,13 @@ module go.loglayer.dev/integrations/loghttp/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/transports/testing/v2 => ../../transports/testing + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/integrations/sloghandler/go.mod b/integrations/sloghandler/go.mod index 5b2229b..23776f2 100644 --- a/integrations/sloghandler/go.mod +++ b/integrations/sloghandler/go.mod @@ -3,13 +3,13 @@ module go.loglayer.dev/integrations/sloghandler/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/transports/testing/v2 => ../../transports/testing + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/plugins/datadogtrace/go.mod b/plugins/datadogtrace/go.mod index 79860e9..eaedc03 100644 --- a/plugins/datadogtrace/go.mod +++ b/plugins/datadogtrace/go.mod @@ -3,15 +3,15 @@ module go.loglayer.dev/plugins/datadogtrace/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/plugins/plugintest/v2 => ../plugintest go.loglayer.dev/transports/testing/v2 => ../../transports/testing + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/plugins/plugintest/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/plugins/datadogtrace/livetest/go.mod b/plugins/datadogtrace/livetest/go.mod index f9e0227..8c38aa4 100644 --- a/plugins/datadogtrace/livetest/go.mod +++ b/plugins/datadogtrace/livetest/go.mod @@ -3,17 +3,17 @@ module go.loglayer.dev/plugins/datadogtrace/livetest/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../../.. go.loglayer.dev/plugins/datadogtrace/v2 => .. go.loglayer.dev/plugins/plugintest/v2 => ../../plugintest go.loglayer.dev/transports/testing/v2 => ../../../transports/testing + go.loglayer.dev/v2 => ../../.. ) require ( github.com/DataDog/dd-trace-go/v2 v2.7.3 - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/plugins/datadogtrace/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require ( diff --git a/plugins/fmtlog/go.mod b/plugins/fmtlog/go.mod index dd6fa23..5485049 100644 --- a/plugins/fmtlog/go.mod +++ b/plugins/fmtlog/go.mod @@ -3,13 +3,13 @@ module go.loglayer.dev/plugins/fmtlog/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/transports/testing/v2 => ../../transports/testing + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/plugins/oteltrace/go.mod b/plugins/oteltrace/go.mod index 0a43421..c5229ae 100644 --- a/plugins/oteltrace/go.mod +++ b/plugins/oteltrace/go.mod @@ -3,15 +3,15 @@ module go.loglayer.dev/plugins/oteltrace/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/plugins/plugintest/v2 => ../plugintest go.loglayer.dev/transports/testing/v2 => ../../transports/testing + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/plugins/plugintest/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/sdk v1.43.0 go.opentelemetry.io/otel/trace v1.43.0 diff --git a/plugins/plugintest/go.mod b/plugins/plugintest/go.mod index c3bbd6b..3dad3ca 100644 --- a/plugins/plugintest/go.mod +++ b/plugins/plugintest/go.mod @@ -3,13 +3,13 @@ module go.loglayer.dev/plugins/plugintest/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/transports/testing/v2 => ../../transports/testing + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/plugins/redact/go.mod b/plugins/redact/go.mod index d1f18a3..6623e91 100644 --- a/plugins/redact/go.mod +++ b/plugins/redact/go.mod @@ -3,15 +3,15 @@ module go.loglayer.dev/plugins/redact/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/plugins/plugintest/v2 => ../plugintest go.loglayer.dev/transports/testing/v2 => ../../transports/testing + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/plugins/plugintest/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/plugins/sampling/go.mod b/plugins/sampling/go.mod index 5f5531e..53e3dee 100644 --- a/plugins/sampling/go.mod +++ b/plugins/sampling/go.mod @@ -3,15 +3,15 @@ module go.loglayer.dev/plugins/sampling/v2 go 1.25.0 replace ( - go.loglayer.dev/v2 => ../.. go.loglayer.dev/plugins/plugintest/v2 => ../plugintest go.loglayer.dev/transports/testing/v2 => ../../transports/testing + go.loglayer.dev/v2 => ../.. ) require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/plugins/plugintest/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/testing/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 ) require github.com/goccy/go-json v0.10.6 // indirect diff --git a/transports/central/go.mod b/transports/central/go.mod index f7577de..227c4f7 100644 --- a/transports/central/go.mod +++ b/transports/central/go.mod @@ -8,7 +8,7 @@ replace go.loglayer.dev/transports/http/v2 => ../http require ( github.com/goccy/go-json v0.10.6 - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/http/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.uber.org/goleak v1.3.0 ) diff --git a/transports/datadog/go.mod b/transports/datadog/go.mod index 1d9c2e5..5aa4319 100644 --- a/transports/datadog/go.mod +++ b/transports/datadog/go.mod @@ -8,7 +8,7 @@ replace go.loglayer.dev/transports/http/v2 => ../http require ( github.com/goccy/go-json v0.10.6 - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/http/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.uber.org/goleak v1.3.0 ) diff --git a/transports/lumberjack/go.mod b/transports/lumberjack/go.mod index 8ae42d6..41ced7b 100644 --- a/transports/lumberjack/go.mod +++ b/transports/lumberjack/go.mod @@ -7,8 +7,8 @@ replace go.loglayer.dev/v2 => ../.. replace go.loglayer.dev/transports/structured/v2 => ../structured require ( - go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 go.loglayer.dev/transports/structured/v2 v2.0.0-00010101000000-000000000000 + go.loglayer.dev/v2 v2.0.0-00010101000000-000000000000 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) From 87daae822ef7a0566b8d8457d32f751454c15dac Mon Sep 17 00:00:00 2001 From: Theo Gravity Date: Sat, 2 May 2026 15:22:38 -0700 Subject: [PATCH 5/8] fix(v2): address round-1 review findings Critical: - Update TransportParams.Prefix GoDoc (loglayer.go) to describe v2 contract; remove the stale 'auto-prepend will be removed in a future major version' caveat that referred to v2 itself. - Update Config.Prefix GoDoc (types.go) to describe v2 contract. - Update internal LogLayer.prefix field comment to describe v2 propagation model. - Update whats-new.md v1.7.0 entry to note the auto-prepend was removed in v2.0.0 (resolves the chronological contradiction). - Rewrite docs/src/transports/cli.md 'Using WithPrefix' section for v2: the cli transport reads params.Prefix and renders the prefix in dim grey, separate from the level color. - Delete .changeset/prefix-on-params.md (revived from a stale branch off main; was already consumed by v1.7.0 release). Important: - Sanitize the user prefix in cli's smart-rendering path (sanitize.Message on params.Prefix) so an env- or config-loaded prefix can't smuggle ANSI / CRLF through the new layer. - Add 4 new cli tests: WithPrefix renders inline, WithPrefix gets dim-grey ANSI separate from level color, WithPrefix sanitizes ANSI smuggling, info-level WithPrefix only colors the prefix (body unstyled). - Add direct unit tests for transport.JoinPrefixAndMessages covering all five branches (empty prefix, nil messages, empty messages, non-string first arg, normal case with fresh-slice guarantee). - Sweep em-dashes from new content (migrating-to-v2.md, cli.md, changeset body). - Rename ':::tip Pre-v1.7.0 readers' callout to 'Pre-v2 readers'. - Add 'Do I have to migrate?' and 'Why this change' lede sections to migrating-to-v2.md, with the existing buried '## Why' tail consolidated into the lede. Skipped (deferred to follow-up): - C1 (37 doc pages with v1 import paths): mechanical sweep that fits a separate PR; build still passes since the import paths in the docs are illustrative, not load-bearing. - AGENTS.md / CONTRIBUTING.md template updates for new sub-modules: same follow-up. - I2 (contract test for prefix in transport/transporttest): worth but not blocking. - I4 (cli WithPrefix Example with // Output): would need to omit // Output for color cases; the new tests cover the same ground. - I5 (no benchmark for prefix path): non-blocking; claim about 'one string compare' is verifiable via the helper's source. - I6 (lltest 'byte-for-byte equivalent' comment): pre-existing drift; unrelated to v2. - I7 (doc.go list of helpers): minor; doesn't affect users. --- .changeset/prefix-on-params.md | 13 ---- .changeset/v2-prefix-passthrough.md | 2 +- docs/src/migrating-to-v2.md | 18 +++-- docs/src/transports/cli.md | 12 ++-- docs/src/transports/creating-transports.md | 2 +- docs/src/whats-new.md | 2 +- loglayer.go | 27 ++++---- transport/helpers_test.go | 46 +++++++++++++ transports/cli/cli.go | 7 +- transports/cli/cli_test.go | 78 ++++++++++++++++++++++ types.go | 8 ++- 11 files changed, 173 insertions(+), 42 deletions(-) delete mode 100644 .changeset/prefix-on-params.md diff --git a/.changeset/prefix-on-params.md b/.changeset/prefix-on-params.md deleted file mode 100644 index c447962..0000000 --- a/.changeset/prefix-on-params.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"go.loglayer.dev": minor ---- - -Expose `Prefix` on dispatch-time params. - -`loglayer.TransportParams` and every dispatch-time plugin hook param struct (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`) now carry `Prefix string`, populated from the `WithPrefix` value of the emitting logger. Transports and plugins can render or react to the prefix independently from the message text. - -The legacy auto-prepend (the core writes `prefix + " "` into `Messages[0]` before dispatch) is preserved unchanged for backwards compatibility, so every existing transport keeps its v1 user-visible output. A future major version will remove the auto-prepend; transports that opt into reading `params.Prefix` today should either ignore the duplicate in `Messages[0]` (legacy behavior) or strip it before their own rendering (smart rendering). - -Documented on `creating-transports.md` (Reading `params.Prefix`) and `creating-plugins.md` (Reading `params.Prefix`). - -`internal/lltest.LogLine` gained a matching `Prefix` field so test fixtures can assert on the new signal. diff --git a/.changeset/v2-prefix-passthrough.md b/.changeset/v2-prefix-passthrough.md index 0c5ffda..b1bdc74 100644 --- a/.changeset/v2-prefix-passthrough.md +++ b/.changeset/v2-prefix-passthrough.md @@ -69,7 +69,7 @@ The new `transport.JoinPrefixAndMessages` helper has fast-path early returns whe ## Plugin authors -Plugin hooks (`OnBeforeDataOut`, `OnBeforeMessageOut`, `TransformLogLevel`, `ShouldSend`) gained a `Prefix string` field on their respective params structs (was added additively in v1.7.0). The field is read-only from the plugin's perspective. With v2, `params.Messages[0]` no longer carries the prefix — plugins that read messages directly should be aware that the prefix is now ONLY on `params.Prefix`. +Plugin hooks (`OnBeforeDataOut`, `OnBeforeMessageOut`, `TransformLogLevel`, `ShouldSend`) gained a `Prefix string` field on their respective params structs (was added additively in v1.7.0). The field is read-only from the plugin's perspective. With v2, `params.Messages[0]` no longer carries the prefix; plugins that read messages directly should be aware that the prefix is now ONLY on `params.Prefix`. ## See also diff --git a/docs/src/migrating-to-v2.md b/docs/src/migrating-to-v2.md index dd3ceda..0187fb1 100644 --- a/docs/src/migrating-to-v2.md +++ b/docs/src/migrating-to-v2.md @@ -9,6 +9,16 @@ description: "Upgrade guide for loglayer-go v2: import paths bump to /v2, the pr This page is the upgrade checklist. +## Do I have to migrate? + +Not immediately. v1.x continues to work; the v1 module path (`go.loglayer.dev`) keeps resolving to its last v1 tag and the auto-prepend behavior stays intact there. Future feature work and bug fixes ship at v2 (`go.loglayer.dev/v2`), so the migration is the path forward but it's not on a deadline. + +You can migrate one module at a time: a project that uses several `loglayer-go` sub-modules can have v1 imports for some and v2 for others (Go treats `go.loglayer.dev` and `go.loglayer.dev/v2` as separate modules). The catch is that fields shared between modules (e.g. `loglayer.Config` from main) won't bridge between v1 and v2 — pick one main module per project. + +## Why this change + +`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. + ## 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. @@ -43,7 +53,7 @@ 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 — so 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** 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`. ## Step 3: custom transports @@ -77,14 +87,10 @@ Read `params.Prefix` directly and render it however suits your transport: ## Step 4: custom plugins -The dispatch-time plugin hook param structs (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`) gained a `Prefix string` field in v1.7.0 — that part is unchanged in v2. The only difference: in v1, `params.Messages[0]` carried the prefix folded in; in v2 it doesn't. Plugins that read the message string directly should be aware. +The dispatch-time plugin hook param structs (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`) gained a `Prefix string` field in v1.7.0; that part is unchanged in v2. The only difference: in v1, `params.Messages[0]` carried the prefix folded in; in v2 it doesn't. Plugins that read the message string directly should be aware. The prefix is read-only from the plugin's perspective; hooks that return modified data / messages / level / send-decision can act on the prefix value but don't propagate a modified prefix back to downstream hooks. -## Why - -`v0.x.x` and `v1.x.x` of loglayer-go folded the prefix into `Messages[0]` so transports that didn't know about the prefix concept got the right behavior for free. The downside: transports that DID want to render the prefix differently (different color, separate field, structured forwarding) couldn't, because by the time they saw the message it was already mangled. Pulling the prefix into a first-class field unblocks that, at the cost of a one-time import-path migration. - ## See also - The full [release notes for v2](/whats-new) cover every package's bump and any other v2-only changes. diff --git a/docs/src/transports/cli.md b/docs/src/transports/cli.md index bba1481..3c5e4c8 100644 --- a/docs/src/transports/cli.md +++ b/docs/src/transports/cli.md @@ -119,16 +119,18 @@ When the entry's level is warn / error / fatal, the headline (prefix + message) ## Using `WithPrefix` -`loglayer.LogLayer.WithPrefix` mutates the message at the loglayer core (prepending `prefix + " "`), so the cli transport sees the message with the prefix already baked in. Combined with the level prefix: +The cli transport reads `params.Prefix` directly and renders it as a third visual layer between the level prefix and the message body, in dim grey. Each piece gets its own color treatment so caller-context and urgency stay visually distinct: ```go log := loglayer.New(...).WithPrefix("[auth]") -log.Info("starting") // → "[auth] starting" -log.Warn("retrying") // → "warning: [auth] retrying" -log.Error("failed") // → "error: [auth] failed" +log.Info("starting") // → "[auth] starting" (prefix dim grey) +log.Warn("retrying") // → "warning: [auth] retrying" (level yellow, prefix grey, body yellow) +log.Error("failed") // → "error: [auth] failed" (level red, prefix grey, body red) ``` -`"warning: "` and `"error: "` come from the cli transport's level prefix; `"[auth]"` is baked into the message at the loglayer core. The level prefix is outermost; `WithPrefix` nests inside as part of the message. The reading order parses as "this is a warning. [auth context] retrying," which is the right framing. +The level prefix and message body share the level color (yellow / red / etc.); the user prefix gets `color.FgHiBlack` (dim grey) regardless of level. The visual layering reads as "this is a warning. [auth context] retrying": three signals stacked rather than blended. + +This is a behavior change vs. v1, where the user prefix arrived already folded into the message string and inherited the level color. If you upgrade from v1.x and want the old monochrome rendering back, set `Color: ColorNever` (drops all color) or read [Migrating to v2](/migrating-to-v2) for the wider migration story. ## Verbose Mode (`-v` / `--debug`) diff --git a/docs/src/transports/creating-transports.md b/docs/src/transports/creating-transports.md index fe8a893..a69eee8 100644 --- a/docs/src/transports/creating-transports.md +++ b/docs/src/transports/creating-transports.md @@ -201,7 +201,7 @@ func (t *Transport) SendToLogger(p loglayer.TransportParams) { } ``` -::: tip Pre-v1.7.0 readers +::: tip Pre-v2 readers Pre-v2 versions of loglayer auto-prepended the prefix into `Messages[0]` from the core. Transports that haven't migrated will see `Messages[0]` arrive WITHOUT the prefix in v2; if you want the v1 user-visible output, you must call the helper as shown above. ::: diff --git a/docs/src/whats-new.md b/docs/src/whats-new.md index 735c7c0..c6a5fa3 100644 --- a/docs/src/whats-new.md +++ b/docs/src/whats-new.md @@ -15,7 +15,7 @@ description: Latest features and improvements in LogLayer for Go. `loglayer`: -`Prefix` is now exposed as a separate field on `TransportParams` and on every dispatch-time plugin hook param struct (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`). Transports and plugins can render or react to the prefix independently from the message string. The legacy "prepend prefix into `Messages[0]`" behavior is preserved unchanged for backwards compatibility; a future major version will remove the auto-prepend in favor of the field. +`Prefix` is now exposed as a separate field on `TransportParams` and on every dispatch-time plugin hook param struct (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`). Transports and plugins can render or react to the prefix independently from the message string. The legacy "prepend prefix into `Messages[0]`" behavior is preserved unchanged for backwards compatibility (and removed in v2.0.0). `transports/cli`: diff --git a/loglayer.go b/loglayer.go index 8497846..1777bee 100644 --- a/loglayer.go +++ b/loglayer.go @@ -84,16 +84,13 @@ type TransportParams struct { // message (e.g. tinted differently, emitted as a structured // field, rendered in its own column). // - // As of this version, Prefix is ALSO prepended to Messages[0] - // (when Messages[0] is a string) for backwards compatibility - // with transports that consumed the legacy "prefix folded into - // message" behavior; that auto-prepend will be removed in a - // future major version. New transports should read Prefix here - // and render it explicitly, either by stripping the legacy - // duplicate from Messages[0] or by using only the standalone - // field once auto-prepend is dropped. - // // Empty string when no prefix was set. + // + // Transports that want the v1 "prefix folded into Messages[0]" + // rendering call [transport.JoinPrefixAndMessages] at the top + // of SendToLogger; the helper has fast-path early returns for + // the no-prefix case, so the per-call cost on a logger that + // hasn't called WithPrefix is one string compare. Prefix string } @@ -129,10 +126,14 @@ type LogLayer struct { // produced this logger; never mutated post-publish, so the dispatch // path can read it without synchronization. boundCtx context.Context - // prefix is prepended to the first string message of every emission - // from this logger. Initialized from Config.Prefix at build time; - // WithPrefix mutates this field on a fresh child only. Same lifecycle - // as assignedGroups/boundCtx: never mutated post-publish. + // prefix is the WithPrefix value for this logger, propagated to + // every emission via TransportParams.Prefix and the dispatch- + // time plugin hook param structs. Transports decide how to + // render it (most call transport.JoinPrefixAndMessages to + // preserve v1 "prefix folded into the message" behavior). + // Initialized from Config.Prefix at build time; WithPrefix + // mutates this field on a fresh child only. Same lifecycle as + // assignedGroups/boundCtx: never mutated post-publish. prefix string // txMu serializes transport mutators (AddTransport / RemoveTransport / // SetTransports) so two concurrent admin operations on the same diff --git a/transport/helpers_test.go b/transport/helpers_test.go index 6c99b8d..fd23a5a 100644 --- a/transport/helpers_test.go +++ b/transport/helpers_test.go @@ -53,6 +53,52 @@ func TestJoinMessages(t *testing.T) { } } +func TestJoinPrefixAndMessages(t *testing.T) { + t.Run("empty prefix returns input slice unchanged (identity)", func(t *testing.T) { + in := []any{"hello", "world"} + got := transport.JoinPrefixAndMessages("", in) + // Identity: same backing array, no allocation. + if len(got) != len(in) || &got[0] != &in[0] { + t.Errorf("expected identity passthrough; got fresh slice") + } + }) + t.Run("nil messages returns input nil", func(t *testing.T) { + got := transport.JoinPrefixAndMessages("[p]", nil) + if got != nil { + t.Errorf("expected nil, got %v", got) + } + }) + t.Run("empty messages slice returns input identity", func(t *testing.T) { + in := []any{} + got := transport.JoinPrefixAndMessages("[p]", in) + if len(got) != 0 { + t.Errorf("expected empty, got %v", got) + } + }) + t.Run("non-string messages[0] returns input slice unchanged", func(t *testing.T) { + in := []any{42, "rest"} + got := transport.JoinPrefixAndMessages("[p]", in) + if len(got) != len(in) || got[0] != 42 || got[1] != "rest" { + t.Errorf("non-string first arg should pass through: %v", got) + } + }) + t.Run("normal case prepends prefix and returns fresh slice", func(t *testing.T) { + in := []any{"hello", "world"} + got := transport.JoinPrefixAndMessages("[p]", in) + if got[0] != "[p] hello" { + t.Errorf("got[0] = %v, want %q", got[0], "[p] hello") + } + if got[1] != "world" { + t.Errorf("got[1] = %v, want %q", got[1], "world") + } + // Mutating the result must not affect the input. + got[0] = "mutated" + if in[0] != "hello" { + t.Errorf("input slice mutated through aliasing: in[0] = %v", in[0]) + } + }) +} + type metaUser struct { ID int `json:"id"` Name string `json:"name"` diff --git a/transports/cli/cli.go b/transports/cli/cli.go index 63cf1b4..f61d739 100644 --- a/transports/cli/cli.go +++ b/transports/cli/cli.go @@ -253,7 +253,12 @@ func (t *Transport) format(params loglayer.TransportParams) string { userPrefix := "" if params.Prefix != "" { - userPrefix = params.Prefix + " " + // Sanitize the prefix in-line so a Config.Prefix / + // WithPrefix value loaded from env or config can't + // smuggle ANSI / CRLF through cli's smart-rendering + // path. Mirrors the sanitize call applied to messages, + // logfmt values, table cells, and LevelPrefix. + userPrefix = sanitize.Message(params.Prefix) + " " } // Append optional logfmt or capture a table. diff --git a/transports/cli/cli_test.go b/transports/cli/cli_test.go index f800c48..91c3aea 100644 --- a/transports/cli/cli_test.go +++ b/transports/cli/cli_test.go @@ -639,6 +639,84 @@ func TestNilElementBailsTableFastPath(t *testing.T) { } } +func TestWithPrefixRendersInline(t *testing.T) { + // v2 contract: WithPrefix renders between the level prefix + // and the message body, plain text when ColorNever. + log, stdout, stderr := makeLogger(t, clitr.Config{}) + + prefixed := log.WithPrefix("[auth]") + prefixed.Info("starting") + prefixed.Warn("retrying") + prefixed.Error("failed") + + if got := strings.TrimRight(stdout.String(), "\n"); got != "[auth] starting" { + t.Errorf("Info: got %q, want %q", got, "[auth] starting") + } + if !strings.Contains(stderr.String(), "warning: [auth] retrying") { + t.Errorf("Warn missing inline prefix: %q", stderr.String()) + } + if !strings.Contains(stderr.String(), "error: [auth] failed") { + t.Errorf("Error missing inline prefix: %q", stderr.String()) + } +} + +func TestWithPrefixGetsDimGreyAnsiSeparateFromLevel(t *testing.T) { + // With Color: ColorAlways and a warn-level entry, the level + // prefix and message body should carry the warn color (yellow, + // FgYellow = 33), while the user prefix should carry FgHiBlack + // (90). Both ANSI color codes appear in the line. + var stdout, stderr bytes.Buffer + log := loglayer.New(loglayer.Config{ + Transport: clitr.New(clitr.Config{ + Stdout: &stdout, + Stderr: &stderr, + Color: clitr.ColorAlways, + }), + }) + log.WithPrefix("[auth]").Warn("retrying") + + out := stderr.String() + if !strings.Contains(out, "\x1b[33m") { + t.Errorf("expected yellow (33) ANSI for warn level/body; got %q", out) + } + if !strings.Contains(out, "\x1b[90m") { + t.Errorf("expected FgHiBlack (90) ANSI for user prefix; got %q", out) + } +} + +func TestWithPrefixSanitizesAnsiSmuggling(t *testing.T) { + // A prefix loaded from env or config that carries ANSI escapes + // must not smuggle them through cli's smart-rendering path. + log, stdout, _ := makeLogger(t, clitr.Config{}) + + log.WithPrefix("\x1b[31mFAKE\x1b[0m").Info("ok") + + got := stdout.String() + if strings.ContainsRune(got, 0x1b) { + t.Errorf("ANSI ESC in WithPrefix value leaked through: %q", got) + } +} + +func TestWithPrefixWithNoLevelColorOnInfo(t *testing.T) { + // At info level the default level color is nil. With a user + // prefix, only the user prefix carries ANSI; the message body + // is unstyled. + var stdout, stderr bytes.Buffer + log := loglayer.New(loglayer.Config{ + Transport: clitr.New(clitr.Config{ + Stdout: &stdout, + Stderr: &stderr, + Color: clitr.ColorAlways, + }), + }) + log.WithPrefix("[auth]").Info("hi") + + out := stdout.String() + if !strings.Contains(out, "\x1b[90m[auth] \x1b[0m") { + t.Errorf("user prefix should be wrapped in FgHiBlack ANSI; got %q", out) + } +} + func TestColorAlwaysDoesNotTintTableBody(t *testing.T) { // When color is forced on AND the level is warn (yellow), the // headline should be tinted but the table body should not. diff --git a/types.go b/types.go index 051a286..25f7c0f 100644 --- a/types.go +++ b/types.go @@ -62,7 +62,13 @@ type Config struct { // either form is fine. Plugins []Plugin - // Prefix is prepended to the first string message of every log call. + // Prefix is exposed verbatim on TransportParams.Prefix and on + // every dispatch-time plugin hook param struct. Transports + // decide how to render it (most call + // transport.JoinPrefixAndMessages to preserve v1 "prefix + // folded into the message" behavior; cli renders the prefix + // in dim grey separate from the level color). Equivalent to + // calling WithPrefix on the freshly-constructed logger. Prefix string // Disabled suppresses all log output when true. Defaults to false From e1864993fc24f4986c3221e5d5fc3d95cc20d018 Mon Sep 17 00:00:00 2001 From: Theo Gravity Date: Sat, 2 May 2026 15:32:27 -0700 Subject: [PATCH 6/8] docs: strip v1/v2 archaeology outside whats-new + migrating-to-v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per direction: loglayer-go is too new to make v1-vs-v2 framing visible to readers who land on regular docs. Sweep all 'as of v2' / 'preserve v1 behavior' / 'pre-v2 readers' / 'in v2' references out of regular docs and replace with plain present-tense descriptions of what the code does today. Files swept: - loglayer.go: TransportParams.Prefix GoDoc and internal prefix field comment now describe the contract without versioning. - types.go: Config.Prefix GoDoc same. - transport/helpers.go: JoinPrefixAndMessages doc reframed as 'fold prefix into the first message' rather than 'preserve v1 behavior'. - transports/*/*.go: comment cleanup at every SendToLogger call site that called the helper (the line was 'Preserve the v1 prefix folded into Messages[0] rendering; the core no longer mutates messages, transports own it now' — now 'Fold the prefix into Messages[0] for the rendered output; transports own this rendering choice'). - docs/src/transports/creating-transports.md: drop 'As of v2' and 'Pre-v2 readers' callout; describe current contract plainly. - docs/src/transports/cli.md: drop 'behavior change vs. v1' paragraph; keep just the 'set ColorNever for monochrome' tip. - docs/src/plugins/creating-plugins.md: drop 'In v2' qualifier on the read-only contract. - docs/src/cheatsheet.md: drop 'as of v2' framing; replace stale 'prefix prepended' inline comment with 'Prefix value'. - docs/src/public/llms.txt and llms-full.txt: drop 'as of v2' / 'in v2' framing; update 'Out of Scope (v1)' heading to 'Currently out of scope'. - docs/src/whats-new.md: tighten the v1.7.0 line so the parenthetical doesn't self-contradict. - docs/src/migrating-to-v2.md: em-dash sweep on the new lede. Kept intact (per direction): - whats-new.md v2.0.0 entry — still names v1.7.0 / v2.0.0 because whats-new is the version-history page. - migrating-to-v2.md — still names v1 / v2 because it's the migration page. - .changeset/v2-prefix-passthrough.md — the changeset body is the canonical v2 release note. --- docs/src/cheatsheet.md | 4 ++-- docs/src/migrating-to-v2.md | 2 +- docs/src/plugins/creating-plugins.md | 2 +- docs/src/public/llms-full.txt | 4 ++-- docs/src/public/llms.txt | 2 +- docs/src/transports/cli.md | 2 +- docs/src/transports/creating-transports.md | 12 ++++------ docs/src/whats-new.md | 2 +- loglayer.go | 12 +++++----- transport/helpers.go | 28 ++++++++++------------ transports/charmlog/charmlog.go | 4 ++-- transports/console/console.go | 4 ++-- transports/gcplogging/gcplogging.go | 4 ++-- transports/http/http.go | 4 ++-- transports/logrus/logrus.go | 4 ++-- transports/otellog/otellog.go | 4 ++-- transports/phuslu/phuslu.go | 4 ++-- transports/pretty/pretty.go | 4 ++-- transports/sentry/sentry.go | 4 ++-- transports/slog/slog.go | 4 ++-- transports/structured/structured.go | 4 ++-- transports/zap/zap.go | 4 ++-- transports/zerolog/zerolog.go | 4 ++-- types.go | 10 ++++---- 24 files changed, 62 insertions(+), 70 deletions(-) diff --git a/docs/src/cheatsheet.md b/docs/src/cheatsheet.md index 54f96e2..d54b602 100644 --- a/docs/src/cheatsheet.md +++ b/docs/src/cheatsheet.md @@ -185,12 +185,12 @@ The "At a Glance" example shows the typical chain. Two things to know: ```go child := log.Child() // copy of fields + level state -prefixed := log.WithPrefix("[auth]") // child with a prefix prepended +prefixed := log.WithPrefix("[auth]") // child with a Prefix value ``` Mutations on the child do not affect the parent. -The prefix is surfaced to transports via `TransportParams.Prefix` and to all four dispatch-time plugin hooks (`BeforeDataOutParams.Prefix`, `BeforeMessageOutParams.Prefix`, `TransformLogLevelParams.Prefix`, `ShouldSendParams.Prefix`) so transports and plugins can render or react to the prefix independently from the message text. As of v2 the prefix is NOT folded into `Messages[0]`; transports that want the v1 "prefix folded into message" rendering call `transport.JoinPrefixAndMessages(params.Prefix, params.Messages)`. +The prefix is surfaced to transports via `TransportParams.Prefix` and to all four dispatch-time plugin hooks (`BeforeDataOutParams.Prefix`, `BeforeMessageOutParams.Prefix`, `TransformLogLevelParams.Prefix`, `ShouldSendParams.Prefix`) so transports and plugins can render or react to the prefix independently from the message text. Transports that want a "prefix folded into the message" rendering call `transport.JoinPrefixAndMessages(params.Prefix, params.Messages)`. ## Level Control diff --git a/docs/src/migrating-to-v2.md b/docs/src/migrating-to-v2.md index 0187fb1..0eb960a 100644 --- a/docs/src/migrating-to-v2.md +++ b/docs/src/migrating-to-v2.md @@ -13,7 +13,7 @@ This page is the upgrade checklist. Not immediately. v1.x continues to work; the v1 module path (`go.loglayer.dev`) keeps resolving to its last v1 tag and the auto-prepend behavior stays intact there. Future feature work and bug fixes ship at v2 (`go.loglayer.dev/v2`), so the migration is the path forward but it's not on a deadline. -You can migrate one module at a time: a project that uses several `loglayer-go` sub-modules can have v1 imports for some and v2 for others (Go treats `go.loglayer.dev` and `go.loglayer.dev/v2` as separate modules). The catch is that fields shared between modules (e.g. `loglayer.Config` from main) won't bridge between v1 and v2 — pick one main module per project. +You can migrate one module at a time: a project that uses several `loglayer-go` sub-modules can have v1 imports for some and v2 for others (Go treats `go.loglayer.dev` and `go.loglayer.dev/v2` as separate modules). The catch is that fields shared between modules (e.g. `loglayer.Config` from main) won't bridge between v1 and v2; pick one main module per project. ## Why this change diff --git a/docs/src/plugins/creating-plugins.md b/docs/src/plugins/creating-plugins.md index 1ef5edc..7521a76 100644 --- a/docs/src/plugins/creating-plugins.md +++ b/docs/src/plugins/creating-plugins.md @@ -271,7 +271,7 @@ Every dispatch-time hook param struct (`BeforeDataOutParams`, `BeforeMessageOutP The prefix is intentionally read-only from the plugin's perspective: hooks that return modified data / messages / level / send-decision can act on the prefix value, but they don't propagate a modified prefix back to downstream hooks. Plugins that want to mutate the user-visible prefix have to do it via `OnBeforeMessageOut` (rewriting `Messages[0]`). -In v2, `params.Messages[0]` no longer carries the prefix — it's only on `params.Prefix`. Plugins reading the message string directly should be aware that the prefix won't be there. +`params.Messages[0]` does NOT carry the prefix; `params.Prefix` is the only signal. Plugins reading the message string can ignore the prefix, or read it from `params.Prefix` directly when needed. Use cases: diff --git a/docs/src/public/llms-full.txt b/docs/src/public/llms-full.txt index ed0e428..932c981 100644 --- a/docs/src/public/llms-full.txt +++ b/docs/src/public/llms-full.txt @@ -896,7 +896,7 @@ func (t *myTransport) SendToLogger(p loglayer.TransportParams) { } ``` -`TransportParams` carries: `LogLevel`, `Messages` (the raw message slice; the prefix is NOT prepended in v2 — see `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 the v1 "prefix folded into Messages[0]" behavior call `transport.JoinPrefixAndMessages(p.Prefix, p.Messages)` at the top of `SendToLogger`. +`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.). @@ -1099,7 +1099,7 @@ require.Equal(t, "[REDACTED]", md["pw"]) `plugintest.AssertNoMutation` and `plugintest.AssertPanicRecovered` are available for common patterns. -## What Out of Scope (v1) +## Currently out of scope - Lazy evaluation in fields/metadata (TS LogLayer has `lazy()`; not in Go yet) - Async lazy values diff --git a/docs/src/public/llms.txt b/docs/src/public/llms.txt index 9936354..876a34e 100644 --- a/docs/src/public/llms.txt +++ b/docs/src/public/llms.txt @@ -241,7 +241,7 @@ loglayer.New(loglayer.Config{ The merged group slice for an entry is also surfaced to transports as `TransportParams.Groups` and to all four dispatch-time plugin hooks (`BeforeDataOutParams.Groups`, `BeforeMessageOutParams.Groups`, `TransformLogLevelParams.Groups`, `ShouldSendParams.Groups`). Use it to ship groups in a transport's wire payload, or to drive group-aware transformations. -The `WithPrefix` value (or `Config.Prefix`) is surfaced to transports as `TransportParams.Prefix` and to the same four dispatch-time plugin hooks. Transports can render the prefix independently from the message body (e.g. tinted differently, emitted as a structured field). As of v2 the core does NOT prepend the prefix into `Messages[0]`; transports that want the v1 "prefix folded into the message" rendering call `transport.JoinPrefixAndMessages(p.Prefix, p.Messages)` at the top of `SendToLogger`. +The `WithPrefix` value (or `Config.Prefix`) is surfaced to transports as `TransportParams.Prefix` and to the same four dispatch-time plugin hooks. Transports can render the prefix independently from the message body (e.g. tinted differently, emitted as a structured field). The core does NOT prepend the prefix into `Messages[0]`; transports that want a "prefix folded into the message" rendering call `transport.JoinPrefixAndMessages(p.Prefix, p.Messages)` at the top of `SendToLogger`. ## Child Loggers diff --git a/docs/src/transports/cli.md b/docs/src/transports/cli.md index 3c5e4c8..9f56e01 100644 --- a/docs/src/transports/cli.md +++ b/docs/src/transports/cli.md @@ -130,7 +130,7 @@ log.Error("failed") // → "error: [auth] failed" (level red, prefix g The level prefix and message body share the level color (yellow / red / etc.); the user prefix gets `color.FgHiBlack` (dim grey) regardless of level. The visual layering reads as "this is a warning. [auth context] retrying": three signals stacked rather than blended. -This is a behavior change vs. v1, where the user prefix arrived already folded into the message string and inherited the level color. If you upgrade from v1.x and want the old monochrome rendering back, set `Color: ColorNever` (drops all color) or read [Migrating to v2](/migrating-to-v2) for the wider migration story. +If you want monochrome rendering, set `Color: ColorNever` to drop all color (the user prefix and the level prefix both render as plain text). ## Verbose Mode (`-v` / `--debug`) diff --git a/docs/src/transports/creating-transports.md b/docs/src/transports/creating-transports.md index a69eee8..5528ef1 100644 --- a/docs/src/transports/creating-transports.md +++ b/docs/src/transports/creating-transports.md @@ -185,26 +185,22 @@ func (t *Transport) SendToLogger(p loglayer.TransportParams) { `params.Prefix` is the value attached via `WithPrefix` on the emitting logger (or set on `Config.Prefix` at construction), exposed verbatim so transports can render it independently from the message. Empty string when no prefix was set. -As of v2, the core does NOT prepend `params.Prefix` into `Messages[0]`. Each transport decides how to render the prefix: +The core does NOT prepend `params.Prefix` into `Messages[0]`. Each transport decides how to render the prefix: -- **Preserve v1 behavior** (simplest): call `transport.JoinPrefixAndMessages(params.Prefix, params.Messages)` at the top of your `SendToLogger`. The helper returns `Messages` unchanged when `Prefix` is empty (fast path) or when `Messages[0]` isn't a string; otherwise it returns a fresh slice with `prefix + " "` prepended to `Messages[0]`. Use this when your transport should keep the v1 "prefix folded into the message" rendering. -- **Smart rendering**: read `params.Prefix` directly and render it however suits your transport. A renderer can color the prefix differently from the message body; a structured transport can emit it as its own top-level field; a wrapper transport can forward it to the underlying logger's structured-field API (`zerolog.Event.Str("prefix", p.Prefix)`, etc.). Don't call `JoinPrefixAndMessages` in this path. +- **Fold the prefix into the message** (simplest): call `transport.JoinPrefixAndMessages(params.Prefix, params.Messages)` at the top of your `SendToLogger`. The helper returns `Messages` unchanged when `Prefix` is empty (fast path) or when `Messages[0]` isn't a string; otherwise it returns a fresh slice with `prefix + " "` prepended to `Messages[0]`. The output reads as one blob (`"[prefix] message body"`) which is what most renderer / wrapper transports want. +- **Render the prefix separately**: read `params.Prefix` directly and render it however suits your transport. A renderer can color the prefix differently from the message body; a structured transport can emit it as its own top-level field; a wrapper transport can forward it to the underlying logger's structured-field API (`zerolog.Event.Str("prefix", p.Prefix)`, etc.). Don't call `JoinPrefixAndMessages` in this path. ```go func (t *Transport) SendToLogger(p loglayer.TransportParams) { if !t.ShouldProcess(p.LogLevel) { return } - // Path A: preserve v1 behavior + // Fold-into-message path: p.Messages = transport.JoinPrefixAndMessages(p.Prefix, p.Messages) // ... existing rendering ... } ``` -::: tip Pre-v2 readers -Pre-v2 versions of loglayer auto-prepended the prefix into `Messages[0]` from the core. Transports that haven't migrated will see `Messages[0]` arrive WITHOUT the prefix in v2; if you want the v1 user-visible output, you must call the helper as shown above. -::: - Use cases for reading `params.Prefix`: - **Renderer transports** rendering the prefix in a different color than the message (e.g. dim `[auth]` + plain message body). diff --git a/docs/src/whats-new.md b/docs/src/whats-new.md index c6a5fa3..62fc48b 100644 --- a/docs/src/whats-new.md +++ b/docs/src/whats-new.md @@ -15,7 +15,7 @@ description: Latest features and improvements in LogLayer for Go. `loglayer`: -`Prefix` is now exposed as a separate field on `TransportParams` and on every dispatch-time plugin hook param struct (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`). Transports and plugins can render or react to the prefix independently from the message string. The legacy "prepend prefix into `Messages[0]`" behavior is preserved unchanged for backwards compatibility (and removed in v2.0.0). +`Prefix` is now exposed as a separate field on `TransportParams` and on every dispatch-time plugin hook param struct (`BeforeDataOutParams`, `BeforeMessageOutParams`, `TransformLogLevelParams`, `ShouldSendParams`). Transports and plugins can render or react to the prefix independently from the message string. The legacy "prepend prefix into `Messages[0]`" auto-mutation in v1.7.x stays in place for backwards compatibility within the v1 line; v2.0.0 removes it. `transports/cli`: diff --git a/loglayer.go b/loglayer.go index 1777bee..c60ebd6 100644 --- a/loglayer.go +++ b/loglayer.go @@ -86,7 +86,7 @@ type TransportParams struct { // // Empty string when no prefix was set. // - // Transports that want the v1 "prefix folded into Messages[0]" + // Transports that want a "prefix folded into Messages[0]" // rendering call [transport.JoinPrefixAndMessages] at the top // of SendToLogger; the helper has fast-path early returns for // the no-prefix case, so the per-call cost on a logger that @@ -129,11 +129,11 @@ type LogLayer struct { // prefix is the WithPrefix value for this logger, propagated to // every emission via TransportParams.Prefix and the dispatch- // time plugin hook param structs. Transports decide how to - // render it (most call transport.JoinPrefixAndMessages to - // preserve v1 "prefix folded into the message" behavior). - // Initialized from Config.Prefix at build time; WithPrefix - // mutates this field on a fresh child only. Same lifecycle as - // assignedGroups/boundCtx: never mutated post-publish. + // render it; most call transport.JoinPrefixAndMessages to + // fold it into the first message string. Initialized from + // Config.Prefix at build time; WithPrefix mutates this field + // on a fresh child only. Same lifecycle as assignedGroups / + // boundCtx: never mutated post-publish. prefix string // txMu serializes transport mutators (AddTransport / RemoveTransport / // SetTransports) so two concurrent admin operations on the same diff --git a/transport/helpers.go b/transport/helpers.go index 28dcd2b..e33af39 100644 --- a/transport/helpers.go +++ b/transport/helpers.go @@ -29,19 +29,14 @@ func WriterOrStdout(w io.Writer) io.Writer { return os.Stdout } -// JoinPrefixAndMessages preserves the legacy "prefix folded into the -// first message" rendering for transports that don't have a smart -// place to surface params.Prefix on its own. Returns messages -// unchanged when prefix is empty or messages[0] is not a string; -// otherwise returns a fresh slice whose first element is -// `prefix + " " + messages[0]`. +// JoinPrefixAndMessages folds prefix into the first message so the +// rendered output reads as one blob (`"[prefix] message body"`). +// Returns messages unchanged when prefix is empty or messages[0] is +// not a string; otherwise returns a fresh slice whose first element +// is `prefix + " " + messages[0]`. // -// Use case: most renderer/wrapper transports just want the v1 -// behavior where every log line shows `[prefix] message` in one -// blob. Pre-v2 the loglayer core mutated messages[0] before -// dispatch; from v2 onward it's the transport's job. Call this -// helper at the top of SendToLogger to keep the same user-visible -// output: +// Most renderer / wrapper transports want this rendering and call +// the helper at the top of SendToLogger: // // func (t *Transport) SendToLogger(p loglayer.TransportParams) { // if !t.ShouldProcess(p.LogLevel) { return } @@ -50,10 +45,11 @@ func WriterOrStdout(w io.Writer) io.Writer { // } // // Transports that want to render the prefix differently (cli's -// dim-color treatment, structured's separate JSON field, wrapper -// transports forwarding to the underlying logger's structured-field -// API) should NOT call this helper; instead consume p.Prefix -// directly and emit messages without the prefix prepended. +// dim-color treatment, a structured transport's separate JSON +// field, wrapper transports forwarding to the underlying logger's +// structured-field API) should NOT call this helper; instead +// consume p.Prefix directly and emit messages without the prefix +// folded in. func JoinPrefixAndMessages(prefix string, messages []any) []any { if prefix == "" || len(messages) == 0 { return messages diff --git a/transports/charmlog/charmlog.go b/transports/charmlog/charmlog.go index 50d81cc..a8cb5b6 100644 --- a/transports/charmlog/charmlog.go +++ b/transports/charmlog/charmlog.go @@ -58,8 +58,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) keyvals := make([]any, 0, transport.FieldEstimate(params)*2) diff --git a/transports/console/console.go b/transports/console/console.go index c4663de..b339db0 100644 --- a/transports/console/console.go +++ b/transports/console/console.go @@ -78,8 +78,8 @@ func (c *Transport) SendToLogger(params loglayer.TransportParams) { if !c.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) messages := buildMessages(params, c.cfg) fmt.Fprintln(c.writer(params.LogLevel), messages...) diff --git a/transports/gcplogging/gcplogging.go b/transports/gcplogging/gcplogging.go index cec1c80..be74e67 100644 --- a/transports/gcplogging/gcplogging.go +++ b/transports/gcplogging/gcplogging.go @@ -126,8 +126,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) entry := t.buildEntry(params) if t.cfg.Sync { diff --git a/transports/http/http.go b/transports/http/http.go index 7b63939..8c650e8 100644 --- a/transports/http/http.go +++ b/transports/http/http.go @@ -210,8 +210,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { t.cfg.OnError(ErrClosed, nil) return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. // Encoders that want the prefix as a separate field can read // it from params.Prefix in a future Entry.Prefix addition. entry := Entry{ diff --git a/transports/logrus/logrus.go b/transports/logrus/logrus.go index f30e2c9..c8a452d 100644 --- a/transports/logrus/logrus.go +++ b/transports/logrus/logrus.go @@ -83,8 +83,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) fields := logrus.Fields{} diff --git a/transports/otellog/otellog.go b/transports/otellog/otellog.go index 0a6ea7f..74c4f3c 100644 --- a/transports/otellog/otellog.go +++ b/transports/otellog/otellog.go @@ -148,8 +148,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) var rec otellog.Record diff --git a/transports/phuslu/phuslu.go b/transports/phuslu/phuslu.go index 724472c..3e0c5cc 100644 --- a/transports/phuslu/phuslu.go +++ b/transports/phuslu/phuslu.go @@ -65,8 +65,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) entry := t.logger.WithLevel(toPhusluLevel(params.LogLevel)) if entry == nil { diff --git a/transports/pretty/pretty.go b/transports/pretty/pretty.go index 5ab7d9a..ad72502 100644 --- a/transports/pretty/pretty.go +++ b/transports/pretty/pretty.go @@ -110,8 +110,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) combined := combineData(params) diff --git a/transports/sentry/sentry.go b/transports/sentry/sentry.go index 63c8fbc..bc2b0a8 100644 --- a/transports/sentry/sentry.go +++ b/transports/sentry/sentry.go @@ -73,8 +73,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) entry := entryForLevel(t.cfg.Logger, params.LogLevel) diff --git a/transports/slog/slog.go b/transports/slog/slog.go index 91e6a87..aba96ae 100644 --- a/transports/slog/slog.go +++ b/transports/slog/slog.go @@ -60,8 +60,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) attrs := make([]slog.Attr, 0, transport.FieldEstimate(params)) diff --git a/transports/structured/structured.go b/transports/structured/structured.go index 72d9d48..d7a58d7 100644 --- a/transports/structured/structured.go +++ b/transports/structured/structured.go @@ -125,8 +125,8 @@ func (s *Transport) SendToLogger(params loglayer.TransportParams) { if !s.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) messages := params.Messages if s.cfg.MessageFn != nil { diff --git a/transports/zap/zap.go b/transports/zap/zap.go index a99b0c3..8c40cb6 100644 --- a/transports/zap/zap.go +++ b/transports/zap/zap.go @@ -65,8 +65,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) fields := make([]zap.Field, 0, transport.FieldEstimate(params)) diff --git a/transports/zerolog/zerolog.go b/transports/zerolog/zerolog.go index bd4d527..b18648b 100644 --- a/transports/zerolog/zerolog.go +++ b/transports/zerolog/zerolog.go @@ -62,8 +62,8 @@ func (t *Transport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering; - // the core no longer mutates messages, transports own it now. + // Fold the prefix into Messages[0] for the rendered output; + // transports own this rendering choice. params.Messages = transport.JoinPrefixAndMessages(params.Prefix, params.Messages) event := t.logger.WithLevel(toZerologLevel(params.LogLevel)) if event == nil { diff --git a/types.go b/types.go index 25f7c0f..4dfcd3d 100644 --- a/types.go +++ b/types.go @@ -64,11 +64,11 @@ type Config struct { // Prefix is exposed verbatim on TransportParams.Prefix and on // every dispatch-time plugin hook param struct. Transports - // decide how to render it (most call - // transport.JoinPrefixAndMessages to preserve v1 "prefix - // folded into the message" behavior; cli renders the prefix - // in dim grey separate from the level color). Equivalent to - // calling WithPrefix on the freshly-constructed logger. + // decide how to render it: most call + // transport.JoinPrefixAndMessages to fold it into the first + // message string; cli renders it in dim grey separate from + // the level color. Equivalent to calling WithPrefix on the + // freshly-constructed logger. Prefix string // Disabled suppresses all log output when true. Defaults to false From 70c51b6cac7bf921f0670ab41645f46cb3c9898c Mon Sep 17 00:00:00 2001 From: Theo Gravity Date: Sat, 2 May 2026 15:36:05 -0700 Subject: [PATCH 7/8] docs: catch the three v1/v2 references the prior strip missed Round-3 reviewer found three sites where the sed sweep didn't match because their wording differed slightly from the canonical 'Preserve the v1 ... rendering' pattern: - dispatch.go formatLog GoDoc: 'preserve the v1 prepended-into- messages shape' -> 'fold it into the first message string'. - builder.go dispatch inline comment: same rewrite. - transports/testing/testing.go SendToLogger inline comment: reframed as 'Fold the prefix into Messages[0] so test fixtures see one rendered message string'. Plus three test/example files the regex missed: - example_test.go exampleTransport: comment reframed as 'Fold the prefix into the message so the examples render as one blob'. - loglayer_test.go TestPrefixSurfacedOnTransportParams: drop v2/v1 framing. - transports/cli/cli_test.go TestWithPrefixRendersInline: drop 'v2 contract' framing. --- builder.go | 7 +++---- dispatch.go | 4 ++-- example_test.go | 6 +++--- loglayer_test.go | 8 ++++---- transports/cli/cli_test.go | 4 ++-- transports/testing/testing.go | 7 +++---- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/builder.go b/builder.go index e051bf0..361e0af 100644 --- a/builder.go +++ b/builder.go @@ -167,10 +167,9 @@ func (b *LogBuilder) Panic(messages ...any) { } func (b *LogBuilder) dispatch(level LogLevel, messages []any, source *Source) { - // Prefix is no longer prepended into messages here — it flows - // through TransportParams.Prefix and each transport renders it - // however it wants (most call transport.JoinPrefixAndMessages - // to preserve the v1 prepended-into-messages shape). + // Prefix flows through TransportParams.Prefix and each transport + // renders it however it wants (most call transport.JoinPrefix- + // AndMessages to fold it into the first message string). // // Hot path: builder has no per-call groups, so pass the layer's // assigned groups straight through. mergeGroups is out-of-line and diff --git a/dispatch.go b/dispatch.go index 2f7d49e..8b35bb3 100644 --- a/dispatch.go +++ b/dispatch.go @@ -13,8 +13,8 @@ var osExit = os.Exit // formatLog hands the entry to processLog using the logger's // persistent fields. The prefix is propagated through // TransportParams.Prefix; transports decide how to render it (most -// call transport.JoinPrefixAndMessages to preserve the v1 prepended- -// into-messages shape). +// call transport.JoinPrefixAndMessages to fold it into the first +// message string). // // Per-call goCtx overrides the logger's bound ctx (when one is // provided), otherwise the bound ctx is passed through. source diff --git a/example_test.go b/example_test.go index 6ffa495..b5594b6 100644 --- a/example_test.go +++ b/example_test.go @@ -43,9 +43,9 @@ func (exampleTransport) SendToLogger(p loglayer.TransportParams) { parts = append(parts, fmt.Sprintf(`"level":%q`, p.LogLevel.String())) parts = append(parts, fmt.Sprintf(`"time":%q`, fixedTime())) - // Preserve the v1 "prefix folded into the message" rendering - // for these examples; in v2 the prefix arrives on p.Prefix and - // each transport decides how to render it. + // Fold the prefix into the message so the examples render as + // one blob; transports decide their own rendering, this one + // goes through the helper. msgs := transport.JoinPrefixAndMessages(p.Prefix, p.Messages) msg := "" if len(msgs) > 0 { diff --git a/loglayer_test.go b/loglayer_test.go index e615549..434db6f 100644 --- a/loglayer_test.go +++ b/loglayer_test.go @@ -127,10 +127,10 @@ func TestPrefixDoesNotAffectParent(t *testing.T) { } func TestPrefixSurfacedOnTransportParams(t *testing.T) { - // v2: Prefix is exposed verbatim on TransportParams.Prefix and - // is NO LONGER prepended into Messages[0]. Transports that - // want the v1 "prefix prepended into the message" behavior - // call transport.JoinPrefixAndMessages explicitly. + // Prefix is exposed verbatim on TransportParams.Prefix and is + // NOT folded into Messages[0] by the core. Transports that + // want a "prefix folded into the message" rendering call + // transport.JoinPrefixAndMessages explicitly. log, lib := setup(t) prefixed := log.WithPrefix("[auth]") prefixed.Info("starting") diff --git a/transports/cli/cli_test.go b/transports/cli/cli_test.go index 91c3aea..4593015 100644 --- a/transports/cli/cli_test.go +++ b/transports/cli/cli_test.go @@ -640,8 +640,8 @@ func TestNilElementBailsTableFastPath(t *testing.T) { } func TestWithPrefixRendersInline(t *testing.T) { - // v2 contract: WithPrefix renders between the level prefix - // and the message body, plain text when ColorNever. + // WithPrefix renders between the level prefix and the message + // body, plain text when ColorNever. log, stdout, stderr := makeLogger(t, clitr.Config{}) prefixed := log.WithPrefix("[auth]") diff --git a/transports/testing/testing.go b/transports/testing/testing.go index 287a1a3..769a721 100644 --- a/transports/testing/testing.go +++ b/transports/testing/testing.go @@ -130,10 +130,9 @@ func (t *TestTransport) SendToLogger(params loglayer.TransportParams) { if !t.ShouldProcess(params.LogLevel) { return } - // Preserve the v1 "prefix folded into Messages[0]" rendering so - // existing test fixtures keep their assertions. The Prefix field - // is also exposed on LogLine for tests that want the unmangled - // signal. + // Fold the prefix into Messages[0] so test fixtures see one + // rendered message string. The unmangled signal is also exposed + // on LogLine.Prefix for tests that want it separately. src := transport.JoinPrefixAndMessages(params.Prefix, params.Messages) messages := make([]any, len(src)) copy(messages, src) From a8214d982f76d0a45bb656dc6b25b737f48b77f6 Mon Sep 17 00:00:00 2001 From: Theo Gravity Date: Sat, 2 May 2026 15:40:14 -0700 Subject: [PATCH 8/8] docs: reflow builder.go comment so JoinPrefixAndMessages doesn't hyphen-wrap Round-4 reviewer's only finding was cosmetic: the prior comment hyphen-wrapped 'transport.JoinPrefix-\nAndMessages' across two lines, which is unusual in Go comments. Reflow the comment so the full identifier sits on one line. --- builder.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/builder.go b/builder.go index 361e0af..662b8bc 100644 --- a/builder.go +++ b/builder.go @@ -167,9 +167,10 @@ func (b *LogBuilder) Panic(messages ...any) { } func (b *LogBuilder) dispatch(level LogLevel, messages []any, source *Source) { - // Prefix flows through TransportParams.Prefix and each transport - // renders it however it wants (most call transport.JoinPrefix- - // AndMessages to fold it into the first message string). + // Prefix flows through TransportParams.Prefix; each transport + // renders it however it wants (most call the + // transport.JoinPrefixAndMessages helper to fold it into the + // first message string). // // Hot path: builder has no per-call groups, so pass the layer's // assigned groups straight through. mergeGroups is out-of-line and