From 2426ff3f5ed155a233b706a17e9bf9df559220a2 Mon Sep 17 00:00:00 2001 From: Pavel Ivanov Date: Tue, 6 Feb 2024 23:41:17 +0100 Subject: [PATCH] new: initial version --- .github/workflows/ci.yml | 57 + .golangci.yml | 79 + .vscode/launch.json | 23 + README.md | 28 +- attr.go | 108 + benchmark_test.go | 445 ++ doc/benchmark/README.md | 34 + doc/benchmark/logger/benchmark-lt-always.svg | 6387 +++++++++++++++++ doc/benchmark/logger/benchmark-lt-never.svg | 6387 +++++++++++++++++ doc/benchmark/logger/benchmark-lt-optimal.svg | 6387 +++++++++++++++++ doc/benchmark/logger/benchmark.log | 446 ++ doc/benchmark/slogc/benchmark-slogc.log | 183 + doc/benchmark/slogc/benchmark-slogc.svg | 6387 +++++++++++++++++ example/longterm/main.go | 16 + go.mod | 5 + go.sum | 2 + handler.go | 176 + internal/mock/attr.go | 42 + internal/mock/calllog.go | 56 + internal/mock/handler.go | 120 + internal/mock/record.go | 58 + internal/mock/util.go | 9 + logger.go | 427 ++ logger_test.go | 203 + slogc/README.md | 13 + slogc/benchmark_test.go | 223 + slogc/name.go | 50 + slogc/name_test.go | 227 + slogc/slogc.go | 86 + slogc/slogc_test.go | 198 + 30 files changed, 28860 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .golangci.yml create mode 100644 .vscode/launch.json create mode 100644 attr.go create mode 100644 benchmark_test.go create mode 100644 doc/benchmark/README.md create mode 100644 doc/benchmark/logger/benchmark-lt-always.svg create mode 100644 doc/benchmark/logger/benchmark-lt-never.svg create mode 100644 doc/benchmark/logger/benchmark-lt-optimal.svg create mode 100644 doc/benchmark/logger/benchmark.log create mode 100644 doc/benchmark/slogc/benchmark-slogc.log create mode 100644 doc/benchmark/slogc/benchmark-slogc.svg create mode 100644 example/longterm/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 handler.go create mode 100644 internal/mock/attr.go create mode 100644 internal/mock/calllog.go create mode 100644 internal/mock/handler.go create mode 100644 internal/mock/record.go create mode 100644 internal/mock/util.go create mode 100644 logger.go create mode 100644 logger_test.go create mode 100644 slogc/README.md create mode 100644 slogc/benchmark_test.go create mode 100644 slogc/name.go create mode 100644 slogc/name_test.go create mode 100644 slogc/slogc.go create mode 100644 slogc/slogc_test.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0672ca9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,57 @@ +name: Continuous Integration + +on: + push: + tags: + - v* + branches: + - master + - main + pull_request: + +permissions: + contents: read + +jobs: + linters: + name: Run linters + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: '1.21' + cache-dependency-path: | + go.sum + test/go.sum + - name: Lint . + uses: golangci/golangci-lint-action@v3 + with: + version: v1.56 + # Disable caching as a workaround for https://github.com/golangci/golangci-lint-action/issues/135. + # The line can be removed once the golangci-lint issue is resolved. + skip-pkg-cache: true + - name: Lint other modules + run: go list -m -f '{{.Dir}}/...' | golangci-lint run + + unit-tests: + name: Run unit tests + runs-on: ubuntu-latest + strategy: + matrix: + go: ['1.21'] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go }} + - name: Test + run: go list -m -f '{{.Dir}}/...' | xargs go test -race -coverprofile=cover.out -coverpkg=./... + + - name: Collect coverage + run: go tool cover -html=cover.out -o cover.html + + - name: Upload coverage to codecov.io + uses: codecov/codecov-action@v4 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..3f6a773 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,79 @@ +linters-settings: + dupl: + threshold: 150 + exhaustive: + default-signifies-exhaustive: false + funlen: + lines: 100 + statements: 50 + goconst: + min-len: 2 + min-occurrences: 2 + gocyclo: + min-complexity: 32 + goimports: + local-prefixes: github.com/pamburus + govet: + check-shadowing: false + lll: + line-length: 140 + maligned: + suggest-new: true + nolintlint: + allow-unused: false # report any unused nolint directives + require-explanation: true # require an explanation for nolint directives + require-specific: false # don't require nolint directives to be specific about which linter is being skipped + +linters: + # Please, do not use `enable-all`: it's deprecated and will be removed soon. + # Inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint. + disable-all: true + enable: + - asciicheck + - dupl + - errcheck + - exportloopref + - gocritic + - gocyclo + - godot + - gofmt + - goimports + - gosec + - gosimple + - govet + - ineffassign + - misspell + - nakedret + - nlreturn + - prealloc + - revive + - staticcheck + - stylecheck + - typecheck + - unconvert + - unparam + - unused + - vet + - vetshadow + - whitespace + +issues: + # Disable this option because it causes golint to hide almost all issues. + exclude-use-default: false + # Excluding configuration per-path, per-linter, per-text and per-source. + exclude-rules: + # The dot-imports linter is disabled for the test files because it is convenient to dot-import third-party testing frameworks. + - linters: [revive] + text: '^dot-imports: ' + paths: + - '*_test.go' + # The staticcheck linter reports that `nil` context is passed, but it is intentionally done for the sake of the tests. + - linters: [staticcheck] + text: '^SA1012:' + paths: + - '*_test.go' + # The duplicate lines in the benchmark_test.go file are expected because any attempt to deduplicate them would affect the performance of the benchmark. + - linters: [dupl] + text: 'lines are duplicate' + paths: + - 'benchmark_test.go' diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..0ccf1fd --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,23 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Go: Benchmark LogAfterWith", + "type": "go", + "request": "launch", + "mode": "test", + "program": "${workspaceFolder}", + "args": [ + "-test.run=^$", + "-test.bench=^BenchmarkLogger/slogx/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs$", + "-test.benchtime=1x" + ], + "env": { + "GOFLAGS": "-count=1" + } + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 6e2338d..8e47418 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,26 @@ -# slogx -Extensions and helpers for log/slog package. +# slogx [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] + +Module [slogx](https://pkg.go.dev/github.com/pamburus/slogx) provides extensions and helpers for the [log/slog](https://pkg.go.dev/log/slog) package. + +## Packages +* [slogx](./README.md) +* [slogc](slogc/README.md) + + +### Package slogx + +Package [slogx](https://pkg.go.dev/github.com/pamburus/slogx) provides [Logger](https://pkg.go.dev/github.com/pamburus/slogx#Logger) as an alternative to [slog.Logger](https://pkg.go.dev/log/slog#Logger), which focuses on performance and makes several design changes to improve it: +* It does not provide convenience methods for attributes that may affect performace. All methods accept attributes only as [slog.Attr](https://pkg.go.dev/log/slog#Attr). +* It provides an [option](https://pkg.go.dev/github.com/pamburus/slogx#Logger.WithSource) to disable the inclusion of [source](https://pkg.go.dev/log/slog#Source) information into the log [Record](https://pkg.go.dev/log/slog#Record). This can improve performance up to 100% in cases where the source information is not included by the [Handler](https://pkg.go.dev/log/slog#Handler) anyway. +* Its [With](https://pkg.go.dev/github.com/pamburus/slogx#Logger.With) method does not immediately call the [WithAttrs](https://pkg.go.dev/log/slog#Handler.WithAttrs) method of the handler, instead it buffers up to 4 attributes which are then will be added to each log [Record](https://pkg.go.dev/log/slog#Record). This improves performance if you need to define a temporary set of attributes in a function and log a few messages with those attributes a few times. It also significantly improves performance when the logger is disabled. It is because calling [WithAttrs](https://pkg.go.dev/log/slog#Handler.WithAttrs) is quite an expensive operation, especially if the [Handler](https://pkg.go.dev/log/slog#Handler) is wrapped several times. That is, each layer will call the underlying handler's [WithAttrs](https://pkg.go.dev/log/slog#Handler.WithAttrs) method and cause a lot of allocations. But what if the message is discarded because the logger is disabled? Yes, it will be a waste of CPU time. So for temporary [With](https://pkg.go.dev/github.com/pamburus/slogx#Logger.With) attribute sets, it is usually more efficient to hold them at the [Logger](https://pkg.go.dev/github.com/pamburus/slogx#Logger). If any of the [WithGroup](https://pkg.go.dev/github.com/pamburus/slogx#Logger.WithGroup), [Handler](https://pkg.go.dev/github.com/pamburus/slogx#Logger.Handler), or [LongTerm](https://pkg.go.dev/github.com/pamburus/slogx#Logger.LongTerm) methods are called later, the temporary attributes will be flushed using the [WithAttrs](https://pkg.go.dev/log/slog#Handler.WithAttrs) method. +* It provides the [WithLongTerm](https://pkg.go.dev/github.com/pamburus/slogx#Logger.WithLongTerm) method, which acts as a sequence of [With](https://pkg.go.dev/github.com/pamburus/slogx#Logger.With) and [LongTerm](https://pkg.go.dev/github.com/pamburus/slogx#Logger.LongTerm) method calls and is needed for cases where the resulting logger is intended to be reused multiple times and may reside in a rather long-lived context. + +## Performance +* See [benchmark results](doc/benchmark/README.md) for details. + +[doc-img]: https://pkg.go.dev/badge/github.com/pamburus/slogx +[doc]: https://pkg.go.dev/github.com/pamburus/slogx +[ci-img]: https://github.com/pamburus/slogx/actions/workflows/ci.yml/badge.svg +[ci]: https://github.com/pamburus/slogx/actions/workflows/ci.yml +[cov-img]: https://codecov.io/gh/pamburus/slogx/graph/badge.svg?token=0TF6JD4KDU +[cov]: https://codecov.io/gh/pamburus/slogx diff --git a/attr.go b/attr.go new file mode 100644 index 0000000..f7c34ab --- /dev/null +++ b/attr.go @@ -0,0 +1,108 @@ +package slogx + +import ( + "log/slog" + "slices" +) + +// ErrorAttr returns an attribute with the error. +func ErrorAttr(err error) slog.Attr { + return slog.Any(ErrorKey, err) +} + +const ( + // ErrorKey is the key used for the error attribute. + ErrorKey = "error" +) + +// AttrPack is a an optimized pack of attributes. +type AttrPack struct { + front [4]slog.Attr + nFront int + back []slog.Attr +} + +// Clone returns a copy of the AttrPack without a shared state. +func (r AttrPack) Clone() AttrPack { + r.back = slices.Clip(r.back) + + return r +} + +// Len returns the number of attributes in the AttrPack. +func (r AttrPack) Len() int { + return r.nFront + len(r.back) +} + +// Enumerate calls f on each Attr in the AttrPack. +func (r AttrPack) Enumerate(f func(slog.Attr) bool) { + for i := 0; i < r.nFront; i++ { + if !f(r.front[i]) { + return + } + } + for _, a := range r.back { + if !f(a) { + return + } + } +} + +// Add appends the given Attrs to the AttrPack's list of Attrs. +func (r *AttrPack) Add(attrs ...slog.Attr) { + var i int + for i = 0; i < len(attrs) && r.nFront < len(r.front); i++ { + a := attrs[i] + if isEmptyGroup(a.Value) { + continue + } + r.front[r.nFront] = a + r.nFront++ + } + if cap(r.back) > len(r.back) { + end := r.back[:len(r.back)+1][len(r.back)] + if !end.Equal(slog.Attr{}) { + panic("multiple copies of a slogx.AttrPack modified the shared state simultaneously, use Clone to avoid this") + } + } + ne := countEmptyGroups(attrs[i:]) + r.back = slices.Grow(r.back, len(attrs[i:])-ne) + for _, a := range attrs[i:] { + if !isEmptyGroup(a.Value) { + r.back = append(r.back, a) + } + } +} + +// Collect returns all the attributes in the AttrPack as a slice. +func (r *AttrPack) Collect() []slog.Attr { + attrs := make([]slog.Attr, 0, r.Len()) + r.Enumerate(func(a slog.Attr) bool { + attrs = append(attrs, a) + + return true + }) + + return attrs +} + +// --- + +func countEmptyGroups(as []slog.Attr) int { + n := 0 + for _, a := range as { + if isEmptyGroup(a.Value) { + n++ + } + } + + return n +} + +func isEmptyGroup(v slog.Value) bool { + if v.Kind() != slog.KindGroup { + return false + } + + return len(v.Group()) == 0 +} diff --git a/benchmark_test.go b/benchmark_test.go new file mode 100644 index 0000000..3cd6222 --- /dev/null +++ b/benchmark_test.go @@ -0,0 +1,445 @@ +package slogx_test + +import ( + "context" + "io" + "log/slog" + "testing" + + "github.com/pamburus/slogx" +) + +func BenchmarkLogger(b *testing.B) { + b.Run("slogx/AsIs", func(b *testing.B) { + benchmarkSLogXLogger(b, false) + }) + b.Run("slogx/LongTerm", func(b *testing.B) { + benchmarkSLogXLogger(b, true) + }) + b.Run("slog", benchmarkSLogLogger) +} + +func benchmarkSLogXLogger(b *testing.B, longTerm bool) { + testEnabled := func(b *testing.B, logger *slogx.Logger) { + b.Run("Enabled", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.Enabled(context.Background(), slog.LevelInfo) + } + }) + } + + testLogAttrs := func(b *testing.B, logger *slogx.Logger) { + b.Run("LogAttrs", func(b *testing.B) { + b.Run("NoAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.LogAttrs(context.Background(), slog.LevelInfo, "msg") + } + }) + b.Run("ThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.LogAttrs(context.Background(), slog.LevelInfo, "msg", slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + } + }) + }) + } + + testWith := func(b *testing.B, logger *slogx.Logger) { + b.Run("With", func(b *testing.B) { + b.Run("ThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + } + }) + b.Run("FiveAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + }) + } + + testWithLongTerm := func(b *testing.B, logger *slogx.Logger) { + b.Run("With", func(b *testing.B) { + b.Run("ThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.WithLongTerm(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + } + }) + b.Run("FiveAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.WithLongTerm(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + }) + } + + testWithAndLog := func(b *testing.B, logger *slogx.Logger) { + b.Run("LogWithAndLog", func(b *testing.B) { + b.Run("TwoAndThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv")) + logger.Log(slog.LevelInfo, "msg", slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + b.Run("ThreeAndFourAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + logger.Log(slog.LevelInfo, "msg", slog.String("d", "dv"), slog.String("e", "ev"), slog.String("f", "fv"), slog.String("g", "gv")) + } + }) + b.Run("FiveAndThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + logger.Log(slog.LevelInfo, "msg", slog.String("f", "fv"), slog.String("g", "gv"), slog.String("h", "hv")) + } + }) + }) + } + + testWithAndLogLongTerm := func(b *testing.B, logger *slogx.Logger) { + b.Run("LogWithAndLog", func(b *testing.B) { + b.Run("TwoAndThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := logger.WithLongTerm(slog.String("a", "av"), slog.String("b", "bv")) + logger.Log(slog.LevelInfo, "msg", slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + b.Run("ThreeAndFourAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := logger.WithLongTerm(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + logger.Log(slog.LevelInfo, "msg", slog.String("d", "dv"), slog.String("e", "ev"), slog.String("f", "fv"), slog.String("g", "gv")) + } + }) + b.Run("FiveAndThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := logger.WithLongTerm(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + logger.Log(slog.LevelInfo, "msg", slog.String("f", "fv"), slog.String("g", "gv"), slog.String("h", "hv")) + } + }) + }) + } + + testLogAfterWith := func(b *testing.B, logger *slogx.Logger) { + b.Run("LogAfterWith", func(b *testing.B) { + b.Run("TwoAndThreeAttrs", func(b *testing.B) { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.Log(slog.LevelInfo, "msg", slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + b.Run("ThreeAndFourAttrs", func(b *testing.B) { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.Log(slog.LevelInfo, "msg", slog.String("d", "dv"), slog.String("e", "ev"), slog.String("f", "fv"), slog.String("g", "gv")) + } + }) + b.Run("FiveAndThreeAttrs", func(b *testing.B) { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.Log(slog.LevelInfo, "msg", slog.String("f", "fv"), slog.String("g", "gv"), slog.String("h", "hv")) + } + }) + }) + } + + testLogAfterWithLongTerm := func(b *testing.B, logger *slogx.Logger) { + b.Run("LogAfterWith", func(b *testing.B) { + b.Run("TwoAndThreeAttrs", func(b *testing.B) { + logger := logger.WithLongTerm(slog.String("a", "av"), slog.String("b", "bv")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.Log(slog.LevelInfo, "msg", slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + b.Run("ThreeAndFourAttrs", func(b *testing.B) { + logger := logger.WithLongTerm(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.Log(slog.LevelInfo, "msg", slog.String("d", "dv"), slog.String("e", "ev"), slog.String("f", "fv"), slog.String("g", "gv")) + } + }) + b.Run("FiveAndThreeAttrs", func(b *testing.B) { + logger := logger.WithLongTerm(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.Log(slog.LevelInfo, "msg", slog.String("f", "fv"), slog.String("g", "gv"), slog.String("h", "hv")) + } + }) + }) + } + + testAllForLogger := func(b *testing.B, logger *slogx.Logger) { + testEnabled(b, logger) + testLogAttrs(b, logger) + if longTerm { + testWithLongTerm(b, logger) + testWithAndLogLongTerm(b, logger) + testLogAfterWithLongTerm(b, logger) + } else { + testWith(b, logger) + testWithAndLog(b, logger) + testLogAfterWith(b, logger) + } + } + + testWithSource := func(b *testing.B, handler slog.Handler, enabled bool) { + name := "WithSource" + if !enabled { + name = "WithoutSource" + } + + b.Run(name, func(b *testing.B) { + b.Run("Unwrapped", func(b *testing.B) { + logger := slogx.New(handler).WithSource(enabled) + testAllForLogger(b, logger) + }) + + b.Run("3xWrapped", func(b *testing.B) { + handler = wrapHandlerN(handler, 3) + logger := slogx.New(handler).WithSource(enabled) + testAllForLogger(b, logger) + }) + }) + } + + testAllForHandler := func(b *testing.B, handler slog.Handler) { + testWithSource(b, handler, false) + testWithSource(b, handler, true) + } + + b.Run("Discard", func(b *testing.B) { + b.Run("Disabled", func(b *testing.B) { + testAllForHandler(b, slogx.Discard()) + }) + b.Run("Enabled", func(b *testing.B) { + testAllForHandler(b, &enabledDiscardHandler{}) + }) + }) + + b.Run("JSON", func(b *testing.B) { + b.Run("Disabled", func(b *testing.B) { + testAllForHandler(b, slog.NewJSONHandler(io.Discard, &slog.HandlerOptions{Level: slog.LevelError})) + }) + b.Run("Enabled", func(b *testing.B) { + testAllForHandler(b, slog.NewJSONHandler(io.Discard, &slog.HandlerOptions{})) + }) + }) +} + +func benchmarkSLogLogger(b *testing.B) { + testEnabled := func(b *testing.B, logger *slog.Logger) { + b.Run("Enabled", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.Enabled(context.Background(), slog.LevelInfo) + } + }) + } + + testLogAttrs := func(b *testing.B, logger *slog.Logger) { + b.Run("LogAttrs", func(b *testing.B) { + b.Run("NoAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.LogAttrs(context.Background(), slog.LevelInfo, "msg") + } + }) + b.Run("ThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.LogAttrs(context.Background(), slog.LevelInfo, "msg", slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + } + }) + }) + } + + testWith := func(b *testing.B, logger *slog.Logger) { + b.Run("With", func(b *testing.B) { + b.Run("ThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + } + }) + b.Run("FiveAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + }) + } + + testWithAndLog := func(b *testing.B, logger *slog.Logger) { + b.Run("WithAndLog", func(b *testing.B) { + b.Run("TwoAndThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv")) + logger.LogAttrs(context.Background(), slog.LevelInfo, "msg", slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + b.Run("ThreeAndFourAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + logger.LogAttrs(context.Background(), slog.LevelInfo, "msg", slog.String("d", "dv"), slog.String("e", "ev"), slog.String("f", "fv"), slog.String("g", "gv")) + } + }) + b.Run("FiveAndThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + logger.LogAttrs(context.Background(), slog.LevelInfo, "msg", slog.String("f", "fv"), slog.String("g", "gv"), slog.String("h", "hv")) + } + }) + }) + } + + testLogAfterWith := func(b *testing.B, logger *slog.Logger) { + b.Run("LogAfterWith", func(b *testing.B) { + b.Run("TwoAndThreeAttrs", func(b *testing.B) { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.LogAttrs(context.Background(), slog.LevelInfo, "msg", slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + b.Run("ThreeAndFourAttrs", func(b *testing.B) { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.LogAttrs(context.Background(), slog.LevelInfo, "msg", slog.String("d", "dv"), slog.String("e", "ev"), slog.String("f", "fv"), slog.String("g", "gv")) + } + }) + b.Run("FiveAndThreeAttrs", func(b *testing.B) { + logger := logger.With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger.LogAttrs(context.Background(), slog.LevelInfo, "msg", slog.String("f", "fv"), slog.String("g", "gv"), slog.String("h", "hv")) + } + }) + }) + } + + testAllForLogger := func(b *testing.B, logger *slog.Logger) { + testEnabled(b, logger) + testLogAttrs(b, logger) + testWith(b, logger) + testWithAndLog(b, logger) + testLogAfterWith(b, logger) + } + + testAllForHandler := func(b *testing.B, handler slog.Handler) { + b.Run("WithSource", func(b *testing.B) { + b.Run("Unwrapped", func(b *testing.B) { + logger := slog.New(handler) + testAllForLogger(b, logger) + }) + + b.Run("3xWrapped", func(b *testing.B) { + handler = wrapHandlerN(handler, 3) + logger := slog.New(handler) + testAllForLogger(b, logger) + }) + }) + } + + b.Run("Discard", func(b *testing.B) { + b.Run("Disabled", func(b *testing.B) { + testAllForHandler(b, slogx.Discard()) + }) + b.Run("Enabled", func(b *testing.B) { + testAllForHandler(b, &enabledDiscardHandler{}) + }) + }) + + b.Run("JSON", func(b *testing.B) { + b.Run("Disabled", func(b *testing.B) { + testAllForHandler(b, slog.NewJSONHandler(io.Discard, &slog.HandlerOptions{Level: slog.LevelError})) + }) + b.Run("Enabled", func(b *testing.B) { + testAllForHandler(b, slog.NewJSONHandler(io.Discard, &slog.HandlerOptions{})) + }) + }) +} + +// --- + +func wrapHandlerN(handler slog.Handler, times int) slog.Handler { + for i := 0; i != times; i++ { + handler = wrapHandler(handler) + } + + return handler +} + +func wrapHandler(handler slog.Handler) slog.Handler { + return &testHandlerWrapper{handler} +} + +// --- + +type testHandlerWrapper struct { + base slog.Handler +} + +func (h *testHandlerWrapper) Enabled(ctx context.Context, level slog.Level) bool { + return h.base.Enabled(ctx, level) +} + +func (h *testHandlerWrapper) Handle(ctx context.Context, record slog.Record) error { + return h.base.Handle(ctx, record) +} + +func (h *testHandlerWrapper) WithAttrs(attrs []slog.Attr) slog.Handler { + if len(attrs) == 0 { + return h + } + + return &testHandlerWrapper{h.base.WithAttrs(attrs)} +} + +func (h *testHandlerWrapper) WithGroup(key string) slog.Handler { + if key == "" { + return h + } + + return &testHandlerWrapper{h.base.WithGroup(key)} +} + +//--- + +type enabledDiscardHandler struct{} + +func (h *enabledDiscardHandler) Enabled(context.Context, slog.Level) bool { + return true +} + +func (h *enabledDiscardHandler) Handle(context.Context, slog.Record) error { + return nil +} + +func (h *enabledDiscardHandler) WithAttrs([]slog.Attr) slog.Handler { + return h +} + +func (h *enabledDiscardHandler) WithGroup(string) slog.Handler { + return h +} diff --git a/doc/benchmark/README.md b/doc/benchmark/README.md new file mode 100644 index 0000000..c06f921 --- /dev/null +++ b/doc/benchmark/README.md @@ -0,0 +1,34 @@ +# Benchmark Results + +## Benchmarks of slogx.Logger using optimal selection of Logger.With or Logger.WithLongTerm method calls + +Performance of [slogx.Logger](https://pkg.go.dev/github.com/pamburus/slogx#Logger) compared to [slog.Logger](https://pkg.go.dev/log/slog#Logger) with [slog.JSONHandler](https://pkg.go.dev/log/slog#JSONHandler) as a backend. +Logger's [WithLongTerm](https://pkg.go.dev/github.com/pamburus/slogx#Logger.WithLongTerm) method is used in all LogAfterWith tests, as it is an optimal strategy for this use case. +Values are in nanoseconds per operation. + +![Benchmark](logger/benchmark-lt-optimal.svg) + +## Benchmarks of slogx.Logger using only Logger.With method calls + +Performance of [slogx.Logger](https://pkg.go.dev/github.com/pamburus/slogx#Logger) compared to [slog.Logger](https://pkg.go.dev/log/slog#Logger) with [slog.JSONHandler](https://pkg.go.dev/log/slog#JSONHandler) as a backend. +Logger's [WithLongTerm](https://pkg.go.dev/github.com/pamburus/slogx#Logger.WithLongTerm) method is never used in these tests, so LogAfterWith tests have significant performance degradation. +But at the same time in many other cases especially when the handler is disabled performance is significantly improved. For optimal performance use [WithLongTerm](https://pkg.go.dev/github.com/pamburus/slogx#Logger.WithLongTerm) when the resulting logger is planned to be used more than 3-4 times. +Values are in nanoseconds per operation. + +![Benchmark](logger/benchmark-lt-never.svg) + +## Benchmarks of slogx.Logger using only Logger.WithLongTerm method calls + +Performance of [slogx.Logger](https://pkg.go.dev/github.com/pamburus/slogx#Logger) compared to [slog.Logger](https://pkg.go.dev/log/slog#Logger) with [slog.JSONHandler](https://pkg.go.dev/log/slog#JSONHandler) as a backend. +Logger's [WithLongTerm](https://pkg.go.dev/github.com/pamburus/slogx#Logger.WithLongTerm) method is always used in these tests, so LogAfterWith tests do not have significant performance degradation. +But at the same time there is no significant performance improvements in other use cases as well. For optimal performance use [WithLongTerm](https://pkg.go.dev/github.com/pamburus/slogx#Logger.WithLongTerm) when the resulting logger is planned to be used more than 3-4 times. +Values are in nanoseconds per operation. + +![Benchmark](logger/benchmark-lt-always.svg) + +## Benchmarks of usage context.Context with slogc package instead of slofx.Logger + +Performance comparison of [slogc](https://pkg.go.dev/github.com/pamburus/slogx/slogc) usage against [slogx.Logger](https://pkg.go.dev/github.com/pamburus/slogx#Logger) with optimal usage of [WithLongTerm](https://pkg.go.dev/github.com/pamburus/slogx#Logger.WithLongTerm) calls. +Values are in nanoseconds per operation. + +![Benchmark](slogc/benchmark-slogc.svg) diff --git a/doc/benchmark/logger/benchmark-lt-always.svg b/doc/benchmark/logger/benchmark-lt-always.svg new file mode 100644 index 0000000..7bfae46 --- /dev/null +++ b/doc/benchmark/logger/benchmark-lt-always.svg @@ -0,0 +1,6387 @@ + +image/svg+xmlDisabled-Unwrapped-EnabledDisabled-Unwrapped-LogAttrs-NoAttrsDisabled-Unwrapped-LogAttrs-ThreeAttrsDisabled-Unwrapped-With-ThreeAttrsDisabled-Unwrapped-With-FiveAttrsDisabled-Unwrapped-WithAndLog-TwoAndThreeAttrsDisabled-Unwrapped-WithAndLog-ThreeAndFourAttrsDisabled-Unwrapped-WithAndLog-FiveAndThreeAttrsDisabled-Unwrapped-LogAfterWith-TwoAndThreeAttrsDisabled-Unwrapped-LogAfterWith-ThreeAndFourAttrsDisabled-Unwrapped-LogAfterWith-FiveAndThreeAttrsDisabled-3xWrapped-EnabledDisabled-3xWrapped-LogAttrs-NoAttrsDisabled-3xWrapped-LogAttrs-ThreeAttrsDisabled-3xWrapped-With-ThreeAttrsDisabled-3xWrapped-With-FiveAttrsDisabled-3xWrapped-WithAndLog-TwoAndThreeAttrsDisabled-3xWrapped-WithAndLog-ThreeAndFourAttrsDisabled-3xWrapped-WithAndLog-FiveAndThreeAttrsDisabled-3xWrapped-LogAfterWith-TwoAndThreeAttrsDisabled-3xWrapped-LogAfterWith-ThreeAndFourAttrsDisabled-3xWrapped-LogAfterWith-FiveAndThreeAttrsEnabled-Unwrapped-EnabledEnabled-Unwrapped-LogAttrs-NoAttrsEnabled-Unwrapped-LogAttrs-ThreeAttrsEnabled-Unwrapped-With-ThreeAttrsEnabled-Unwrapped-With-FiveAttrsEnabled-Unwrapped-WithAndLog-TwoAndThreeAttrsEnabled-Unwrapped-WithAndLog-ThreeAndFourAttrsEnabled-Unwrapped-WithAndLog-FiveAndThreeAttrsEnabled-Unwrapped-LogAfterWith-TwoAndThreeAttrsEnabled-Unwrapped-LogAfterWith-ThreeAndFourAttrsEnabled-Unwrapped-LogAfterWith-FiveAndThreeAttrsEnabled-3xWrapped-EnabledEnabled-3xWrapped-LogAttrs-NoAttrsEnabled-3xWrapped-LogAttrs-ThreeAttrsEnabled-3xWrapped-With-ThreeAttrsEnabled-3xWrapped-With-FiveAttrsEnabled-3xWrapped-WithAndLog-TwoAndThreeAttrsEnabled-3xWrapped-WithAndLog-ThreeAndFourAttrsEnabled-3xWrapped-WithAndLog-FiveAndThreeAttrsEnabled-3xWrapped-LogAfterWith-TwoAndThreeAttrsEnabled-3xWrapped-LogAfterWith-ThreeAndFourAttrsEnabled-3xWrapped-LogAfterWith-FiveAndThreeAttrs04008001200160078179271915791364116374752568450357597726941500127710786894696634812151815768552430745525157612161271049237269446912438068137441484131711876504766865154760773701139712231108588419659495215171567249744064947615751315126084353815924171243449489448112998789965047444029344264644271047909819590419417269215171567349844265047715751315126074363805884191243slogx-no-srcslogxslog diff --git a/doc/benchmark/logger/benchmark-lt-never.svg b/doc/benchmark/logger/benchmark-lt-never.svg new file mode 100644 index 0000000..8630404 --- /dev/null +++ b/doc/benchmark/logger/benchmark-lt-never.svg @@ -0,0 +1,6387 @@ + +image/svg+xmlDisabled-Unwrapped-EnabledDisabled-Unwrapped-LogAttrs-NoAttrsDisabled-Unwrapped-LogAttrs-ThreeAttrsDisabled-Unwrapped-With-ThreeAttrsDisabled-Unwrapped-With-FiveAttrsDisabled-Unwrapped-WithAndLog-TwoAndThreeAttrsDisabled-Unwrapped-WithAndLog-ThreeAndFourAttrsDisabled-Unwrapped-WithAndLog-FiveAndThreeAttrsDisabled-Unwrapped-LogAfterWith-TwoAndThreeAttrsDisabled-Unwrapped-LogAfterWith-ThreeAndFourAttrsDisabled-Unwrapped-LogAfterWith-FiveAndThreeAttrsDisabled-3xWrapped-EnabledDisabled-3xWrapped-LogAttrs-NoAttrsDisabled-3xWrapped-LogAttrs-ThreeAttrsDisabled-3xWrapped-With-ThreeAttrsDisabled-3xWrapped-With-FiveAttrsDisabled-3xWrapped-WithAndLog-TwoAndThreeAttrsDisabled-3xWrapped-WithAndLog-ThreeAndFourAttrsDisabled-3xWrapped-WithAndLog-FiveAndThreeAttrsDisabled-3xWrapped-LogAfterWith-TwoAndThreeAttrsDisabled-3xWrapped-LogAfterWith-ThreeAndFourAttrsDisabled-3xWrapped-LogAfterWith-FiveAndThreeAttrsEnabled-Unwrapped-EnabledEnabled-Unwrapped-LogAttrs-NoAttrsEnabled-Unwrapped-LogAttrs-ThreeAttrsEnabled-Unwrapped-With-ThreeAttrsEnabled-Unwrapped-With-FiveAttrsEnabled-Unwrapped-WithAndLog-TwoAndThreeAttrsEnabled-Unwrapped-WithAndLog-ThreeAndFourAttrsEnabled-Unwrapped-WithAndLog-FiveAndThreeAttrsEnabled-Unwrapped-LogAfterWith-TwoAndThreeAttrsEnabled-Unwrapped-LogAfterWith-ThreeAndFourAttrsEnabled-Unwrapped-LogAfterWith-FiveAndThreeAttrsEnabled-3xWrapped-EnabledEnabled-3xWrapped-LogAttrs-NoAttrsEnabled-3xWrapped-LogAttrs-ThreeAttrsEnabled-3xWrapped-With-ThreeAttrsEnabled-3xWrapped-With-FiveAttrsEnabled-3xWrapped-WithAndLog-TwoAndThreeAttrsEnabled-3xWrapped-WithAndLog-ThreeAndFourAttrsEnabled-3xWrapped-WithAndLog-FiveAndThreeAttrsEnabled-3xWrapped-LogAfterWith-TwoAndThreeAttrsEnabled-3xWrapped-LogAfterWith-ThreeAndFourAttrsEnabled-3xWrapped-LogAfterWith-FiveAndThreeAttrs040080012001600781792719157913641163747525684503575977269415001277107868946966348121518157685524307455251576121612710492372694469124311001005851118810448916833686518410879798261171102086668336604922151715855342693315751214138247406833124373567154582371457968334402924719656521806692559693342027121517158449426933157512141382463968331243slogx-no-srcslogxslog diff --git a/doc/benchmark/logger/benchmark-lt-optimal.svg b/doc/benchmark/logger/benchmark-lt-optimal.svg new file mode 100644 index 0000000..fdb5d86 --- /dev/null +++ b/doc/benchmark/logger/benchmark-lt-optimal.svg @@ -0,0 +1,6387 @@ + +image/svg+xmlDisabled-Unwrapped-EnabledDisabled-Unwrapped-LogAttrs-NoAttrsDisabled-Unwrapped-LogAttrs-ThreeAttrsDisabled-Unwrapped-With-ThreeAttrsDisabled-Unwrapped-With-FiveAttrsDisabled-Unwrapped-WithAndLog-TwoAndThreeAttrsDisabled-Unwrapped-WithAndLog-ThreeAndFourAttrsDisabled-Unwrapped-WithAndLog-FiveAndThreeAttrsDisabled-Unwrapped-LogAfterWith-TwoAndThreeAttrsDisabled-Unwrapped-LogAfterWith-ThreeAndFourAttrsDisabled-Unwrapped-LogAfterWith-FiveAndThreeAttrsDisabled-3xWrapped-EnabledDisabled-3xWrapped-LogAttrs-NoAttrsDisabled-3xWrapped-LogAttrs-ThreeAttrsDisabled-3xWrapped-With-ThreeAttrsDisabled-3xWrapped-With-FiveAttrsDisabled-3xWrapped-WithAndLog-TwoAndThreeAttrsDisabled-3xWrapped-WithAndLog-ThreeAndFourAttrsDisabled-3xWrapped-WithAndLog-FiveAndThreeAttrsDisabled-3xWrapped-LogAfterWith-TwoAndThreeAttrsDisabled-3xWrapped-LogAfterWith-ThreeAndFourAttrsDisabled-3xWrapped-LogAfterWith-FiveAndThreeAttrsEnabled-Unwrapped-EnabledEnabled-Unwrapped-LogAttrs-NoAttrsEnabled-Unwrapped-LogAttrs-ThreeAttrsEnabled-Unwrapped-With-ThreeAttrsEnabled-Unwrapped-With-FiveAttrsEnabled-Unwrapped-WithAndLog-TwoAndThreeAttrsEnabled-Unwrapped-WithAndLog-ThreeAndFourAttrsEnabled-Unwrapped-WithAndLog-FiveAndThreeAttrsEnabled-Unwrapped-LogAfterWith-TwoAndThreeAttrsEnabled-Unwrapped-LogAfterWith-ThreeAndFourAttrsEnabled-Unwrapped-LogAfterWith-FiveAndThreeAttrsEnabled-3xWrapped-EnabledEnabled-3xWrapped-LogAttrs-NoAttrsEnabled-3xWrapped-LogAttrs-ThreeAttrsEnabled-3xWrapped-With-ThreeAttrsEnabled-3xWrapped-With-FiveAttrsEnabled-3xWrapped-WithAndLog-TwoAndThreeAttrsEnabled-3xWrapped-WithAndLog-ThreeAndFourAttrsEnabled-3xWrapped-WithAndLog-FiveAndThreeAttrsEnabled-3xWrapped-LogAfterWith-TwoAndThreeAttrsEnabled-3xWrapped-LogAfterWith-ThreeAndFourAttrsEnabled-3xWrapped-LogAfterWith-FiveAndThreeAttrs040080012001600781792719157913641163747525684503575977269415001277107868946966348121518157685524307455251576121612710492372694469124380681374411881044891683368651847607737011171102086668336604922151715855342693315751315128247406833124344948944882371457968334402924426464427806692559693342027121517158449426933157513151282463968331243slogx-no-srcslogxslog diff --git a/doc/benchmark/logger/benchmark.log b/doc/benchmark/logger/benchmark.log new file mode 100644 index 0000000..0bc6556 --- /dev/null +++ b/doc/benchmark/logger/benchmark.log @@ -0,0 +1,446 @@ +❯ GOMAXPROCS=8 go test -bench=. -benchmem . | tab +goos: darwin +goarch: arm64 +pkg: github.com/pamburus/slogx +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/Enabled-8 549055641 2.066 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/LogAttrs/NoAttrs-8 400409530 2.995 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/LogAttrs/ThreeAttrs-8 100000000 11.03 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/With/ThreeAttrs-8 36792932 32.60 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/With/FiveAttrs-8 17381374 68.08 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 31074597 38.60 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 26637808 45.06 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 14870317 80.20 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 100000000 11.55 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 90591963 13.14 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 100000000 10.84 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/Enabled-8 320202615 3.755 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/LogAttrs/NoAttrs-8 213399945 5.649 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/LogAttrs/ThreeAttrs-8 90855746 13.28 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/With/ThreeAttrs-8 36824076 32.56 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/With/FiveAttrs-8 17569180 69.13 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 28737552 42.40 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 25077736 49.10 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 14341586 83.73 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 79263949 14.32 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 76538338 16.03 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 89620791 13.58 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/Enabled-8 583866078 2.066 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 403382755 2.968 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 100000000 11.23 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/With/ThreeAttrs-8 36678552 33.01 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/With/FiveAttrs-8 17477042 69.08 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 31251084 38.78 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 26480858 45.76 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 14723421 81.22 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 100000000 11.66 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 89273810 13.21 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 100000000 10.89 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/Enabled-8 317628094 3.781 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 212306133 5.662 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 90148462 13.43 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/With/ThreeAttrs-8 36685372 32.97 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/With/FiveAttrs-8 17489566 69.28 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 29116083 41.58 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 24394126 48.53 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 14382589 83.16 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 80176612 14.25 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 75447772 15.98 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 89741432 13.56 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/Enabled-8 580163485 2.073 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/LogAttrs/NoAttrs-8 18524997 64.39 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/LogAttrs/ThreeAttrs-8 14019169 83.91 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/With/ThreeAttrs-8 36953918 32.54 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/With/FiveAttrs-8 17370378 68.20 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 9024272 133.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 6206202 193.9 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 4683068 255.8 ns/op 176 B/op 2 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 10952660 109.7 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 7784992 153.7 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 6880113 174.5 ns/op 128 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/Enabled-8 320298660 3.749 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/LogAttrs/NoAttrs-8 14110528 85.06 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/LogAttrs/ThreeAttrs-8 12277412 98.09 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/With/ThreeAttrs-8 36839384 32.61 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/With/FiveAttrs-8 17415481 68.51 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 7486712 160.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 5461039 217.7 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 4250336 280.7 ns/op 176 B/op 2 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 9440074 127.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 6624410 180.5 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 5932606 202.9 ns/op 128 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/Enabled-8 588590779 2.039 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 4482115 268.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 4057387 295.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/With/ThreeAttrs-8 36552212 32.74 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/With/FiveAttrs-8 17421170 68.55 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 2863963 415.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 2416580 498.5 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 2023962 597.4 ns/op 176 B/op 2 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 3145999 381.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 2605563 458.0 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 2350112 517.9 ns/op 128 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/Enabled-8 319754073 3.749 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 4097119 294.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 3464898 320.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/With/ThreeAttrs-8 36640708 32.80 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/With/FiveAttrs-8 17421433 68.37 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 2722924 441.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 2305526 520.8 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 1936184 620.3 ns/op 176 B/op 2 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 2963370 405.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 2490098 481.9 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 2243935 537.0 ns/op 128 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/Enabled-8 466572812 2.536 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/LogAttrs/NoAttrs-8 294235437 4.083 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/LogAttrs/ThreeAttrs-8 100000000 11.82 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/With/ThreeAttrs-8 36802243 32.60 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/With/FiveAttrs-8 17501086 68.25 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 30483254 39.38 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 25856868 46.35 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 14618427 81.95 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 95600702 12.51 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 84747007 14.23 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 100000000 11.73 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/Enabled-8 237579303 5.076 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/LogAttrs/NoAttrs-8 180647156 6.630 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/LogAttrs/ThreeAttrs-8 81797499 14.59 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/With/ThreeAttrs-8 36894885 32.50 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/With/FiveAttrs-8 17569641 68.53 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 28598694 41.94 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 24269103 49.47 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 14198641 84.49 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 77833418 15.16 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 72366356 16.70 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 82881032 14.51 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/Enabled-8 479392288 2.573 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 295859811 4.072 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 100000000 11.83 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/With/ThreeAttrs-8 36583599 32.71 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/With/FiveAttrs-8 17489598 68.37 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 30225081 39.68 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 25797435 46.56 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 14693209 81.78 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 97151564 12.62 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 83878930 14.26 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 100000000 11.74 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/Enabled-8 237172488 5.071 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 178091559 6.669 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 81212090 14.84 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/With/ThreeAttrs-8 36417618 32.93 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/With/FiveAttrs-8 17336322 68.66 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 28617932 42.14 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 23679439 53.33 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 14149496 84.55 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 78819027 15.08 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 71845707 16.85 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 81493825 14.59 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/Enabled-8 513524780 2.246 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/LogAttrs/NoAttrs-8 4472592 271.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/LogAttrs/ThreeAttrs-8 2850897 420.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/With/ThreeAttrs-8 36305830 32.69 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/With/FiveAttrs-8 17390589 68.58 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 2150720 559.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 1739182 691.8 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 1488715 805.5 ns/op 176 B/op 2 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 2300025 521.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 1845928 655.6 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 1659528 719.3 ns/op 128 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/Enabled-8 292885356 4.094 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/LogAttrs/NoAttrs-8 4112197 291.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/LogAttrs/ThreeAttrs-8 2728689 439.7 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/With/ThreeAttrs-8 36627800 32.67 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/With/FiveAttrs-8 17094108 68.26 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 2071437 579.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 1688011 713.6 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 1417693 823.0 ns/op 176 B/op 2 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 2196582 544.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 1783719 670.6 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 1629112 735.4 ns/op 128 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/Enabled-8 528297097 2.279 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 2439686 491.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 1825096 660.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/With/ThreeAttrs-8 36706320 32.58 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/With/FiveAttrs-8 17429530 68.20 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 1388660 866.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 1000000 1020 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 1000000 1171 ns/op 176 B/op 2 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 1449766 825.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 1227997 979.4 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 1000000 1087 ns/op 128 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/Enabled-8 277280848 4.101 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 2309947 517.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 1747994 686.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/With/ThreeAttrs-8 36805111 32.58 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/With/FiveAttrs-8 17422213 68.35 ns/op 48 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 1345963 890.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 1000000 1044 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 1000000 1188 ns/op 176 B/op 2 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 1408926 851.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 1000000 1005 ns/op 80 B/op 1 allocs/op +BenchmarkLogger/slogx/AsIs/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 1000000 1100 ns/op 128 B/op 1 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/Enabled-8 587702328 2.041 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/LogAttrs/NoAttrs-8 407506668 2.944 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/LogAttrs/ThreeAttrs-8 100000000 11.04 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/With/ThreeAttrs-8 8508420 141.9 ns/op 352 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/With/FiveAttrs-8 5818174 208.1 ns/op 480 B/op 3 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 8606414 140.4 ns/op 304 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 7699959 156.5 ns/op 352 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 5426044 220.8 ns/op 480 B/op 3 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 100000000 11.17 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 84330606 14.23 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 100000000 11.75 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/Enabled-8 318777452 3.769 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/LogAttrs/NoAttrs-8 212265558 5.640 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/LogAttrs/ThreeAttrs-8 91536378 13.16 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/With/ThreeAttrs-8 6053050 196.4 ns/op 400 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/With/FiveAttrs-8 4543351 262.1 ns/op 528 B/op 6 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 5932218 199.7 ns/op 352 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 5523777 216.7 ns/op 400 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 4247532 281.0 ns/op 528 B/op 6 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 90632728 13.20 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 72694779 16.38 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 85004148 13.89 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/Enabled-8 587754861 2.042 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 402857883 2.972 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 100000000 11.05 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/With/ThreeAttrs-8 8499150 140.7 ns/op 352 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/With/FiveAttrs-8 5785545 207.0 ns/op 480 B/op 3 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 8617557 140.6 ns/op 304 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 7682854 157.1 ns/op 352 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 5428840 222.8 ns/op 480 B/op 3 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 100000000 11.20 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 84394862 14.18 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 100000000 11.73 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/Enabled-8 317201541 3.768 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 212381908 5.643 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 90195324 13.32 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/With/ThreeAttrs-8 6098727 197.6 ns/op 400 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/With/FiveAttrs-8 4564699 264.3 ns/op 528 B/op 6 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 5969928 199.8 ns/op 352 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 5542296 216.4 ns/op 400 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 4262991 282.0 ns/op 528 B/op 6 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 90620751 13.24 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 72974017 16.39 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 86109720 13.91 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/Enabled-8 587714799 2.042 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/LogAttrs/NoAttrs-8 19021966 63.47 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/LogAttrs/ThreeAttrs-8 14501232 82.81 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/With/ThreeAttrs-8 8455161 142.3 ns/op 352 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/With/FiveAttrs-8 5787733 207.1 ns/op 480 B/op 3 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 5492521 219.6 ns/op 304 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 5032946 237.7 ns/op 352 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 3976126 302.6 ns/op 480 B/op 3 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 14409596 83.52 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 15092716 79.54 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 15642472 76.74 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/Enabled-8 316597177 3.764 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/LogAttrs/NoAttrs-8 14035908 84.97 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/LogAttrs/ThreeAttrs-8 12214708 98.22 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/With/ThreeAttrs-8 6086157 197.5 ns/op 400 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/With/FiveAttrs-8 4541872 264.9 ns/op 528 B/op 6 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 4010720 299.0 ns/op 352 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 3743690 320.6 ns/op 400 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 3129361 383.4 ns/op 528 B/op 6 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 12276878 97.70 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 11549455 104.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 12226604 98.19 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/Enabled-8 588486265 2.041 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 4471360 268.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 4053648 294.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/With/ThreeAttrs-8 8463609 141.5 ns/op 352 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/With/FiveAttrs-8 5788839 207.8 ns/op 480 B/op 3 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 2496350 481.0 ns/op 304 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 2254041 530.5 ns/op 352 B/op 2 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 1898276 631.8 ns/op 480 B/op 3 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 3693012 327.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 3301468 362.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 3082455 389.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/Enabled-8 318359668 3.766 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 4089634 293.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 3748119 320.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/With/ThreeAttrs-8 6032706 197.1 ns/op 400 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/With/FiveAttrs-8 4535682 264.6 ns/op 528 B/op 6 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 2116975 566.7 ns/op 352 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 1938192 617.8 ns/op 400 B/op 5 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 1672126 720.8 ns/op 528 B/op 6 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 3433864 350.7 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 3100107 386.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 2901588 414.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/Enabled-8 470406453 2.599 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/LogAttrs/NoAttrs-8 293365478 4.108 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/LogAttrs/ThreeAttrs-8 100000000 11.84 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/With/ThreeAttrs-8 2877673 418.6 ns/op 560 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/With/FiveAttrs-8 2028979 587.5 ns/op 752 B/op 9 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 3128544 380.4 ns/op 512 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 2765625 435.8 ns/op 560 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 1972912 607.2 ns/op 752 B/op 9 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 99448540 12.04 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 77248659 15.43 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 94524166 12.60 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/Enabled-8 230797099 5.182 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/LogAttrs/NoAttrs-8 181159340 6.632 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/LogAttrs/ThreeAttrs-8 81881684 14.67 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/With/ThreeAttrs-8 2519102 476.8 ns/op 608 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/With/FiveAttrs-8 1857826 650.2 ns/op 800 B/op 12 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 2726487 442.1 ns/op 560 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 2406294 498.3 ns/op 608 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 1786905 672.5 ns/op 800 B/op 12 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 81468468 14.67 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 68892601 17.48 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 78085814 15.27 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/Enabled-8 483997171 2.570 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 293920978 4.092 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 99788638 11.95 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/With/ThreeAttrs-8 2850048 416.9 ns/op 560 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/With/FiveAttrs-8 2045512 592.1 ns/op 752 B/op 9 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 3159486 380.7 ns/op 512 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 2743636 435.2 ns/op 560 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 1980310 608.4 ns/op 752 B/op 9 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 99549950 12.05 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 77512910 15.49 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 94118878 12.72 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/Enabled-8 236846935 5.077 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 180159530 6.698 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 82637991 14.54 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/With/ThreeAttrs-8 2510024 475.9 ns/op 608 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/With/FiveAttrs-8 1860517 649.3 ns/op 800 B/op 12 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 2707279 439.6 ns/op 560 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 2410690 497.2 ns/op 608 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 1789221 671.6 ns/op 800 B/op 12 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 81325838 14.63 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 69011294 17.48 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 78603477 15.29 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/Enabled-8 530403344 2.255 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/LogAttrs/NoAttrs-8 4464576 268.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/LogAttrs/ThreeAttrs-8 2875759 417.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/With/ThreeAttrs-8 2891575 418.7 ns/op 560 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/With/FiveAttrs-8 2042058 590.0 ns/op 752 B/op 9 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 1468304 818.6 ns/op 512 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 1319166 908.5 ns/op 560 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 1000000 1047 ns/op 752 B/op 9 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 2809728 427.1 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 2585706 463.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 2813330 426.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/Enabled-8 293258505 4.075 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/LogAttrs/NoAttrs-8 4100019 292.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/LogAttrs/ThreeAttrs-8 2729404 439.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/With/ThreeAttrs-8 2516917 473.8 ns/op 608 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/With/FiveAttrs-8 1841642 650.1 ns/op 800 B/op 12 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 1336000 898.7 ns/op 560 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 1216598 986.7 ns/op 608 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 1000000 1129 ns/op 800 B/op 12 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 2682258 447.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 2456256 488.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 2675780 449.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/Enabled-8 531470430 2.251 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 2438672 494.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 1824122 658.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/With/ThreeAttrs-8 2884052 419.0 ns/op 560 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/With/FiveAttrs-8 2032161 587.8 ns/op 752 B/op 9 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-8 1000000 1108 ns/op 512 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-8 974899 1223 ns/op 560 B/op 7 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-8 848906 1397 ns/op 752 B/op 9 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 1711375 701.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 1547506 772.7 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 1573183 759.7 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/Enabled-8 290195532 4.130 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 2316030 515.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 1754522 685.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/With/ThreeAttrs-8 2516814 476.0 ns/op 608 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/With/FiveAttrs-8 1841646 649.6 ns/op 800 B/op 12 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-8 991912 1187 ns/op 560 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-8 887488 1317 ns/op 608 B/op 10 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-8 803221 1484 ns/op 800 B/op 12 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 1642080 744.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 1465856 812.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slogx/LongTerm/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 1492964 806.1 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/Enabled-8 594147277 2.004 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 370258758 3.265 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 100000000 10.99 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/With/ThreeAttrs-8 5789076 206.3 ns/op 448 B/op 7 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/With/FiveAttrs-8 3624445 324.3 ns/op 864 B/op 10 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/WithAndLog/TwoAndThreeAttrs-8 8450624 141.2 ns/op 240 B/op 5 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/WithAndLog/ThreeAndFourAttrs-8 5429814 219.0 ns/op 448 B/op 7 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/WithAndLog/FiveAndThreeAttrs-8 3540992 336.0 ns/op 864 B/op 10 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 100000000 11.01 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 81064648 14.45 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 100000000 10.98 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/Enabled-8 255787911 4.689 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 202358842 5.943 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 89179275 13.44 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/With/ThreeAttrs-8 4488261 265.8 ns/op 496 B/op 10 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/With/FiveAttrs-8 3171129 381.9 ns/op 912 B/op 13 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/WithAndLog/TwoAndThreeAttrs-8 6056856 198.0 ns/op 288 B/op 8 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/WithAndLog/ThreeAndFourAttrs-8 4350814 276.3 ns/op 496 B/op 10 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/WithAndLog/FiveAndThreeAttrs-8 3093800 388.0 ns/op 912 B/op 13 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 89087414 13.52 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 71156790 16.86 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 88464860 13.42 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/Enabled-8 593307247 2.027 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 4616235 259.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 4005786 299.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/With/ThreeAttrs-8 5818544 206.0 ns/op 448 B/op 7 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/With/FiveAttrs-8 3680156 324.0 ns/op 864 B/op 10 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/WithAndLog/TwoAndThreeAttrs-8 2552293 472.1 ns/op 240 B/op 5 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/WithAndLog/ThreeAndFourAttrs-8 2063244 582.0 ns/op 448 B/op 7 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/WithAndLog/FiveAndThreeAttrs-8 1656854 730.7 ns/op 864 B/op 10 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 3653109 328.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 3286243 365.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 3068613 390.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/Enabled-8 256875912 4.671 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 4200636 285.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 3677293 326.1 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/With/ThreeAttrs-8 4611499 260.9 ns/op 496 B/op 10 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/With/FiveAttrs-8 3174752 377.3 ns/op 912 B/op 13 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/WithAndLog/TwoAndThreeAttrs-8 2166379 554.5 ns/op 288 B/op 8 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/WithAndLog/ThreeAndFourAttrs-8 1810603 668.4 ns/op 496 B/op 10 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/WithAndLog/FiveAndThreeAttrs-8 1484910 804.3 ns/op 912 B/op 13 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 3389518 355.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 3072781 390.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 2865369 417.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/Enabled-8 415956975 2.890 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 281147809 4.310 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 100000000 11.97 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/With/ThreeAttrs-8 2541174 468.8 ns/op 656 B/op 12 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/With/FiveAttrs-8 1731087 693.7 ns/op 1136 B/op 16 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/WithAndLog/TwoAndThreeAttrs-8 3226952 371.6 ns/op 448 B/op 10 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/WithAndLog/ThreeAndFourAttrs-8 2444688 491.5 ns/op 656 B/op 12 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/WithAndLog/FiveAndThreeAttrs-8 1700746 710.1 ns/op 1136 B/op 16 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 100000000 11.90 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 76323132 15.66 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 100000000 11.92 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/Enabled-8 213524444 5.622 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 175090984 6.860 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 82043803 14.67 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/With/ThreeAttrs-8 2278458 524.5 ns/op 704 B/op 15 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/With/FiveAttrs-8 1601876 744.5 ns/op 1184 B/op 19 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/WithAndLog/TwoAndThreeAttrs-8 2804304 430.4 ns/op 496 B/op 13 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/WithAndLog/ThreeAndFourAttrs-8 2184435 551.5 ns/op 704 B/op 15 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/WithAndLog/FiveAndThreeAttrs-8 1560952 767.6 ns/op 1184 B/op 19 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 81010831 14.95 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 66942958 17.76 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 82719872 14.73 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/Enabled-8 550210532 2.185 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/LogAttrs/NoAttrs-8 2480950 481.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/LogAttrs/ThreeAttrs-8 1810926 662.7 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/With/ThreeAttrs-8 2566536 469.0 ns/op 656 B/op 12 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/With/FiveAttrs-8 1739553 689.0 ns/op 1136 B/op 16 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/WithAndLog/TwoAndThreeAttrs-8 1000000 1078 ns/op 448 B/op 10 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/WithAndLog/ThreeAndFourAttrs-8 946154 1277 ns/op 656 B/op 12 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/WithAndLog/FiveAndThreeAttrs-8 802561 1500 ns/op 1136 B/op 16 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-8 1730617 693.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-8 1554423 772.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-8 1588707 758.7 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/Enabled-8 240605482 4.985 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/LogAttrs/NoAttrs-8 2382015 502.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/LogAttrs/ThreeAttrs-8 1753304 684.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/With/ThreeAttrs-8 2285960 524.9 ns/op 704 B/op 15 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/With/FiveAttrs-8 1607612 747.0 ns/op 1184 B/op 19 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/WithAndLog/TwoAndThreeAttrs-8 1000000 1163 ns/op 496 B/op 13 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/WithAndLog/ThreeAndFourAttrs-8 888649 1364 ns/op 704 B/op 15 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/WithAndLog/FiveAndThreeAttrs-8 751208 1579 ns/op 1184 B/op 19 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-8 1666695 719.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-8 1512511 792.1 ns/op 0 B/op 0 allocs/op +BenchmarkLogger/slog/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-8 1532436 781.3 ns/op 0 B/op 0 allocs/op +PASS +ok github.com/pamburus/slogx 650.935s \ No newline at end of file diff --git a/doc/benchmark/slogc/benchmark-slogc.log b/doc/benchmark/slogc/benchmark-slogc.log new file mode 100644 index 0000000..3f5cdd1 --- /dev/null +++ b/doc/benchmark/slogc/benchmark-slogc.log @@ -0,0 +1,183 @@ +Running tool: go test -benchmem -run=^$ -bench ^BenchmarkLogging$ github.com/pamburus/slogx/slogc + +goos: darwin +goarch: arm64 +pkg: github.com/pamburus/slogx/slogc +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/Enabled-10 302408304 3.797 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/Log/NoAttrs-10 157477438 7.503 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/Log/ThreeAttrs-10 78319825 15.28 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/With/ThreeAttrs-10 6996752 172.1 ns/op 400 B/op 3 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/With/FiveAttrs-10 5013043 239.0 ns/op 528 B/op 4 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-10 28902226 41.46 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-10 24543411 48.82 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-10 14250596 84.07 ns/op 48 B/op 1 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-10 77948863 15.37 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-10 64540129 18.68 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-10 73791470 16.07 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/Enabled-10 181182806 6.623 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/Log/NoAttrs-10 100000000 10.03 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/Log/ThreeAttrs-10 67012588 17.77 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/With/ThreeAttrs-10 5278203 224.5 ns/op 448 B/op 6 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/With/FiveAttrs-10 4088248 293.0 ns/op 576 B/op 7 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-10 27028928 44.47 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-10 23343142 51.33 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-10 13770817 88.89 ns/op 48 B/op 1 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-10 56577974 20.94 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-10 56817844 21.40 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-10 55630888 19.99 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/Enabled-10 321027108 3.741 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/Log/NoAttrs-10 160871287 7.453 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/Log/ThreeAttrs-10 78076710 15.24 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/With/ThreeAttrs-10 7012234 179.3 ns/op 400 B/op 3 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/With/FiveAttrs-10 4823457 243.7 ns/op 528 B/op 4 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-10 28433266 41.68 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-10 24584601 49.14 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-10 14195016 85.28 ns/op 48 B/op 1 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-10 77999529 15.30 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-10 64907113 18.43 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-10 73048242 15.99 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/Enabled-10 179969494 6.654 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/Log/NoAttrs-10 122238222 9.812 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/Log/ThreeAttrs-10 67251379 17.84 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/With/ThreeAttrs-10 5292042 225.7 ns/op 448 B/op 6 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/With/FiveAttrs-10 4111309 293.8 ns/op 576 B/op 7 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-10 27066600 44.39 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-10 23373037 51.39 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-10 13711099 87.04 ns/op 48 B/op 1 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-10 67181413 19.19 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-10 56805180 21.19 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Disabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-10 56811120 20.14 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/Enabled-10 320391802 3.746 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/Log/NoAttrs-10 18869320 63.66 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/Log/ThreeAttrs-10 15204692 79.07 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/With/ThreeAttrs-10 7060116 170.4 ns/op 400 B/op 3 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/With/FiveAttrs-10 5051988 237.8 ns/op 528 B/op 4 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-10 8759362 137.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-10 6007807 200.1 ns/op 80 B/op 1 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-10 4551891 261.7 ns/op 176 B/op 2 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-10 15221882 78.74 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-10 14006725 85.99 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-10 15246370 80.04 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/Enabled-10 179932008 6.677 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/Log/NoAttrs-10 13658312 88.27 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/Log/ThreeAttrs-10 11387404 104.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/With/ThreeAttrs-10 5350111 224.5 ns/op 448 B/op 6 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/With/FiveAttrs-10 4105117 299.3 ns/op 576 B/op 7 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-10 7371069 164.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-10 5184034 221.6 ns/op 80 B/op 1 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-10 4147477 288.9 ns/op 176 B/op 2 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-10 11396443 105.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-10 10680230 111.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-10 11351793 105.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/Enabled-10 320614688 3.765 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/Log/NoAttrs-10 4063066 295.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/Log/ThreeAttrs-10 3460381 346.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/With/ThreeAttrs-10 6959058 172.0 ns/op 400 B/op 3 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/With/FiveAttrs-10 5031410 238.4 ns/op 528 B/op 4 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-10 2872258 420.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-10 2407125 497.1 ns/op 80 B/op 1 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-10 1991977 604.2 ns/op 176 B/op 2 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-10 3307240 362.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-10 3063679 391.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-10 3059085 392.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/Enabled-10 182764054 6.579 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/Log/NoAttrs-10 3745584 326.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/Log/ThreeAttrs-10 3233496 370.1 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/With/ThreeAttrs-10 5287141 224.7 ns/op 448 B/op 6 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/With/FiveAttrs-10 4043258 293.1 ns/op 576 B/op 7 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-10 2705053 449.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-10 2292948 527.6 ns/op 80 B/op 1 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-10 1823280 635.8 ns/op 176 B/op 2 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-10 3071106 392.1 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-10 2851533 421.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/Discard/Enabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-10 2805516 425.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/Enabled-10 221369793 5.410 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/Log/NoAttrs-10 133056931 8.917 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/Log/ThreeAttrs-10 73210350 16.42 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/With/ThreeAttrs-10 2603835 467.6 ns/op 608 B/op 8 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/With/FiveAttrs-10 1867736 638.9 ns/op 800 B/op 10 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-10 28106006 42.78 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-10 24151105 49.89 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-10 13905579 86.30 ns/op 48 B/op 1 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-10 73311171 16.33 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-10 60841513 19.83 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-10 70795938 16.99 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/Enabled-10 142398338 8.359 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/Log/NoAttrs-10 100000000 10.99 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/Log/ThreeAttrs-10 62287375 18.90 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/With/ThreeAttrs-10 2340777 511.6 ns/op 656 B/op 11 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/With/FiveAttrs-10 1727594 712.5 ns/op 848 B/op 13 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-10 26753266 45.01 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-10 22806172 52.29 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-10 13534514 88.72 ns/op 48 B/op 1 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-10 64370343 18.57 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-10 53694178 22.31 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-10 61154548 19.80 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/Enabled-10 221955276 5.390 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/Log/NoAttrs-10 134528506 9.001 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/Log/ThreeAttrs-10 73236040 16.40 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/With/ThreeAttrs-10 2641196 455.4 ns/op 608 B/op 8 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/With/FiveAttrs-10 1872402 641.0 ns/op 800 B/op 10 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-10 27977896 42.80 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-10 24107882 49.89 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-10 13871181 86.36 ns/op 48 B/op 1 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-10 73316205 16.30 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-10 60876106 19.81 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-10 70466990 16.97 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/Enabled-10 142236157 8.382 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/Log/NoAttrs-10 100000000 11.12 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/Log/ThreeAttrs-10 62619177 19.19 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/With/ThreeAttrs-10 2337238 518.1 ns/op 656 B/op 11 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/With/FiveAttrs-10 1720125 704.2 ns/op 848 B/op 13 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-10 26727421 44.97 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-10 22960372 52.54 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-10 13569025 88.78 ns/op 48 B/op 1 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-10 64280836 18.60 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-10 54039144 22.29 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Disabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-10 60986455 19.58 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/Enabled-10 275437646 4.403 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/Log/NoAttrs-10 4315434 278.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/Log/ThreeAttrs-10 2785440 431.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/With/ThreeAttrs-10 2613122 454.8 ns/op 608 B/op 8 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/With/FiveAttrs-10 1875732 637.0 ns/op 800 B/op 10 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-10 2122630 565.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-10 1720545 696.8 ns/op 80 B/op 1 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-10 1473368 814.9 ns/op 176 B/op 2 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-10 2740965 442.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-10 2456793 488.1 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-10 2749677 440.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/Enabled-10 160578510 7.422 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/Log/NoAttrs-10 3986242 299.1 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/Log/ThreeAttrs-10 2704306 444.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/With/ThreeAttrs-10 2327130 512.8 ns/op 656 B/op 11 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/With/FiveAttrs-10 1721772 695.2 ns/op 848 B/op 13 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-10 2045834 586.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-10 1675624 716.4 ns/op 80 B/op 1 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-10 1426124 839.6 ns/op 176 B/op 2 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-10 2649457 455.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-10 2405959 511.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithoutSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-10 2620563 453.8 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/Enabled-10 269167129 4.466 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/Log/NoAttrs-10 2302797 522.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/Log/ThreeAttrs-10 1651009 726.0 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/With/ThreeAttrs-10 2635567 455.0 ns/op 608 B/op 8 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/With/FiveAttrs-10 1878526 638.6 ns/op 800 B/op 10 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/LogWithAndLog/TwoAndThreeAttrs-10 1366870 876.6 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/LogWithAndLog/ThreeAndFourAttrs-10 1000000 1029 ns/op 80 B/op 1 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/LogWithAndLog/FiveAndThreeAttrs-10 1000000 1191 ns/op 176 B/op 2 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/TwoAndThreeAttrs-10 1637605 734.2 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/ThreeAndFourAttrs-10 1465765 819.1 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/Unwrapped/LogAfterWith/FiveAndThreeAttrs-10 1557883 769.3 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/Enabled-10 159909810 7.505 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/Log/NoAttrs-10 2187394 548.9 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/Log/ThreeAttrs-10 1624827 739.5 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/With/ThreeAttrs-10 2339976 512.8 ns/op 656 B/op 11 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/With/FiveAttrs-10 1724787 695.0 ns/op 848 B/op 13 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/LogWithAndLog/TwoAndThreeAttrs-10 1333200 898.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/LogWithAndLog/ThreeAndFourAttrs-10 1000000 1047 ns/op 80 B/op 1 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/LogWithAndLog/FiveAndThreeAttrs-10 993201 1205 ns/op 176 B/op 2 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/TwoAndThreeAttrs-10 1577520 761.1 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/ThreeAndFourAttrs-10 1411441 895.4 ns/op 0 B/op 0 allocs/op +BenchmarkLogging/JSON/Enabled/WithSource/3xWrapped/LogAfterWith/FiveAndThreeAttrs-10 1503277 806.8 ns/op 0 B/op 0 allocs/op +PASS +ok github.com/pamburus/slogx/slogc 266.852s \ No newline at end of file diff --git a/doc/benchmark/slogc/benchmark-slogc.svg b/doc/benchmark/slogc/benchmark-slogc.svg new file mode 100644 index 0000000..0162265 --- /dev/null +++ b/doc/benchmark/slogc/benchmark-slogc.svg @@ -0,0 +1,6387 @@ + +image/svg+xmlDisabled-Unwrapped-EnabledDisabled-Unwrapped-LogAttrs-NoAttrsDisabled-Unwrapped-LogAttrs-ThreeAttrsDisabled-Unwrapped-With-ThreeAttrsDisabled-Unwrapped-With-FiveAttrsDisabled-Unwrapped-WithAndLog-TwoAndThreeAttrsDisabled-Unwrapped-WithAndLog-ThreeAndFourAttrsDisabled-Unwrapped-WithAndLog-FiveAndThreeAttrsDisabled-Unwrapped-LogAfterWith-TwoAndThreeAttrsDisabled-Unwrapped-LogAfterWith-ThreeAndFourAttrsDisabled-Unwrapped-LogAfterWith-FiveAndThreeAttrsDisabled-3xWrapped-EnabledDisabled-3xWrapped-LogAttrs-NoAttrsDisabled-3xWrapped-LogAttrs-ThreeAttrsDisabled-3xWrapped-With-ThreeAttrsDisabled-3xWrapped-With-FiveAttrsDisabled-3xWrapped-WithAndLog-TwoAndThreeAttrsDisabled-3xWrapped-WithAndLog-ThreeAndFourAttrsDisabled-3xWrapped-WithAndLog-FiveAndThreeAttrsDisabled-3xWrapped-LogAfterWith-TwoAndThreeAttrsDisabled-3xWrapped-LogAfterWith-ThreeAndFourAttrsDisabled-3xWrapped-LogAfterWith-FiveAndThreeAttrsEnabled-Unwrapped-EnabledEnabled-Unwrapped-LogAttrs-NoAttrsEnabled-Unwrapped-LogAttrs-ThreeAttrsEnabled-Unwrapped-With-ThreeAttrsEnabled-Unwrapped-With-FiveAttrsEnabled-Unwrapped-WithAndLog-TwoAndThreeAttrsEnabled-Unwrapped-WithAndLog-ThreeAndFourAttrsEnabled-Unwrapped-WithAndLog-FiveAndThreeAttrsEnabled-Unwrapped-LogAfterWith-TwoAndThreeAttrsEnabled-Unwrapped-LogAfterWith-ThreeAndFourAttrsEnabled-Unwrapped-LogAfterWith-FiveAndThreeAttrsEnabled-3xWrapped-EnabledEnabled-3xWrapped-LogAttrs-NoAttrsEnabled-3xWrapped-LogAttrs-ThreeAttrsEnabled-3xWrapped-With-ThreeAttrsEnabled-3xWrapped-With-FiveAttrsEnabled-3xWrapped-WithAndLog-TwoAndThreeAttrsEnabled-3xWrapped-WithAndLog-ThreeAndFourAttrsEnabled-3xWrapped-WithAndLog-FiveAndThreeAttrsEnabled-3xWrapped-LogAfterWith-TwoAndThreeAttrsEnabled-3xWrapped-LogAfterWith-ThreeAndFourAttrsEnabled-3xWrapped-LogAfterWith-FiveAndThreeAttrs0350700105014008068137441188104489165047668651847607737011171102086658841966049221517158553426494761575131512824740592417124380789576112051047898695513740549876981973411911029877639455726523420221989534570451819118172016865043641455169545451145684071658669551344429974414884428156975656374554312794202219895245713512191181720168650436394681695slogc-no-srcslogcslogx diff --git a/example/longterm/main.go b/example/longterm/main.go new file mode 100644 index 0000000..65ca82b --- /dev/null +++ b/example/longterm/main.go @@ -0,0 +1,16 @@ +// Package main provides an example of using the slogx logger. +package main + +import ( + "log/slog" + "os" + + "github.com/pamburus/slogx" +) + +func main() { + logger := slogx.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{})) + + l1 := logger.With(slog.String("a", "av"), slog.String("b", "bv")).LongTerm() + l1.Log(slog.LevelInfo, "msg", slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..63eb084 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/pamburus/slogx + +go 1.21.5 + +require github.com/pamburus/go-tst v0.2.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..10ec275 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/pamburus/go-tst v0.2.0 h1:C6C0l6N/DXeGfX9vUNMDvko3i7ApUkundDUQK3bSKP4= +github.com/pamburus/go-tst v0.2.0/go.mod h1:Jbmc83QXCwwfX4E2HhZ8n7tVM8tHbs6RhIl1CdayMls= diff --git a/handler.go b/handler.go new file mode 100644 index 0000000..887e8fa --- /dev/null +++ b/handler.go @@ -0,0 +1,176 @@ +package slogx + +import ( + "context" + "errors" + "log/slog" +) + +// Join returns a new handler that joins the provided handlers. +func Join(handlers ...slog.Handler) slog.Handler { + switch len(handlers) { + case 0: + return Discard() + case 1: + return handlers[0] + } + + return &multiHandler{handlers} +} + +// Discard returns a handler that discards all log records. +func Discard() slog.Handler { + return discardHandlerInstance +} + +// TweakHandler returns a builder for a new handler based on existing handler. +func TweakHandler(handler slog.Handler) TweakHandlerBuilder { + return TweakHandlerBuilder{handler, handlerTweaks{}} +} + +// --- + +// TweakHandlerBuilder is a builder for a new handler based on existing handler. +type TweakHandlerBuilder struct { + handler slog.Handler + tweaks handlerTweaks +} + +// WithDynamicAttr adds a dynamic attribute to the handler. +func (b TweakHandlerBuilder) WithDynamicAttr(attr func(context.Context) slog.Attr) TweakHandlerBuilder { + b.tweaks.dynamicAttrs = append(b.tweaks.dynamicAttrs, attr) + + return b +} + +// Result returns the new handler. +func (b TweakHandlerBuilder) Result() slog.Handler { + return &tweakedHandler{b.handler, b.tweaks} +} + +// --- + +type handlerTweaks struct { + dynamicAttrs []func(context.Context) slog.Attr +} + +// --- + +type tweakedHandler struct { + base slog.Handler + handlerTweaks +} + +func (h *tweakedHandler) Enabled(ctx context.Context, level slog.Level) bool { + return h.base.Enabled(ctx, level) +} + +func (h *tweakedHandler) Handle(ctx context.Context, record slog.Record) error { + if len(h.dynamicAttrs) != 0 { + record = record.Clone() + for _, attr := range h.dynamicAttrs { + if attr := attr(ctx); !attr.Equal(slog.Attr{}) { + record.AddAttrs(attr) + } + } + } + + return h.base.Handle(ctx, record) +} + +func (h *tweakedHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + if len(attrs) == 0 { + return h + } + + return &tweakedHandler{h.base.WithAttrs(attrs), h.handlerTweaks} +} + +func (h *tweakedHandler) WithGroup(key string) slog.Handler { + if key == "" { + return h + } + + return &tweakedHandler{h.base.WithGroup(key), h.handlerTweaks} +} + +// --- + +var discardHandlerInstance = &discardHandler{} + +// --- + +type discardHandler struct{} + +func (h *discardHandler) Enabled(context.Context, slog.Level) bool { + return false +} + +func (h *discardHandler) Handle(context.Context, slog.Record) error { + return nil +} + +func (h *discardHandler) WithAttrs([]slog.Attr) slog.Handler { + return h +} + +func (h *discardHandler) WithGroup(string) slog.Handler { + return h +} + +// --- + +type multiHandler struct { + handlers []slog.Handler +} + +func (h *multiHandler) Enabled(ctx context.Context, level slog.Level) bool { + for _, handler := range h.handlers { + if handler.Enabled(ctx, level) { + return true + } + } + + return false +} + +func (h *multiHandler) Handle(ctx context.Context, record slog.Record) error { + var errs []error + + for _, handler := range h.handlers { + if handler.Enabled(ctx, record.Level) { + err := handler.Handle(ctx, record) + if err != nil { + errs = append(errs, err) + } + } + } + + return errors.Join(errs...) +} + +func (h *multiHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + if len(attrs) == 0 { + return h + } + + handlers := make([]slog.Handler, len(h.handlers)) + for i, handler := range h.handlers { + handlers[i] = handler.WithAttrs(attrs) + } + + return &multiHandler{handlers} +} + +func (h *multiHandler) WithGroup(key string) slog.Handler { + if key == "" { + return h + } + + handlers := make([]slog.Handler, len(h.handlers)) + for i, handler := range h.handlers { + handlers[i] = handler.WithGroup(key) + } + + return &multiHandler{handlers} +} diff --git a/internal/mock/attr.go b/internal/mock/attr.go new file mode 100644 index 0000000..6dcd3b1 --- /dev/null +++ b/internal/mock/attr.go @@ -0,0 +1,42 @@ +package mock + +import ( + "log/slog" +) + +// NewAttrs returns a new slice of [Attr] based on the given slice of [slog.Attr]. +func NewAttrs(attrs []slog.Attr) []Attr { + return AttrsUsingFunc(len(attrs), func(fn func(slog.Attr)) { + for _, a := range attrs { + fn(a) + } + }) +} + +// AttrsUsingFunc returns a new slice of [Attr] based on the given number and function to get next [slog.Attr]. +func AttrsUsingFunc(n int, fn func(func(slog.Attr))) []Attr { + if n == 0 { + return nil + } + + testAttrs := make([]Attr, 0, n) + fn(func(a slog.Attr) { + testAttrs = append(testAttrs, Attr{ + Key: a.Key, + Value: a.Value.Any(), + }) + }) + + return testAttrs +} + +// NewAttr returns a new [Attr] based on the given key and value. +func NewAttr(key string, value any) Attr { + return Attr{Key: key, Value: value} +} + +// Attr is a mockable representation of [slog.Attr]. +type Attr struct { + Key string + Value any +} diff --git a/internal/mock/calllog.go b/internal/mock/calllog.go new file mode 100644 index 0000000..8990686 --- /dev/null +++ b/internal/mock/calllog.go @@ -0,0 +1,56 @@ +package mock + +import ( + "slices" + "sync" +) + +// NewCallLog returns a new [CallLog]. +func NewCallLog() *CallLog { + return &CallLog{} +} + +// CallLog is a log of method of function calls that can be used to build assertions. +type CallLog struct { + mu sync.Mutex + calls CallList +} + +// Calls returns all recorded calls in the log. +func (l *CallLog) Calls() CallList { + l.mu.Lock() + defer l.mu.Unlock() + + return slices.Clone(l.calls) +} + +func (l *CallLog) append(call any) int { + l.mu.Lock() + defer l.mu.Unlock() + + l.calls = append(l.calls, call) + + return len(l.calls) +} + +// --- + +// CallList is a list of recorded calls. +type CallList []any + +// WithoutTime returns a new [CallList] with all time fields set to zero. +func (l CallList) WithoutTime() CallList { + l = slices.Clone(l) + + for i := range l { + if item, ok := l[i].(cloner); ok { + l[i] = item.clone() + } + + if item, ok := l[i].(timeRemover); ok { + l[i] = item.withoutTime() + } + } + + return l +} diff --git a/internal/mock/handler.go b/internal/mock/handler.go new file mode 100644 index 0000000..aaf66d6 --- /dev/null +++ b/internal/mock/handler.go @@ -0,0 +1,120 @@ +// Package mock provides a mock slog.Handler implementation and other helpers. +package mock + +import ( + "context" + "fmt" + "log/slog" + "slices" +) + +// --- + +// NewHandler returns a new [Handler] with the given [CallLog]. +func NewHandler(log *CallLog) *Handler { + return &Handler{ + instance: "0", + log: log, + } +} + +// --- + +// Handler is a mockable representation of [slog.Handler]. +type Handler struct { + instance string + log *CallLog +} + +// Enabled records the call and returns true. +func (h Handler) Enabled(_ context.Context, level slog.Level) bool { + h.log.append(HandlerEnabled{h.instance, level}) + + return true +} + +// Handle records the call. +func (h Handler) Handle(_ context.Context, record slog.Record) error { + h.log.append(HandlerHandle{h.instance, NewRecord(record)}) + + return nil +} + +// WithAttrs records the call and returns a new [Handler] with the given attributes. +func (h Handler) WithAttrs(attrs []slog.Attr) slog.Handler { + h.instance = h.newInstance( + h.log.append(HandlerWithAttrs{h.instance, NewAttrs(attrs)}), + ) + + return &h +} + +// WithGroup records the call and returns a new [Handler] with the given group. +func (h Handler) WithGroup(group string) slog.Handler { + h.instance = h.newInstance( + h.log.append(HandlerWithGroup{h.instance, group}), + ) + + return &h +} + +func (h Handler) newInstance(n int) string { + return fmt.Sprintf("%s.%d", h.instance, n) +} + +// --- + +// HandlerEnabled is a representation of a call to [slog.Handler.Enabled] +// that can be used to compare against recorded calls in a [CallLog]. +type HandlerEnabled struct { + Instance string + Level slog.Level +} + +// HandlerHandle is a representation of a call to [slog.Handler.Handle] +// that can be used to compare against recorded calls in a [CallLog]. +type HandlerHandle struct { + Instance string + Record Record +} + +func (h HandlerHandle) clone() any { + h.Record = h.Record.clone().(Record) + + return h +} + +func (h HandlerHandle) withoutTime() any { + h.Record = h.Record.WithoutTime() + + return h +} + +// HandlerWithAttrs is a representation of a call to [slog.Handler.WithAttrs] +// that can be used to compare against recorded calls in a [CallLog]. +type HandlerWithAttrs struct { + Instance string + Attrs []Attr +} + +func (h HandlerWithAttrs) clone() any { + h.Attrs = slices.Clone(h.Attrs) + + return h +} + +// HandlerWithGroup is a representation of a call to [slog.Handler.WithGroup] +// that can be used to compare against recorded calls in a [CallLog]. +type HandlerWithGroup struct { + Instance string + Key string +} + +// --- + +var ( + _ slog.Handler = Handler{} + _ cloner = (*HandlerHandle)(nil) + _ timeRemover = (*HandlerHandle)(nil) + _ cloner = (*HandlerWithAttrs)(nil) +) diff --git a/internal/mock/record.go b/internal/mock/record.go new file mode 100644 index 0000000..e09cf8c --- /dev/null +++ b/internal/mock/record.go @@ -0,0 +1,58 @@ +package mock + +import ( + "log/slog" + "slices" + "time" +) + +// NewRecord returns a new [Record] based on the given [slog.Record]. +func NewRecord(record slog.Record) Record { + return Record{ + Time: record.Time, + Message: record.Message, + Level: record.Level, + PC: record.PC, + Attrs: recordAttrs(record), + } +} + +// Record is a mockable representation of [slog.Record]. +type Record struct { + Time time.Time + Message string + Level slog.Level + PC uintptr + Attrs []Attr +} + +// WithoutTime returns a copy of [Record] with [Record.Time] set to zero. +func (r Record) WithoutTime() Record { + r.Time = time.Time{} + + return r +} + +func (r Record) clone() any { + r.Attrs = slices.Clone(r.Attrs) + + return r +} + +// --- + +func recordAttrs(record slog.Record) []Attr { + return AttrsUsingFunc(record.NumAttrs(), func(fn func(slog.Attr)) { + record.Attrs(func(a slog.Attr) bool { + fn(a) + + return true + }) + }) +} + +// --- + +var ( + _ cloner = (*Record)(nil) +) diff --git a/internal/mock/util.go b/internal/mock/util.go new file mode 100644 index 0000000..70e0e8a --- /dev/null +++ b/internal/mock/util.go @@ -0,0 +1,9 @@ +package mock + +type cloner interface { + clone() any +} + +type timeRemover interface { + withoutTime() any +} diff --git a/logger.go b/logger.go new file mode 100644 index 0000000..633672e --- /dev/null +++ b/logger.go @@ -0,0 +1,427 @@ +// Package slogx provides extensions to the [slog] package. +// It focuses on performance and simplicity. +// Only functions working with [slog.Attr] are provided. +// Any slower alternatives are not supported. +package slogx + +import ( + "context" + "log/slog" + "runtime" + "time" +) + +// New returns a new [Logger] with the given handler. +func New(handler slog.Handler) *Logger { + return &Logger{commonLogger{ + handler: handler, + src: true, + }} +} + +// NewContextLogger returns a new [ContextLogger] with the given handler. +func NewContextLogger(handler slog.Handler) *ContextLogger { + return &ContextLogger{commonLogger{ + handler: handler, + src: true, + }} +} + +// Default returns a new [Logger] with the default handler from [slog.Default]. +func Default() *Logger { + return New(defaultHandler()) +} + +// With returns a new [Logger] based on [Default] with the given attributes. +func With(attrs ...slog.Attr) *Logger { + return Default().With(attrs...) +} + +// WithGroup returns a new [Logger] based on [Default] with the given group. +func WithGroup(group string) *Logger { + return Default().WithGroup(group) +} + +// Debug logs a message at the debug level. +func Debug(msg string, attrs ...slog.Attr) { + logAttrs(context.Background(), defaultHandler(), slog.LevelDebug, msg, attrs) +} + +// Info logs a message at the info level. +func Info(msg string, attrs ...slog.Attr) { + logAttrs(context.Background(), defaultHandler(), slog.LevelInfo, msg, attrs) +} + +// Warn logs a message at the warn level. +func Warn(msg string, attrs ...slog.Attr) { + logAttrs(context.Background(), defaultHandler(), slog.LevelWarn, msg, attrs) +} + +// Error logs a message at the error level. +func Error(msg string, attrs ...slog.Attr) { + logAttrs(context.Background(), defaultHandler(), slog.LevelError, msg, attrs) +} + +// Log logs a message at the given level. +func Log(level slog.Level, msg string, attrs ...slog.Attr) { + logAttrs(context.Background(), defaultHandler(), level, msg, attrs) +} + +// --- + +// Logger is a simple logger that logs to a [slog.Handler]. +// It is an alternative to [slog.Logger] focused on performance and simplicity. +// It forces to use [slog.Attr] for log attributes and does not support slow alternatives provided by [slog.Logger]. +// It also takes [slog.Attr] in [Logger.With] because it is the only high performance way to add attributes. +type Logger struct { + commonLogger +} + +// Handler returns the logger's handler. +func (l *Logger) Handler() slog.Handler { + return l.handlerForExport() +} + +// SlogLogger returns a new [slog.Logger] that logs to the associated handler. +func (l *Logger) SlogLogger() *slog.Logger { + return slog.New(l.handler) +} + +// ContextLogger returns a new [ContextLogger] that takes context in logging methods. +func (l *Logger) ContextLogger() *ContextLogger { + return &ContextLogger{l.commonLogger} +} + +// Enabled returns true if the given level is enabled. +func (l *Logger) Enabled(ctx context.Context, level slog.Level) bool { + return l.handler.Enabled(ctx, level) +} + +// With returns a new [Logger] with the given attributes optimized for short usage (one or two times). +func (l *Logger) With(attrs ...slog.Attr) *Logger { + if len(attrs) != 0 { + l = l.clone() + l.setWithAttrs(attrs) + } + + return l +} + +// WithLongTerm returns a new [Logger] with the given attributes optimized for long usage. +func (l *Logger) WithLongTerm(attrs ...slog.Attr) *Logger { + if len(attrs) != 0 || l.attrs.Len() != 0 { + l = l.clone() + l.setWithAttrs(attrs) + l.setLongTerm() + } + + return l +} + +// WithGroup returns a new [Logger] with the given group. +func (l *Logger) WithGroup(group string) *Logger { + if group != "" { + l = l.clone() + l.setWithGroup(group) + } + + return l +} + +// WithSource returns a new [Logger] that includes the source file and line in the log record if [enabled] is true. +func (l *Logger) WithSource(enabled bool) *Logger { + if l.src != enabled { + l = l.clone() + l.src = enabled + } + + return l +} + +// Debug logs a message at the debug level. +func (l *Logger) Debug(msg string, attrs ...slog.Attr) { + l.log(context.Background(), slog.LevelDebug, msg, attrs, 0) +} + +// DebugContext logs a message at the debug level with the given context. +func (l *Logger) DebugContext(ctx context.Context, msg string, attrs ...slog.Attr) { + l.log(ctx, slog.LevelDebug, msg, attrs, 0) +} + +// Info logs a message at the info level. +func (l *Logger) Info(msg string, attrs ...slog.Attr) { + l.log(context.Background(), slog.LevelInfo, msg, attrs, 0) +} + +// InfoContext logs a message at the info level with the given context. +func (l *Logger) InfoContext(ctx context.Context, msg string, attrs ...slog.Attr) { + l.log(ctx, slog.LevelInfo, msg, attrs, 0) +} + +// Warn logs a message at the warn level. +func (l *Logger) Warn(msg string, attrs ...slog.Attr) { + l.log(context.Background(), slog.LevelWarn, msg, attrs, 0) +} + +// WarnContext logs a message at the warn level with the given context. +func (l *Logger) WarnContext(ctx context.Context, msg string, attrs ...slog.Attr) { + l.log(ctx, slog.LevelWarn, msg, attrs, 0) +} + +// Error logs a message at the error level. +func (l *Logger) Error(msg string, attrs ...slog.Attr) { + l.log(context.Background(), slog.LevelError, msg, attrs, 0) +} + +// ErrorContext logs a message at the error level with the given context. +func (l *Logger) ErrorContext(ctx context.Context, msg string, attrs ...slog.Attr) { + l.log(ctx, slog.LevelError, msg, attrs, 0) +} + +// Log logs a message at the given level. +func (l *Logger) Log(level slog.Level, msg string, attrs ...slog.Attr) { + l.log(context.Background(), level, msg, attrs, 0) +} + +// LogContext logs a message at the given level. +func (l *Logger) LogContext(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) { + l.log(ctx, level, msg, attrs, 0) +} + +// LogAttrs logs a message at the given level. +func (l *Logger) LogAttrs(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) { + l.log(ctx, level, msg, attrs, 0) +} + +// LongTerm returns a new [Logger] with the attributes applied to the handler. +func (l *Logger) LongTerm() *Logger { + if l.attrs.Len() != 0 { + l = l.clone() + l.setLongTerm() + } + + return l +} + +func (l Logger) clone() *Logger { + return &l +} + +// --- + +// ContextLogger is an alternative to [Logger] having only methods with context for logging messages. +type ContextLogger struct { + commonLogger +} + +// Logger returns a new [Logger] with the associated handler. +func (l *ContextLogger) Logger() *Logger { + return &Logger{l.commonLogger} +} + +// Handler returns the associated handler. +func (l *ContextLogger) Handler() slog.Handler { + return l.handlerForExport() +} + +// SlogLogger returns a new [slog.Logger] that logs to the associated handler. +func (l *ContextLogger) SlogLogger() *slog.Logger { + return slog.New(l.handler) +} + +// Enabled returns true if the given level is enabled. +func (l *ContextLogger) Enabled(ctx context.Context, level slog.Level) bool { + return l.handler.Enabled(ctx, level) +} + +// With returns a new [ContextLogger] with the given attributes. +func (l *ContextLogger) With(attrs ...slog.Attr) *ContextLogger { + if len(attrs) != 0 { + l = l.clone() + l.setWithAttrs(attrs) + } + + return l +} + +// WithLongTerm returns a new [ContextLogger] with the given attributes optimized for multiple usage. +func (l *ContextLogger) WithLongTerm(attrs ...slog.Attr) *ContextLogger { + if len(attrs) != 0 { + l = l.clone() + l.setWithAttrs(attrs) + l.setLongTerm() + } + + return l +} + +// WithGroup returns a new [ContextLogger] with the given group. +func (l *ContextLogger) WithGroup(group string) *ContextLogger { + if group != "" { + l = l.clone() + l.setWithGroup(group) + } + + return l +} + +// WithSource returns a new [ContextLogger] that includes the source file and line in the log record if [enabled] is true. +func (l *ContextLogger) WithSource(enabled bool) *ContextLogger { + if l.src != enabled { + l = l.clone() + l.src = enabled + } + + return l +} + +// Debug logs a message at the debug level. +func (l *ContextLogger) Debug(ctx context.Context, msg string, attrs ...slog.Attr) { + l.log(ctx, slog.LevelDebug, msg, attrs, 0) +} + +// Info logs a message at the info level. +func (l *ContextLogger) Info(ctx context.Context, msg string, attrs ...slog.Attr) { + l.log(ctx, slog.LevelInfo, msg, attrs, 0) +} + +// Warn logs a message at the warn level. +func (l *ContextLogger) Warn(ctx context.Context, msg string, attrs ...slog.Attr) { + l.log(ctx, slog.LevelWarn, msg, attrs, 0) +} + +// Error logs a message at the error level. +func (l *ContextLogger) Error(ctx context.Context, msg string, attrs ...slog.Attr) { + l.log(ctx, slog.LevelError, msg, attrs, 0) +} + +// Log logs a message at the given level. +func (l *ContextLogger) Log(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) { + l.log(ctx, level, msg, attrs, 0) +} + +// LogAttrs logs a message at the given level. +func (l *ContextLogger) LogAttrs(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) { + l.log(ctx, level, msg, attrs, 0) +} + +// LogWithCallerSkip logs a message at the given level with additional skipping of the specified amount of call stack frames. +func (l *ContextLogger) LogWithCallerSkip(ctx context.Context, skip int, level slog.Level, msg string, attrs ...slog.Attr) { + l.log(ctx, level, msg, attrs, skip) +} + +// LongTerm returns a new [Logger] with the attributes applied to the handler. +func (l *ContextLogger) LongTerm() *ContextLogger { + if l.attrs.Len() != 0 { + l = l.clone() + l.setLongTerm() + } + + return l +} + +func (l ContextLogger) clone() *ContextLogger { + return &l +} + +// --- + +func defaultHandler() slog.Handler { + return slog.Default().Handler() +} + +// --- + +type commonLogger struct { + handler slog.Handler + src bool + attrs AttrPack +} + +func (l *commonLogger) handlerForExport() slog.Handler { + handler := l.handler + if l.attrs.Len() != 0 { + handler = handler.WithAttrs(l.attrs.Collect()) + } + + return handler +} + +func (l *commonLogger) setWithAttrs(attrs []slog.Attr) { + if len(attrs) != 0 { + l.attrs = l.attrs.Clone() + l.attrs.Add(attrs...) + } +} + +func (l *commonLogger) setWithGroup(group string) { + if group != "" { + l.setLongTerm() + l.handler = l.handler.WithGroup(group) + } +} + +func (l *commonLogger) setLongTerm() { + if l.attrs.Len() != 0 { + l.handler = l.handlerForExport() + l.attrs = AttrPack{} + } +} + +func (l *commonLogger) log(ctx context.Context, level slog.Level, msg string, attrs []slog.Attr, skip int) { + if ctx == nil { + ctx = context.Background() + } + + if !l.handler.Enabled(ctx, level) { + return + } + + var pcs [1]uintptr + if l.src { + runtime.Callers(skip+3, pcs[:]) + } + + r := slog.NewRecord(time.Now(), level, msg, pcs[0]) + + if l.attrs.Len() != 0 { + l.attrs.Enumerate(func(attr slog.Attr) bool { + r.AddAttrs(attr) + + return true + }) + } + + r.AddAttrs(attrs...) + + _ = l.handler.Handle(ctx, r) +} + +// --- + +func logAttrs(ctx context.Context, handler slog.Handler, level slog.Level, msg string, attrs []slog.Attr) { + l := commonLogger{ + handler: handler, + src: true, + } + l.log(ctx, level, msg, attrs, 1) +} + +// --- + +type commonLoggerInterface[T any] interface { + Handler() slog.Handler + SlogLogger() *slog.Logger + Enabled(context.Context, slog.Level) bool + LogAttrs(context.Context, slog.Level, string, ...slog.Attr) + With(...slog.Attr) T + WithLongTerm(...slog.Attr) T + WithGroup(string) T + WithSource(bool) T + LongTerm() T +} + +var ( + _ commonLoggerInterface[*Logger] = (*Logger)(nil) + _ commonLoggerInterface[*ContextLogger] = (*ContextLogger)(nil) +) diff --git a/logger_test.go b/logger_test.go new file mode 100644 index 0000000..4040591 --- /dev/null +++ b/logger_test.go @@ -0,0 +1,203 @@ +package slogx_test + +import ( + "context" + "log/slog" + + . "github.com/pamburus/go-tst/tst" + "github.com/pamburus/slogx" + "github.com/pamburus/slogx/internal/mock" + + "testing" +) + +func TestLogger(tt *testing.T) { + t := New(tt) + + t.Run("Default", func(t Test) { + cl := mock.NewCallLog() + handler := mock.NewHandler(cl) + slog.SetDefault(slog.New(handler)) + logger := slogx.Default().WithSource(false) + + logger.Info("msg") + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelInfo, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelInfo, + Message: "msg", + }, + }, + )) + }) + + test := func(name string, fn func(Test, *mock.CallLog, *slogx.Logger)) { + cl := mock.NewCallLog() + handler := mock.NewHandler(cl) + logger := slogx.New(handler).WithSource(false) + + t.Run(name, func(t Test) { + fn(t, cl, logger) + }) + } + + test("Debug", func(t Test, cl *mock.CallLog, logger *slogx.Logger) { + logger.Debug("msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelDebug, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelDebug, + Message: "msg", + Attrs: []mock.Attr{{Key: "a", Value: "v"}}, + }, + }, + )) + }) + + test("Info", func(t Test, cl *mock.CallLog, logger *slogx.Logger) { + logger.Info("msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelInfo, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelInfo, + Message: "msg", + Attrs: []mock.Attr{{Key: "a", Value: "v"}}, + }, + }, + )) + }) + + test("Warn", func(t Test, cl *mock.CallLog, logger *slogx.Logger) { + logger.Warn("msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelWarn, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelWarn, + Message: "msg", + Attrs: []mock.Attr{{Key: "a", Value: "v"}}, + }, + }, + )) + }) + + test("Error", func(t Test, cl *mock.CallLog, logger *slogx.Logger) { + logger.Error("msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelError, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelError, + Message: "msg", + Attrs: []mock.Attr{{Key: "a", Value: "v"}}, + }, + }, + )) + }) + + test("Log", func(t Test, cl *mock.CallLog, logger *slogx.Logger) { + logger.Log(slog.LevelWarn, "msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelWarn, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelWarn, + Message: "msg", + Attrs: []mock.Attr{{Key: "a", Value: "v"}}, + }, + }, + )) + }) + + test("With", func(t Test, cl *mock.CallLog, logger *slogx.Logger) { + logger = logger.With( + slog.String("a", "va"), + slog.String("b", "vb"), + ) + logger.Log(slog.LevelInfo, "msg", slog.String("c", "d")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelInfo, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelInfo, + Message: "msg", + Attrs: []mock.Attr{ + {Key: "a", Value: "va"}, + {Key: "b", Value: "vb"}, + {Key: "c", Value: "d"}, + }, + }, + }, + )) + }) + + test("WithGroup", func(t Test, cl *mock.CallLog, logger *slogx.Logger) { + logger = logger.WithGroup("g1") + logger.Log(slog.LevelInfo, "msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerWithGroup{ + Instance: "0", + Key: "g1", + }, + mock.HandlerEnabled{ + Instance: "0.1", + Level: slog.LevelInfo, + }, + mock.HandlerHandle{ + Instance: "0.1", + Record: mock.Record{ + Level: slog.LevelInfo, + Message: "msg", + Attrs: []mock.Attr{ + {Key: "a", Value: "v"}, + }, + }, + }, + )) + }) + + test("Enabled", func(t Test, cl *mock.CallLog, logger *slogx.Logger) { + logger.Enabled(context.Background(), slog.LevelDebug) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelDebug, + }, + )) + }) + + test("SlogLogger", func(t Test, cl *mock.CallLog, logger *slogx.Logger) { + t.Expect(logger.SlogLogger().Handler()).To(Equal(logger.Handler())) + }) +} diff --git a/slogc/README.md b/slogc/README.md new file mode 100644 index 0000000..ac8eab4 --- /dev/null +++ b/slogc/README.md @@ -0,0 +1,13 @@ +# slogx [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] + +Package [slogc](https://pkg.go.dev/github.com/pamburus/slogx/slogc) provides [Logger](https://pkg.go.dev/github.com/pamburus/slogx/slogc#Logger), which is an alias for [slogx.ContextLogger](https://pkg.go.dev/github.com/pamburus/slogx#ContextLogger) and is an alternative to [slog.Logger](https://pkg.go.dev/log/slog#Logger) that focuses on performance and usability. See the [slogx](../README.md) package description for more details about [slogx.ContextLogger](https://pkg.go.dev/github.com/pamburus/slogx#ContextLogger) and its rationale. This package provides logging primitives that are context-centric. The [Logger](https://pkg.go.dev/github.com/pamburus/slogx/slogc#Logger) can be stored in a context using the [New](https://pkg.go.dev/github.com/pamburus/slogx/slogc#New) function, and later used implicitly by providing only the context to a set of functions such as [Log](https://pkg.go.dev/github.com/pamburus/slogx/slogc#Log), [Info](https://pkg.go.dev/github.com/pamburus/slogx/slogc#Info), [Debug](https://pkg.go.dev/github.com/pamburus/slogx/slogc#Debug), and so on. It can also be retrieved from the context using the [Get](https://pkg.go.dev/github.com/pamburus/slogx/slogc#Get) method. If the context does not contain a value stored by the [New](https://pkg.go.dev/github.com/pamburus/slogx/slogc#New) method, a [Default](https://pkg.go.dev/github.com/pamburus/slogx/slogc#Default) logger is returned, which is constructed using a handler returned by [slog.Default](https://pkg.go.dev/log/slog#Default). + +## Performance +* See [benchmark results](../doc/benchmark/README.md) for details. + +[doc-img]: https://pkg.go.dev/badge/github.com/pamburus/slogx/slogc +[doc]: https://pkg.go.dev/github.com/pamburus/slogx/slogc +[ci-img]: https://github.com/pamburus/slogx/actions/workflows/ci.yml/badge.svg +[ci]: https://github.com/pamburus/slogx/actions/workflows/ci.yml +[cov-img]: https://codecov.io/gh/pamburus/slogx/slogc/graph/badge.svg?token=0TF6JD4KDU +[cov]: https://codecov.io/gh/pamburus/slogx/slogc diff --git a/slogc/benchmark_test.go b/slogc/benchmark_test.go new file mode 100644 index 0000000..b1c56f7 --- /dev/null +++ b/slogc/benchmark_test.go @@ -0,0 +1,223 @@ +package slogc_test + +import ( + "context" + "io" + "log/slog" + "testing" + + "github.com/pamburus/slogx" + "github.com/pamburus/slogx/slogc" +) + +func BenchmarkLogging(b *testing.B) { + testEnabled := func(ctx context.Context, b *testing.B) { + b.Run("Enabled", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + slogc.Get(ctx).Enabled(ctx, slog.LevelInfo) + } + }) + } + + testLogAttrs := func(ctx context.Context, b *testing.B) { + b.Run("Log", func(b *testing.B) { + b.Run("NoAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + slogc.Log(ctx, slog.LevelInfo, "msg") + } + }) + b.Run("ThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + slogc.Log(ctx, slog.LevelInfo, "msg", slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + } + }) + }) + } + + testWith := func(ctx context.Context, b *testing.B) { + b.Run("With", func(b *testing.B) { + b.Run("ThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + slogc.With(ctx, slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + } + }) + b.Run("FiveAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + slogc.With(ctx, slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + }) + } + + testWithAndLog := func(ctx context.Context, b *testing.B) { + b.Run("LogWithAndLog", func(b *testing.B) { + b.Run("TwoAndThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := slogc.Get(ctx).With(slog.String("a", "av"), slog.String("b", "bv")) + logger.Log(ctx, slog.LevelInfo, "msg", slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + b.Run("ThreeAndFourAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := slogc.Get(ctx).With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + logger.Log(ctx, slog.LevelInfo, "msg", slog.String("d", "dv"), slog.String("e", "ev"), slog.String("f", "fv"), slog.String("g", "gv")) + } + }) + b.Run("FiveAndThreeAttrs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i != b.N; i++ { + logger := slogc.Get(ctx).With(slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + logger.Log(ctx, slog.LevelInfo, "msg", slog.String("f", "fv"), slog.String("g", "gv"), slog.String("h", "hv")) + } + }) + }) + } + + testLogAfterWith := func(ctx context.Context, b *testing.B) { + b.Run("LogAfterWith", func(b *testing.B) { + b.Run("TwoAndThreeAttrs", func(b *testing.B) { + ctx := slogc.With(ctx, slog.String("a", "av"), slog.String("b", "bv")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + slogc.Log(ctx, slog.LevelInfo, "msg", slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + } + }) + b.Run("ThreeAndFourAttrs", func(b *testing.B) { + ctx := slogc.With(ctx, slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + slogc.Log(ctx, slog.LevelInfo, "msg", slog.String("d", "dv"), slog.String("e", "ev"), slog.String("f", "fv"), slog.String("g", "gv")) + } + }) + b.Run("FiveAndThreeAttrs", func(b *testing.B) { + ctx := slogc.With(ctx, slog.String("a", "av"), slog.String("b", "bv"), slog.String("c", "cv"), slog.String("d", "dv"), slog.String("e", "ev")) + b.ResetTimer() + for i := 0; i != b.N; i++ { + slogc.Log(ctx, slog.LevelInfo, "msg", slog.String("f", "fv"), slog.String("g", "gv"), slog.String("h", "hv")) + } + }) + }) + } + + testAllForContext := func(ctx context.Context, b *testing.B) { + testEnabled(ctx, b) + testLogAttrs(ctx, b) + testWith(ctx, b) + testWithAndLog(ctx, b) + testLogAfterWith(ctx, b) + } + + testWithSource := func(ctx context.Context, b *testing.B, handler slog.Handler, enabled bool) { + name := "WithSource" + if !enabled { + name = "WithoutSource" + } + + b.Run(name, func(b *testing.B) { + b.Run("Unwrapped", func(b *testing.B) { + ctx := slogc.New(ctx, slogx.NewContextLogger(handler).WithSource(enabled)) + testAllForContext(ctx, b) + }) + + b.Run("3xWrapped", func(b *testing.B) { + handler = wrapHandlerN(handler, 3) + ctx := slogc.New(ctx, slogx.NewContextLogger(handler).WithSource(enabled)) + testAllForContext(ctx, b) + }) + }) + } + + testAllForHandler := func(ctx context.Context, b *testing.B, handler slog.Handler) { + testWithSource(ctx, b, handler, false) + testWithSource(ctx, b, handler, true) + } + + b.Run("Discard", func(b *testing.B) { + b.Run("Disabled", func(b *testing.B) { + testAllForHandler(context.Background(), b, slogx.Discard()) + }) + b.Run("Enabled", func(b *testing.B) { + testAllForHandler(context.Background(), b, &enabledDiscardHandler{}) + }) + }) + + b.Run("JSON", func(b *testing.B) { + b.Run("Disabled", func(b *testing.B) { + testAllForHandler(context.Background(), b, slog.NewJSONHandler(io.Discard, &slog.HandlerOptions{Level: slog.LevelError})) + }) + b.Run("Enabled", func(b *testing.B) { + testAllForHandler(context.Background(), b, slog.NewJSONHandler(io.Discard, &slog.HandlerOptions{})) + }) + }) +} + +// --- + +func wrapHandlerN(handler slog.Handler, times int) slog.Handler { + for i := 0; i != times; i++ { + handler = wrapHandler(handler) + } + + return handler +} + +func wrapHandler(handler slog.Handler) slog.Handler { + return &testHandlerWrapper{handler} +} + +// --- + +type testHandlerWrapper struct { + base slog.Handler +} + +func (h *testHandlerWrapper) Enabled(ctx context.Context, level slog.Level) bool { + return h.base.Enabled(ctx, level) +} + +func (h *testHandlerWrapper) Handle(ctx context.Context, record slog.Record) error { + return h.base.Handle(ctx, record) +} + +func (h *testHandlerWrapper) WithAttrs(attrs []slog.Attr) slog.Handler { + if len(attrs) == 0 { + return h + } + + return &testHandlerWrapper{h.base.WithAttrs(attrs)} +} + +func (h *testHandlerWrapper) WithGroup(key string) slog.Handler { + if key == "" { + return h + } + + return &testHandlerWrapper{h.base.WithGroup(key)} +} + +//--- + +type enabledDiscardHandler struct{} + +func (h *enabledDiscardHandler) Enabled(context.Context, slog.Level) bool { + return true +} + +func (h *enabledDiscardHandler) Handle(context.Context, slog.Record) error { + return nil +} + +func (h *enabledDiscardHandler) WithAttrs([]slog.Attr) slog.Handler { + return h +} + +func (h *enabledDiscardHandler) WithGroup(string) slog.Handler { + return h +} diff --git a/slogc/name.go b/slogc/name.go new file mode 100644 index 0000000..140819f --- /dev/null +++ b/slogc/name.go @@ -0,0 +1,50 @@ +package slogc + +import ( + "context" + "log/slog" +) + +// WithName returns a new context with the logger name composed +// of the base name that is already in context as a prefix and the provided name +// using dot as a separator. +// If the name is empty, the context is returned as is. +func WithName(ctx context.Context, name string) context.Context { + if name == "" { + return ctx + } + + base := Name(ctx) + if base != "" { + name = base + "." + name + } + + return context.WithValue(ctx, &contextKeyName, name) +} + +// Name returns the full logger name from the context. +// If the name is not set, an empty string is returned. +func Name(ctx context.Context) string { + if name, ok := ctx.Value(&contextKeyName).(string); ok { + return name + } + + return "" +} + +// NameAttr returns a dynamic attribute that contains the logger name. +func NameAttr(key string) func(ctx context.Context) slog.Attr { + return func(ctx context.Context) slog.Attr { + if name := Name(ctx); name != "" { + return slog.String(key, name) + } + + return slog.Attr{} + } +} + +// --- + +var ( + contextKeyName int +) diff --git a/slogc/name_test.go b/slogc/name_test.go new file mode 100644 index 0000000..4ab082c --- /dev/null +++ b/slogc/name_test.go @@ -0,0 +1,227 @@ +package slogc_test + +import ( + "context" + "log/slog" + "testing" + "time" + + . "github.com/pamburus/go-tst/tst" + "github.com/pamburus/slogx" + "github.com/pamburus/slogx/internal/mock" + "github.com/pamburus/slogx/slogc" +) + +func TestName(tt *testing.T) { + t := New(tt) + + someTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) + + t.Run("EmptyAttrKey", func(t Test) { + handler := &mock.Handler{} + t.Expect(newHandlerWithName(handler, "")).To(Equal(handler)) + }) + + t.Run("Enabled", func(t Test) { + cl := mock.NewCallLog() + base := mock.NewHandler(cl) + handler := newHandlerWithName(base, "@logger") + + t.Expect(handler.Enabled(context.Background(), slog.LevelInfo)).To(BeTrue()) + t.Expect(cl.Calls()...).To(Equal( + mock.HandlerEnabled{Instance: "0", Level: slog.LevelInfo}, + )) + }) + + t.Run("WithEmptyAttrs", func(t Test) { + cl := mock.NewCallLog() + base := mock.NewHandler(cl) + handler := newHandlerWithName(base, "@logger") + + t.Expect(handler.WithAttrs(nil)).To(Equal(handler)) + }) + + t.Run("WithEmptyGroup", func(t Test) { + cl := mock.NewCallLog() + base := mock.NewHandler(cl) + handler := newHandlerWithName(base, "@logger") + + t.Expect(handler.WithGroup("")).To(Equal(handler)) + }) + + t.Run("WithGroup", func(t Test) { + ctx := context.Background() + cl := mock.NewCallLog() + base := mock.NewHandler(cl) + + handler := newHandlerWithName(base, "@logger") + handler = handler.WithAttrs([]slog.Attr{slog.String("a1", "av1")}) + handler = handler.WithGroup("g1") + handler = handler.WithAttrs([]slog.Attr{slog.String("a2", "av2")}) + + record1 := slog.NewRecord(someTime, slog.LevelDebug, "m1", 42) + record1.AddAttrs( + slog.String("a3", "av3"), + slog.String("a4", "av4"), + ) + + err := handler.Handle(slogc.WithName(ctx, "ab"), record1) + t.Expect(err).ToNot(HaveOccurred()) + + t.Expect(cl.Calls()...).To(Equal( + mock.HandlerWithAttrs{ + Instance: "0", + Attrs: []mock.Attr{ + {Key: "a1", Value: "av1"}, + }, + }, + mock.HandlerWithGroup{ + Instance: "0.1", + Key: "g1", + }, + mock.HandlerWithAttrs{ + Instance: "0.1.2", + Attrs: []mock.Attr{ + {Key: "a2", Value: "av2"}, + }, + }, + mock.HandlerHandle{ + Instance: "0.1.2.3", + Record: mock.Record{ + Time: someTime, + Message: "m1", + Level: slog.LevelDebug, + PC: 42, + Attrs: []mock.Attr{ + {Key: "a3", Value: "av3"}, + {Key: "a4", Value: "av4"}, + {Key: "@logger", Value: "ab"}, + }, + }, + }, + )) + }) + + t.Run("WithoutName", func(t Test) { + cl := mock.NewCallLog() + base := mock.NewHandler(cl) + handler := newHandlerWithName(base, "@logger") + record1 := slog.NewRecord(someTime, slog.LevelInfo, "m1", 0) + + err := handler.Handle(context.Background(), record1) + t.Expect(err).ToNot(HaveOccurred()) + t.Expect(cl.Calls()...).To(Equal( + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Time: someTime, + Message: "m1", + Level: slog.LevelInfo, + PC: 0, + Attrs: nil, + }, + }, + )) + }) + + t.Run("WithName", func(t Test) { + ctx := slogc.WithName(context.Background(), "a") + cl := mock.NewCallLog() + base := mock.NewHandler(cl) + handler := newHandlerWithName(base, "@logger") + record1 := slog.NewRecord(someTime, slog.LevelInfo, "m1", 0) + + err := handler.Handle(slogc.WithName(ctx, "b"), record1) + t.Expect(err).ToNot(HaveOccurred()) + t.Expect(cl.Calls()...).To(Equal( + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Time: someTime, + Message: "m1", + Level: slog.LevelInfo, + PC: 0, + Attrs: []mock.Attr{ + {Key: "@logger", Value: "a.b"}, + }, + }, + }, + )) + }) + + t.Run("WithEmptyName", func(t Test) { + ctx := context.Background() + cl := mock.NewCallLog() + base := mock.NewHandler(cl) + handler := newHandlerWithName(base, "@logger") + record1 := slog.NewRecord(someTime, slog.LevelInfo, "m1", 0) + + err := handler.Handle(slogc.WithName(ctx, ""), record1) + t.Expect(err).ToNot(HaveOccurred()) + t.Expect(cl.Calls()...).To(Equal( + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Time: someTime, + Message: "m1", + Level: slog.LevelInfo, + PC: 0, + Attrs: nil, + }, + }, + )) + }) + + t.Run("WithAttrsAndName", func(t Test) { + ctx := context.Background() + cl := mock.NewCallLog() + base := mock.NewHandler(cl) + handler := newHandlerWithName(base, "@logger") + + record1 := slog.NewRecord(someTime, slog.LevelInfo, "m1", 0) + record1.AddAttrs( + slog.Any("a1", "av1"), + slog.Any("a2", "av2"), + ) + + handler = handler.WithAttrs([]slog.Attr{ + slog.Any("c1", "cv1"), + slog.Any("c2", "cv2"), + }) + err := handler.Handle(slogc.WithName(ctx, "aa"), record1) + t.Expect(err).ToNot(HaveOccurred()) + t.Expect(cl.Calls()...).To(Equal( + mock.HandlerWithAttrs{ + Instance: "0", + Attrs: []mock.Attr{ + {Key: "c1", Value: "cv1"}, + {Key: "c2", Value: "cv2"}, + }, + }, + mock.HandlerHandle{ + Instance: "0.1", + Record: mock.Record{ + Time: someTime, + Message: "m1", + Level: slog.LevelInfo, + PC: 0, + Attrs: []mock.Attr{ + {Key: "a1", Value: "av1"}, + {Key: "a2", Value: "av2"}, + {Key: "@logger", Value: "aa"}, + }, + }, + }, + )) + }) +} + +func newHandlerWithName(handler slog.Handler, attrKey string) slog.Handler { + if attrKey == "" { + return handler + } + + return slogx.TweakHandler(handler). + WithDynamicAttr(slogc.NameAttr(attrKey)). + Result() +} diff --git a/slogc/slogc.go b/slogc/slogc.go new file mode 100644 index 0000000..a35b53d --- /dev/null +++ b/slogc/slogc.go @@ -0,0 +1,86 @@ +// Package slogc provides context-centric logging facilities based on [slogx] and [slog] packages. +package slogc + +import ( + "context" + "log/slog" + + "github.com/pamburus/slogx" +) + +// Logger is an alias for [slogx.ContextLogger]. +type Logger = slogx.ContextLogger + +// New returns a new context with the provided logger. +func New(ctx context.Context, logger *Logger) context.Context { + if ctx == nil { + ctx = context.Background() + } + + return context.WithValue(ctx, &contextKeyLogger, logger) +} + +// Get returns a [Logger] from the given context stored by [New]. +// If the context is nil or the logger is not found, a [Default] logger is returned. +func Get(ctx context.Context) *Logger { + if ctx != nil { + if logger, ok := ctx.Value(&contextKeyLogger).(*Logger); ok { + return logger + } + } + + return Default() +} + +// Default returns a [Logger] with the default handler from [slog.Default]. +func Default() *Logger { + return slogx.Default().ContextLogger() +} + +// With returns a new context with a modified logger containing additionally the provided attributes. +func With(ctx context.Context, attrs ...slog.Attr) context.Context { + return New(ctx, Get(ctx).WithLongTerm(attrs...)) +} + +// WithGroup returns a new context with a modified logger containing the provided group. +func WithGroup(ctx context.Context, key string) context.Context { + return New(ctx, Get(ctx).WithGroup(key)) +} + +// WithSource returns a new context with a modified logger containing the source information enabled flag. +func WithSource(ctx context.Context, enabled bool) context.Context { + return New(ctx, Get(ctx).WithSource(enabled)) +} + +// --- + +// Debug logs a message at debug level. +func Debug(ctx context.Context, msg string, attrs ...slog.Attr) { + Get(ctx).LogWithCallerSkip(ctx, 1, slog.LevelDebug, msg, attrs...) +} + +// Info logs a message at info level. +func Info(ctx context.Context, msg string, attrs ...slog.Attr) { + Get(ctx).LogWithCallerSkip(ctx, 1, slog.LevelInfo, msg, attrs...) +} + +// Warn logs a message at warn level. +func Warn(ctx context.Context, msg string, attrs ...slog.Attr) { + Get(ctx).LogWithCallerSkip(ctx, 1, slog.LevelWarn, msg, attrs...) +} + +// Error logs a message at error level. +func Error(ctx context.Context, msg string, attrs ...slog.Attr) { + Get(ctx).LogWithCallerSkip(ctx, 1, slog.LevelError, msg, attrs...) +} + +// Log logs a message with attributes at the given level. +func Log(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) { + Get(ctx).LogWithCallerSkip(ctx, 1, level, msg, attrs...) +} + +// --- + +var ( + contextKeyLogger int +) diff --git a/slogc/slogc_test.go b/slogc/slogc_test.go new file mode 100644 index 0000000..ad98f5d --- /dev/null +++ b/slogc/slogc_test.go @@ -0,0 +1,198 @@ +package slogc_test + +import ( + "context" + "log/slog" + + . "github.com/pamburus/go-tst/tst" + "github.com/pamburus/slogx" + "github.com/pamburus/slogx/internal/mock" + "github.com/pamburus/slogx/slogc" + + "testing" +) + +func TestLogger(tt *testing.T) { + t := New(tt) + + t.Run("Default", func(t Test) { + cl := mock.NewCallLog() + handler := mock.NewHandler(cl) + slog.SetDefault(slog.New(handler)) + ctx := context.Background() + ctx = slogc.WithSource(ctx, false) + logger := slogc.Get(ctx) + + logger.Info(ctx, "msg") + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelInfo, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelInfo, + Message: "msg", + }, + }, + )) + }) + + test := func(name string, fn func(context.Context, *mock.CallLog, Test)) { + cl := mock.NewCallLog() + handler := mock.NewHandler(cl) + logger := slogx.NewContextLogger(handler).WithSource(false) + ctx := slogc.New(nil, logger) + + t.Run(name, func(t Test) { + fn(ctx, cl, t) + }) + } + + test("Debug", func(ctx context.Context, cl *mock.CallLog, t Test) { + slogc.Debug(ctx, "msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelDebug, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelDebug, + Message: "msg", + Attrs: []mock.Attr{{Key: "a", Value: "v"}}, + }, + }, + )) + }) + + test("Info", func(ctx context.Context, cl *mock.CallLog, t Test) { + slogc.Info(ctx, "msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelInfo, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelInfo, + Message: "msg", + Attrs: []mock.Attr{{Key: "a", Value: "v"}}, + }, + }, + )) + }) + + test("Warn", func(ctx context.Context, cl *mock.CallLog, t Test) { + slogc.Warn(ctx, "msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelWarn, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelWarn, + Message: "msg", + Attrs: []mock.Attr{{Key: "a", Value: "v"}}, + }, + }, + )) + }) + + test("Error", func(ctx context.Context, cl *mock.CallLog, t Test) { + slogc.Error(ctx, "msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelError, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelError, + Message: "msg", + Attrs: []mock.Attr{{Key: "a", Value: "v"}}, + }, + }, + )) + }) + + test("Log", func(ctx context.Context, cl *mock.CallLog, t Test) { + slogc.Log(ctx, slog.LevelWarn, "msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerEnabled{ + Instance: "0", + Level: slog.LevelWarn, + }, + mock.HandlerHandle{ + Instance: "0", + Record: mock.Record{ + Level: slog.LevelWarn, + Message: "msg", + Attrs: []mock.Attr{{Key: "a", Value: "v"}}, + }, + }, + )) + }) + + test("With", func(ctx context.Context, cl *mock.CallLog, t Test) { + ctx = slogc.With(ctx, + slog.String("a", "va"), + slog.String("b", "vb"), + ) + slogc.Log(ctx, slog.LevelInfo, "msg", slog.String("c", "d")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerWithAttrs{ + Instance: "0", + Attrs: []mock.Attr{ + {Key: "a", Value: "va"}, + {Key: "b", Value: "vb"}, + }, + }, + mock.HandlerEnabled{ + Instance: "0.1", + Level: slog.LevelInfo, + }, + mock.HandlerHandle{ + Instance: "0.1", + Record: mock.Record{ + Level: slog.LevelInfo, + Message: "msg", + Attrs: []mock.Attr{ + {Key: "c", Value: "d"}, + }, + }, + }, + )) + }) + + test("WithGroup", func(ctx context.Context, cl *mock.CallLog, t Test) { + ctx = slogc.WithGroup(ctx, "g1") + slogc.Log(ctx, slog.LevelInfo, "msg", slog.String("a", "v")) + t.Expect(cl.Calls().WithoutTime()...).To(Equal( + mock.HandlerWithGroup{ + Instance: "0", + Key: "g1", + }, + mock.HandlerEnabled{ + Instance: "0.1", + Level: slog.LevelInfo, + }, + mock.HandlerHandle{ + Instance: "0.1", + Record: mock.Record{ + Level: slog.LevelInfo, + Message: "msg", + Attrs: []mock.Attr{ + {Key: "a", Value: "v"}, + }, + }, + }, + )) + }) +}