Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rs/zerolog
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.29.1
Choose a base ref
...
head repository: rs/zerolog
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.30.0
Choose a head ref
  • 10 commits
  • 16 files changed
  • 11 contributors

Commits on Apr 17, 2023

  1. Bump github.com/rs/xid from 1.4.0 to 1.5.0 (#542)

    Bumps [github.com/rs/xid](https://github.com/rs/xid) from 1.4.0 to 1.5.0.
    - [Release notes](https://github.com/rs/xid/releases)
    - [Commits](rs/xid@v1.4.0...v1.5.0)
    
    ---
    updated-dependencies:
    - dependency-name: github.com/rs/xid
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Apr 17, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    64a5863 View commit details

Commits on Apr 21, 2023

  1. doc(readme): explain zerolog with context (#544)

    Add section about `context.Context` usage with zerolog instance
    g4s8 authored Apr 21, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    a712f61 View commit details

Commits on May 1, 2023

  1. doc(readme): fix a typo (#548)

    Co-authored-by: jirasak <jirasak@lmwn.com>
    koungkub and jirasak authored May 1, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    927516b View commit details

Commits on May 11, 2023

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    8981d80 View commit details

Commits on May 15, 2023

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    4612e09 View commit details

Commits on Jun 11, 2023

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    b662f08 View commit details

Commits on Jun 18, 2023

  1. Add event method RawCBOR analogous to RawJSON (#556)

    CBOR is encoded as data-url in JSON encoding and tagged in CBOR encoding.
    stergiotis authored Jun 18, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9070d49 View commit details

Commits on Jul 12, 2023

  1. Fix #564 (#565)

    This could be a potential fix for #564
    finkandreas authored Jul 12, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    61485f3 View commit details

Commits on Jul 25, 2023

  1. Allow callers to pass go context through to hooks (#559)

    Add Ctx(context.Context) to Event and Context, allowing
    log.Info().Ctx(ctx).Msg("hello").  Registered hooks can retrieve the
    context from Event.GetCtx().  Facilitates writing hooks which fetch
    tracing context from the go context.
    danielbprice authored Jul 25, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    873cbf1 View commit details

Commits on Jul 29, 2023

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    06ec071 View commit details
Showing with 304 additions and 22 deletions.
  1. +72 −2 README.md
  2. +9 −0 benchmark_test.go
  3. +12 −1 context.go
  4. +3 −0 encoder_cbor.go
  5. +12 −0 encoder_json.go
  6. +39 −3 event.go
  7. +1 −1 go.mod
  8. +2 −2 go.sum
  9. +34 −0 hook_test.go
  10. +2 −1 internal/cbor/cbor.go
  11. +40 −0 internal/cbor/decode_stream.go
  12. +22 −0 internal/cbor/string.go
  13. +24 −3 log.go
  14. +7 −2 log_test.go
  15. +20 −3 pkgerrors/stacktrace.go
  16. +5 −4 pkgerrors/stacktrace_test.go
74 changes: 72 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ Find out [who uses zerolog](https://github.com/rs/zerolog/wiki/Who-uses-zerolog)
* [Sampling](#log-sampling)
* [Hooks](#hooks)
* [Contextual fields](#contextual-logging)
* `context.Context` integration
* [`context.Context` integration](#contextcontext-integration)
* [Integration with `net/http`](#integration-with-nethttp)
* [JSON and CBOR encoding formats](#binary-encoding)
* [Pretty logging for development](#pretty-logging)
@@ -499,7 +499,7 @@ log.Ctx(ctx).Info().Msg("hello world")
### Set as standard logger output

```go
log := zerolog.New(os.Stdout).With().
stdlog := zerolog.New(os.Stdout).With().
Str("foo", "bar").
Logger()

@@ -511,6 +511,58 @@ stdlog.Print("hello world")
// Output: {"foo":"bar","message":"hello world"}
```

### context.Context integration

Go contexts are commonly passed throughout Go code, and this can help you pass
your Logger into places it might otherwise be hard to inject. The `Logger`
instance may be attached to Go context (`context.Context`) using
`Logger.WithContext(ctx)` and extracted from it using `zerolog.Ctx(ctx)`.
For example:

```go
func f() {
logger := zerolog.New(os.Stdout)
ctx := context.Background()

// Attach the Logger to the context.Context
ctx = logger.WithContext(ctx)
someFunc(ctx)
}

func someFunc(ctx context.Context) {
// Get Logger from the go Context. if it's nil, then
// `zerolog.DefaultContextLogger` is returned, if
// `DefaultContextLogger` is nil, then a disabled logger is returned.
logger := zerolog.Ctx(ctx)
logger.Info().Msg("Hello")
}
```

A second form of `context.Context` integration allows you to pass the current
context.Context into the logged event, and retrieve it from hooks. This can be
useful to log trace and span IDs or other information stored in the go context,
and facilitates the unification of logging and tracing in some systems:

```go
type TracingHook struct{}

func (h TracingHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
ctx := e.Ctx()
spanId := getSpanIdFromContext(ctx) // as per your tracing framework
e.Str("span-id", spanId)
}

func f() {
// Setup the logger
logger := zerolog.New(os.Stdout)
logger = logger.Hook(TracingHook{})

ctx := context.Background()
// Use the Ctx function to make the context available to the hook
logger.Info().Ctx(ctx).Msg("Hello")
}
```

### Integration with `net/http`

The `github.com/rs/zerolog/hlog` package provides some helpers to integrate zerolog with `http.Handler`.
@@ -703,6 +755,8 @@ Log a static string, without any context or `printf`-style templating:

## Caveats

### Field duplication

Note that zerolog does no de-duplication of fields. Using the same key multiple times creates multiple keys in final JSON:

```go
@@ -714,3 +768,19 @@ logger.Info().
```

In this case, many consumers will take the last value, but this is not guaranteed; check yours if in doubt.

### Concurrency safety

Be careful when calling UpdateContext. It is not concurrency safe. Use the With method to create a child logger:

```go
func handler(w http.ResponseWriter, r *http.Request) {
// Create a child logger for concurrency safety
logger := log.Logger.With().Logger()

// Add context fields, for example User-Agent from HTTP headers
logger.UpdateContext(func(c zerolog.Context) zerolog.Context {
...
})
}
```
9 changes: 9 additions & 0 deletions benchmark_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package zerolog

import (
"context"
"errors"
"io/ioutil"
"net"
@@ -160,6 +161,7 @@ func BenchmarkLogFieldType(b *testing.B) {
{"a", "a", 0},
}
errs := []error{errors.New("a"), errors.New("b"), errors.New("c"), errors.New("d"), errors.New("e")}
ctx := context.Background()
types := map[string]func(e *Event) *Event{
"Bool": func(e *Event) *Event {
return e.Bool("k", bools[0])
@@ -191,6 +193,9 @@ func BenchmarkLogFieldType(b *testing.B) {
"Errs": func(e *Event) *Event {
return e.Errs("k", errs)
},
"Ctx": func(e *Event) *Event {
return e.Ctx(ctx)
},
"Time": func(e *Event) *Event {
return e.Time("k", times[0])
},
@@ -284,6 +289,7 @@ func BenchmarkContextFieldType(b *testing.B) {
{"a", "a", 0},
}
errs := []error{errors.New("a"), errors.New("b"), errors.New("c"), errors.New("d"), errors.New("e")}
ctx := context.Background()
types := map[string]func(c Context) Context{
"Bool": func(c Context) Context {
return c.Bool("k", bools[0])
@@ -318,6 +324,9 @@ func BenchmarkContextFieldType(b *testing.B) {
"Errs": func(c Context) Context {
return c.Errs("k", errs)
},
"Ctx": func(c Context) Context {
return c.Ctx(ctx)
},
"Time": func(c Context) Context {
return c.Time("k", times[0])
},
13 changes: 12 additions & 1 deletion context.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package zerolog

import (
"context"
"fmt"
"io/ioutil"
"math"
@@ -165,6 +166,15 @@ func (c Context) Err(err error) Context {
return c.AnErr(ErrorFieldName, err)
}

// Ctx adds the context.Context to the logger context. The context.Context is
// not rendered in the error message, but is made available for hooks to use.
// A typical use case is to extract tracing information from the
// context.Context.
func (c Context) Ctx(ctx context.Context) Context {
c.l.ctx = ctx
return c
}

// Bool adds the field key with val as a bool to the logger context.
func (c Context) Bool(key string, b bool) Context {
c.l.context = enc.AppendBool(enc.AppendKey(c.l.context, key), b)
@@ -329,8 +339,9 @@ func (ts timestampHook) Run(e *Event, level Level, msg string) {

var th = timestampHook{}

// Timestamp adds the current local time as UNIX timestamp to the logger context with the "time" key.
// Timestamp adds the current local time to the logger context with the "time" key, formatted using zerolog.TimeFieldFormat.
// To customize the key name, change zerolog.TimestampFieldName.
// To customize the time format, change zerolog.TimeFieldFormat.
//
// NOTE: It won't dedupe the "time" key if the *Context has one already.
func (c Context) Timestamp() Context {
3 changes: 3 additions & 0 deletions encoder_cbor.go
Original file line number Diff line number Diff line change
@@ -24,6 +24,9 @@ func init() {
func appendJSON(dst []byte, j []byte) []byte {
return cbor.AppendEmbeddedJSON(dst, j)
}
func appendCBOR(dst []byte, c []byte) []byte {
return cbor.AppendEmbeddedCBOR(dst, c)
}

// decodeIfBinaryToString - converts a binary formatted log msg to a
// JSON formatted String Log message.
12 changes: 12 additions & 0 deletions encoder_json.go
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ package zerolog
// JSON encoded byte stream.

import (
"encoding/base64"
"github.com/rs/zerolog/internal/json"
)

@@ -25,6 +26,17 @@ func init() {
func appendJSON(dst []byte, j []byte) []byte {
return append(dst, j...)
}
func appendCBOR(dst []byte, cbor []byte) []byte {
dst = append(dst, []byte("\"data:application/cbor;base64,")...)
l := len(dst)
enc := base64.StdEncoding
n := enc.EncodedLen(len(cbor))
for i := 0; i < n; i++ {
dst = append(dst, '.')
}
enc.Encode(dst[l:], cbor)
return append(dst, '"')
}

func decodeIfBinaryToString(in []byte) string {
return string(in)
42 changes: 39 additions & 3 deletions event.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package zerolog

import (
"context"
"fmt"
"net"
"os"
@@ -24,9 +25,10 @@ type Event struct {
w LevelWriter
level Level
done func(msg string)
stack bool // enable error stack trace
ch []Hook // hooks from context
skipFrame int // The number of additional frames to skip when printing the caller.
stack bool // enable error stack trace
ch []Hook // hooks from context
skipFrame int // The number of additional frames to skip when printing the caller.
ctx context.Context // Optional Go context for event
}

func putEvent(e *Event) {
@@ -318,6 +320,18 @@ func (e *Event) RawJSON(key string, b []byte) *Event {
return e
}

// RawCBOR adds already encoded CBOR to the log line under key.
//
// No sanity check is performed on b
// Note: The full featureset of CBOR is supported as data will not be mapped to json but stored as data-url
func (e *Event) RawCBOR(key string, b []byte) *Event {
if e == nil {
return e
}
e.buf = appendCBOR(enc.AppendKey(e.buf, key), b)
return e
}

// AnErr adds the field key with serialized err to the *Event context.
// If err is nil, no field is added.
func (e *Event) AnErr(key string, err error) *Event {
@@ -405,6 +419,28 @@ func (e *Event) Stack() *Event {
return e
}

// Ctx adds the Go Context to the *Event context. The context is not rendered
// in the output message, but is available to hooks and to Func() calls via the
// GetCtx() accessor. A typical use case is to extract tracing information from
// the Go Ctx.
func (e *Event) Ctx(ctx context.Context) *Event {
if e != nil {
e.ctx = ctx
}
return e
}

// GetCtx retrieves the Go context.Context which is optionally stored in the
// Event. This allows Hooks and functions passed to Func() to retrieve values
// which are stored in the context.Context. This can be useful in tracing,
// where span information is commonly propagated in the context.Context.
func (e *Event) GetCtx() context.Context {
if e == nil || e.ctx == nil {
return context.Background()
}
return e.ctx
}

// Bool adds the field key with val as a bool to the *Event context.
func (e *Event) Bool(key string, b bool) *Event {
if e == nil {
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -6,5 +6,5 @@ require (
github.com/coreos/go-systemd/v22 v22.5.0
github.com/mattn/go-colorable v0.1.12
github.com/pkg/errors v0.9.1
github.com/rs/xid v1.4.0
github.com/rs/xid v1.5.0
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -7,8 +7,8 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
34 changes: 34 additions & 0 deletions hook_test.go
Original file line number Diff line number Diff line change
@@ -2,10 +2,15 @@ package zerolog

import (
"bytes"
"context"
"io/ioutil"
"testing"
)

type contextKeyType int

var contextKey contextKeyType

var (
levelNameHook = HookFunc(func(e *Event, level Level, msg string) {
levelName := level.String()
@@ -31,6 +36,12 @@ var (
discardHook = HookFunc(func(e *Event, level Level, message string) {
e.Discard()
})
contextHook = HookFunc(func(e *Event, level Level, message string) {
contextData, ok := e.GetCtx().Value(contextKey).(string)
if ok {
e.Str("context-data", contextData)
}
})
)

func TestHook(t *testing.T) {
@@ -120,6 +131,29 @@ func TestHook(t *testing.T) {
log = log.Hook(discardHook)
log.Log().Msg("test message")
}},
{"Context/Background", `{"level":"info","message":"test message"}` + "\n", func(log Logger) {
log = log.Hook(contextHook)
log.Info().Ctx(context.Background()).Msg("test message")
}},
{"Context/nil", `{"level":"info","message":"test message"}` + "\n", func(log Logger) {
// passing `nil` where a context is wanted is against
// the rules, but people still do it.
log = log.Hook(contextHook)
log.Info().Ctx(nil).Msg("test message") // nolint
}},
{"Context/valid", `{"level":"info","context-data":"12345abcdef","message":"test message"}` + "\n", func(log Logger) {
ctx := context.Background()
ctx = context.WithValue(ctx, contextKey, "12345abcdef")
log = log.Hook(contextHook)
log.Info().Ctx(ctx).Msg("test message")
}},
{"Context/With/valid", `{"level":"info","context-data":"12345abcdef","message":"test message"}` + "\n", func(log Logger) {
ctx := context.Background()
ctx = context.WithValue(ctx, contextKey, "12345abcdef")
log = log.Hook(contextHook)
log = log.With().Ctx(ctx).Logger()
log.Info().Msg("test message")
}},
{"None", `{"level":"error"}` + "\n", func(log Logger) {
log.Error().Msg("")
}},
3 changes: 2 additions & 1 deletion internal/cbor/cbor.go
Original file line number Diff line number Diff line change
@@ -26,7 +26,8 @@ const (
additionalTypeBreak byte = 31

// Tag Sub-types.
additionalTypeTimestamp byte = 01
additionalTypeTimestamp byte = 01
additionalTypeEmbeddedCBOR byte = 63

// Extended Tags - from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
additionalTypeTagNetworkAddr uint16 = 260
Loading