Commit f6fbd33 added `case nil: return e` in Event.Err() so that when
ErrorStackMarshaler returns nil (the error has no stack trace), the
function returns early without logging the error itself.
This was a regression. The previous behaviour was to fall through the
switch and always call AnErr(ErrorFieldName, err), ensuring the error
message is logged even when no stack is attached.
Libraries such as elastic/ecs-logging-go-zerolog (and plain fmt.Errorf
errors) rely on the old behaviour: calling Stack().Err(err) should
always log the error field; the stack field is additional and optional.
Change the `nil` case from `return e` to a comment (fall-through) so
that AnErr is called unconditionally. Update the test that was written
to match the incorrect behaviour.
Fixes#762
Signed-off-by: alliasgher <alliasgher123@gmail.com>
* Added variadic StrsV, ObjectsV, and StringersV
This allows you to just list all the string, object, or stringer that you want added to a Event or Context.
The variadic versions are suffixed with V so as to not be a breaking change.
If you have an existing array of objects that implement the LogObjectMarshaler or fmt.Stringer interfaces, unfortunately go doesn't consider those slices as identical types, so you have to allocate an array and copy the entries, there are generic helper methods in global_118.go zerolog.AsLogObjectMarshalers and zerolog.AsStringers if you're using go 1.18 or later.
Somewhat addresses #551
* Address CoPilot comments.
* Resolve odd Stringers on nil array
UpdateContext previously used pointer equality (l == disabledLogger) to
detect disabled loggers. This only caught the package-level singleton
returned by Ctx() but missed loggers created via Nop() or zero-value
Logger{}, which could lead to data races when a shared Nop logger was
used from multiple goroutines.
Replace the pointer comparison with a check for nil writer or Disabled
level, consistent with how Logger.should() determines if logging is
active. This prevents unnecessary context mutations on loggers that
will never produce output.
Fixes#643
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Closes#571
I needed slog interop in a project where zerolog handles all log output, but some dependencies use `log/slog`. Rather than losing zerolog's performance by switching to slog's built-in JSON handler, this adds a `SlogHandler` that implements `slog.Handler` and routes everything through zerolog.
### What this does
`zerolog.NewSlogHandler(logger)` returns a `slog.Handler` backed by the given `zerolog.Logger`. You can use it like:
```go
zl := zerolog.New(os.Stderr).With().Timestamp().Logger()
slog.SetDefault(slog.New(zerolog.NewSlogHandler(zl)))
slog.Info("request handled", "method", "GET", "status", 200)
// Output: {"level":"info","method":"GET","status":200,"time":...,"message":"request handled"}
```
**Level mapping:**
- `slog.LevelDebug-4` and below -> `zerolog.TraceLevel`
- `slog.LevelDebug` -> `zerolog.DebugLevel`
- `slog.LevelInfo` -> `zerolog.InfoLevel`
- `slog.LevelWarn` -> `zerolog.WarnLevel`
- `slog.LevelError` -> `zerolog.ErrorLevel`
**Supported features:**
- All slog attribute types encoded with zerolog's typed methods (no reflection for primitives)
- `WithAttrs` for pre-attaching fields to child handlers
- `WithGroup` for namespacing keys with dot-separated prefixes
- Nested groups work correctly
- `LogValuer` resolution
- Level filtering respects the zerolog Logger's configured level
- Zerolog contextual fields from `With()` are preserved
**Files:**
- `slog.go` - the handler implementation (~200 lines)
- `slog_test.go` - 26 tests covering levels, all attr types, groups, filtering, LogValuer, immutability
All existing tests continue to pass (the `RandomSampler` flake in `sampler_test.go` is pre-existing).
The `go.mod` already requires Go 1.23, so `log/slog` is available without any changes.
* Test coverage improvements
Implements #397 and #591, might help with #473
Test coverage for core is 97.6% with only real fringe cases remaining.
Improve `Fields` `isNilValue()` portability.
Added a new global handler `FatalExitFunc` to allow intercepting `Fatal()` messages.
Fixed CBOR float constants (removed the CBOR prefix)
Added tests for:
- global `FatalExitFunc` to allow intercepting Fatal messages (both for testing and public use).
- `Logger`
- `DisableSampling`
- `.With()` copying existing context if present.
- `.With().Fields()` all forms of `ErrorStackMarshaler` returns.
- `.WithLevel()` for `FatalLevel`, `PanicLevel`, and `DisabledLevel`.
- `.Err()` with `nil` and non-`nil` `error` and test the resulting log level.
- `.should()` covering `nil` writer.
- `.Output()` gets context values.
- `.UpdateContext()` on a disabled logger doesn't panic and is a nop.
- `.With()` all forms of `ErrorStackMarshaler` returns.
- with a `nil`writer.
- `.Hook()` passing no hooks.
- `Array`
- `.MarshalZerologArray` is a nop that won't panic.
- `Context`
- ` .Err()` and `.AnErr()` for `nil` errors and all forms of `ErrorStackMarshaler` returns.
- `Event`
- `.Caller()` to ensure we don't panic or add invalid information if `runtime.Caller()` fails
-` .Err()` and `.AnErr()` for `nil` errors and all forms of `ErrorStackMarshaler` returns.
- `Fields`
- ` .appendFields()` all forms of `ErrorStackMarshaler` returns.
- `HookLevel`
- `.Run()` methods.
- `LevelSampler`
- `.Sample() methods.
- `Syslog`
- `.Write()`, `.WriteLevel()`, and `.Close()` methods.
- `.WriteLevel()` with an `InvalidLevel`.
- `Writer`
- `.Write()` short write and error cases.
- `MultiLevelWriter` `.WriteLevel()` and for `.Write()` error and `.Close()` cases.
- test of unmarshalling a level byte returns correct error.
- CBOR decodeStream
- `.decodeFloat()`, `.binaryFmt()`, `.DecodeIfBinaryToString()`, `.DecodeObjectToStr()`, `.DecodeIfBinaryToBytes()`, `.decodeTagData()`, and `.decodeSimpleFloat()`
- handling of invalid UTF-8 sequences
- handling of UTC times.
- handling of timestamps
- handling of various map lengths
Restructure `Event` `.caller()` so we test for ok and eliminate untestable coverage hole.
Restructure `Context` `.Err()` when the `ErrorStackMarshaler` returns a `nil` so there's code to cover.
Inverted logic for`Event` `.Caller()`'s call to `runtime.Caller()` for simpler testing.
Inverted logic for `Array` `.putArray()` and `Event` `.putEvent()` so there isn't uncoverable code.
Restructure `Field` `.appendFieldList()` to early return when `ErrorStackMarshaler` returns a `nil`
Added comments for things we can't get coverage on.
Did a go fmt ./...
Coverage of core is now 100% on `Array`, `Context`, `Ctx`, `Event`, `Field`, `Hook`, and `Syslog`.
Coverage of `Globals`, `Log`, `Sampler`, and `Writer` is almost all except some real edge-cases.
JSON encoder coverage is 100%
CBOR encoder coverage is 96.3% with base, cbor, string, time and types at 100% and decode_stream (which is lacks coverage on some panic states, and two incorrect coverage-tool lapses)
* Fix CBOR tests for StackMarshaler
Forgot to use the `decodeIfBinaryToString()`
* Added documentation for DurationFieldFormat
Added documentation for the new option added in PR#733
Added code markers some references to logger func/types.
Also, did a format-document pass to get rid of trailing blanks,
missing/extra blank lines, and other markdown warnings.
* Added documentation for Concurrency Safety
Added documentation to the Concurrency Safety section about not referencing
Event objects after they are written.
Closes#731
* Ensure that Event and Array objects returned to pool are cleared
Help ensure no corruptible state remains in objects being returned to the pool.
Always clear the contextual properties to ensure the recycled (or erroneously referenced)
Event or Array are not accidentally used/shared.
Sets the truncates the buffer (setting length, not capacity, to zero).
Make it really obvious when you hold references as mentioned in #733
Clarified the documentation about holding references to CreateDict() events.
Copies over event settings for ctx, hooks, and stack
- Fix missing context for Event.appendObjects passes event's stack, ctx, and hooks (ch).
- Add Array.Errs support.
- Context.Errs, Event.Errs, use new Array.Errs()
- Array.Err handles nil correctly.
- Fix Event.Err code ignoring modified event in ErrorStackMarshaler handling.
- Fix Fields.appendFieldList when ErrorMarshalFunc returns a nil.
- Fields.appendFieldList does no longer adds the ErrorStackFieldName field when ErrorStackMarshaler returns nil.
- Don't call the ErrorMarshalFunc on nil errors.
- Removed unreachable code NOP in Context.Array
- Rewrite ErrorMarshalFunc testing.
- Made diode tests more stable.
- Log copy error in test.
- Address review comments
- Added CreateArray() and CreateDict() for both Context and Event and deprecate the Arr() and Dict().
Array now carries then stack/context/hooks so they are available to LogObjectMarshal of Array elements.
Added unit tests for error marshal that returns an interface{}
* Improve code coverage before adding Objects
* Refactor ErrorMarshal tests.
Added testing of the error marshal in Fields Reduce the duplication of the test data and make it clearer what the "wants" represent.
* Add Objects support to Fields, Event, Context
* Add support for Object Fields
Passed as []LogObjectMarshaler.
* Fixed syntax of ExampleContext_Objects
Seems 1.24 accepts variadic for arrays and understands covariance but 1.21 doesn't.
* Fix problem with []uint8 serialized as a Base64 string
* Better syntax in the example use of Objects
* Add array handling of IPAddr and IPPrefix
Updated documentation, benchmark, and tests including catching up some missing.
Cleaned up couple lint messages
* Added cbor encoding for []net.IP and []net.IPNet
* Fix binary_test
Typos galore, thanks CI
* Remove feral x character
* Added IPAddrs and IPPrefixes tests for json encoder
* Increase code coverage and test cleanup
Added Type to the BenchmarkLogFieldType and BenchmarkContexdtFieldType test cases, also to log_test.go
Moved the test-fixture data for them and also shared them with new event test for nil events.
Added a couple strings for encodeByteTest for FF, CR, LF
Added complete cbor testing for AppendInt*, AppendInts*, AppendUint*, and AppendUints* methods.
Added test for float IsNaN and Inf(0) and Inf(-1).
Added all min/max/smallest value tests for ints and floats
Extended the Array test to include IPPrefix, MACAddr, Interface, and object marshaled.
Better test of MarshalZerologObject.
Added test for encoder AppendStrings and AppendStringers.
* Remove merge detritus.
* Remove code duplication when appending objects
* Add missing Stringers support to Context
* Add test cases for Err and Object in Array
* Add missing benchmark for Events and Contexts
Events: Any, Bytes, Hex, Float32, Floats32, Stringer, Stringers, Timestamp
Context: Any, Bytes, Hex, Float32, Floats32, Stringers
(also renamed Float,Floats to Float64,Floats64)
* Add test of MarshalZeroLogObject of error
* Build out Event test cases
Test of nil Event
- write
- Array, Dict
- Fields
- Int8, Ints8, Int16, Ints16, Int32, Ints32, Int64, Ints64
- Uint8, Uints8, Uint16, Uints16, Uint32, Uints32, Uint64, Uints64
- RawCBOR, RawJSON, EmbedObject
- Stringers
- Caller, CallerSkip, Stack
- Send, Msg, Msgf, MsgFunc
- (renamed tests of Float, Floats to Float64, Floats64)
Added test of MsgFunc
* Add more tests
- Dur (With)
- Any (With, Fields, Fields map, Disabled)
- Interface
- Stack (Fields)
Fix issue with testing a nil loggableError
* Split out the With tests again type arrays
Simplifies the "want" maintenance
* Add missing test fixture data
Bytes, Floats32, Ints8, Ints16, Ints32, Ints64, Uints8, Uints16, Uints32, Uints64, RawJSON, RawCBOR
Stringers is now an array (not a single Stringer)
(also renamed Float, Floats to Float64, Floats64)
* Add examples for IPAddrs, IPPrefixes, Times
Missing examples that increase coverage
* Build out the complete ErrorMarshalFunc tests
* Add AppendStrings to CBOR tests
* Add CBOR AppendTimes, AppendDuration, AppendDurations tests
* Add CBOR tests
- BeginMarker, EndMarker, AppendArrayDim, AppendLineBreak
- AppendObjectData
- AppendIterface
- AppendType
- AppendHex
- Empty arrays for
- Bools
- Floats32, Floats64
- Large arrays for
- Bools,
- Uints8, Uints16, Uints32, Uints64
- Floats32, Floats64
- IPAddrs, IPPrefixes
- Small arrays for
- Ints, Ints8, Ints16, Ints32, Ints64
- Uints, Uints32, Uints64
- Floats32, Floats64
* Add CBOR test for AppendKey
* Added more string encoding tests
Test escape character handling.
* Fix test import cycle
* Rename hex to hexCharacters to avoid namespace.
* Remove leftover comment
* Add test cases to share between CBOR and JSON tests
* Switched CBOR to shared test cases
* Add JSON test for AppendKey
* Switch to shared test cases
Added test for AppendStringer
* Added JSON test
- AppendNil
- AppendBeginMarker, AppendEndMarker
- AppendArrayStart, AppendArrayEnd
- AppendArrayDelim
- AppendLineBreak
- AppendObjectData
- AppendInterface
- AppendBool, AppendBools
* Add JSON time tests
- AppendTime, AppendTimes
- AppendTime (past/present) (integer/float)
- AppendDuration, AppendDurations
* Added JSON tests for plurals
Split out the Int and Float tests into distinct files.
Add
- AppendInt
- AppendInts8, AppendInts16, AppendInts32, AppendInts64, AppendInts
- AppendUints8, AppendUints16, AppendUints32, AppendUints64, AppendUints
- AppendFloats32, AppendFloats64
* Add array handling of IPAddr and IPPrefix
Updated documentation, benchmark, and tests including catching up some missing.
Cleaned up couple lint messages
* Added cbor encoding for []net.IP and []net.IPNet
* Fix binary_test
Typos galore, thanks CI
* Remove feral x character
* Added IPAddrs and IPPrefixes tests for json encoder