Skip to content

New Text Encoder with Flattened Dot-Separated Keys for Improved Readability and Performance #1509

@sagarsuperuser

Description

@sagarsuperuser

Is your feature request related to a problem? Please describe.
Zap’s current encoders (JSON, console) don’t provide an easy-to-read text output for nested objects:

  • JSONEncoder is structured but verbose and less operator-friendly for quick inspection in terminals.
  • ConsoleEncoder is compact but does not handle nested objects in a way that makes them easy to grep or read.
  • Alternatives like Kubernetes’ klog textlogger and Go’s slog.TextHandler provide text output, but are either slower or less flexible.

Describe the solution you'd like
Introduce a new zapcore.Encoder implementation (e.g., TextEncoder) with the following features:

  1. Dot-flattened keys for nested objects
    Example:

    logger.Info("user created", zap.Any("user", User{
      Name: "Alice",
      Addr: Addr{City: "Bangalore", Zip: "560001"},
    }))

    Current JSONEncoder output:

    {"user": {"Name": "Alice", "Addr": {"City": "Bangalore", "Zip": "560001"}}}

    Proposed TextEncoder output:

    "user.Name"="Alice" "user.Addr.City"="Bangalore" "user.Addr.Zip"="560001"
    

    This makes logs more human-readable and grep-friendly.

  2. Performance improvements
    Benchmarks show this encoder is faster than both k8s textlogger and slog.TextHandler, while competitive with zap’s json encoder.

  3. Seamless zap integration

    • Provided as a zapcore.Encoder implementation.
    • Configurable via zapcore.NewTextEncoder(cfg) or zap configuration.

Describe alternatives you've considered

  • Using JSONEncoder → too verbose and not grep-friendly.
  • Using ConsoleEncoder → compact but nested structures are still hard to scan.
  • Using Kubernetes’ klog textlogger / slog.TextHandler → slower and not integrated with zap.

Is this a breaking change?
No. This would be an additive change introducing a new encoder.
Existing users of JSONEncoder and ConsoleEncoder remain unaffected.


Additional context

Log a message and 10 fields

(https://github.com/sagarsuperuser/zap/tree/text-encoder#log-a-message-and-10-fields)

Package Time (ns/op) Time % vs Zap Objects Allocated
zap (json) 656 +0% 5 allocs/op
⚡ zap (text) 852 +30% 5 allocs/op
⚡ zap (sugared json) 854 +30% 10 allocs/op
⚡ zap (sugared text) 1071 +63% 10 allocs/op
zerolog 318 -52% 1 alloc/op
go-kit 1989 +203% 56 allocs/op
slog 2122 +224% 41 allocs/op
slog (LogAttrs) 2161 +229% 40 allocs/op
apex/log 10762 +1539% 64 allocs/op
log15 12049 +1736% 73 allocs/op
logrus 12721 +1840% 84 allocs/op
klog/v2 textlogger 2776 +323% 45 allocs/op

Example log with nested fields:

(https://github.com/sagarsuperuser/zap/tree/text-encoder?tab=readme-ov-file#example-logging-structured-http-requestresponse-using-text-format)

"level"="info" "ts"=1758088355.259905 "caller"="zap_test/main.go:57" "msg"="served" "http.request.method"="GET" "http.request.url"="/api/v1/users" "http.response.status"=200 "http.response.bytes"=1234

Next Steps

Would the maintainers be open to including this encoder in zap core as an additional zapcore.Encoder implementation?
I can submit a draft PR with tests, benchmarks, and documentation once there’s guidance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions