From 1f50797d7d24e4cf3a6407203bd694f3d35de724 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 12:29:36 -0700 Subject: [PATCH 1/9] Bump actions/setup-go from 3 to 4 (#529) Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 82a75a4..816f164 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: ${{ matrix.go-version }} - name: Checkout code From 64a5863c5e2ffecb0ffadd1cfa90f3a9993f8320 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 11:56:52 +0200 Subject: [PATCH 2/9] 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](https://github.com/rs/xid/compare/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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 27b9925..6ec5abc 100644 --- a/go.mod +++ b/go.mod @@ -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 ) diff --git a/go.sum b/go.sum index ba05bcb..50b6327 100644 --- a/go.sum +++ b/go.sum @@ -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= From a712f6193674c928bb853f2cb40e0ed68ebb5ef7 Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 21 Apr 2023 13:55:19 +0400 Subject: [PATCH 3/9] doc(readme): explain zerolog with context (#544) Add section about `context.Context` usage with zerolog instance --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e8cbfc2..d424a72 100644 --- a/README.md +++ b/README.md @@ -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) @@ -511,6 +511,30 @@ stdlog.Print("hello world") // Output: {"foo":"bar","message":"hello world"} ``` +### context.Context integration + +The `Logger` isntance could be attached to `context.Context` values with `logger.WithContext(ctx)` +and extracted from it using `zerolog.Ctx(ctx)`. + +Example to add logger to context: +```go +// this code attach logger instance to context fields +ctx := context.Background() +logger := zerolog.New(os.Stdout) +ctx = logger.WithContext(ctx) +someFunc(ctx) +``` + +Extracting logger from context: +```go +func someFunc(ctx context.Context) { + // get logger from context. if it's nill, then `zerolog.DefaultContextLogger` is returned, + // if `DefaultContextLogger` is nil, then disabled logger returned. + logger := zerolog.Ctx(ctx) + logger.Info().Msg("Hello") +} +``` + ### Integration with `net/http` The `github.com/rs/zerolog/hlog` package provides some helpers to integrate zerolog with `http.Handler`. From 927516bcf137771377cc98fe2567688d30fb4132 Mon Sep 17 00:00:00 2001 From: Koung <20951663+koungkub@users.noreply.github.com> Date: Mon, 1 May 2023 19:04:49 +0700 Subject: [PATCH 4/9] doc(readme): fix a typo (#548) Co-authored-by: jirasak --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d424a72..68df81e 100644 --- a/README.md +++ b/README.md @@ -513,7 +513,7 @@ stdlog.Print("hello world") ### context.Context integration -The `Logger` isntance could be attached to `context.Context` values with `logger.WithContext(ctx)` +The `Logger` instance could be attached to `context.Context` values with `logger.WithContext(ctx)` and extracted from it using `zerolog.Ctx(ctx)`. Example to add logger to context: From 8981d80ed338dab0fc9bec56587e0bd0e3c4c40d Mon Sep 17 00:00:00 2001 From: Angus <45074804+AngusGMorrison@users.noreply.github.com> Date: Thu, 11 May 2023 13:00:42 +0100 Subject: [PATCH 5/9] Correct logger variable name in stdout example (#549) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 68df81e..312b3b1 100644 --- a/README.md +++ b/README.md @@ -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() From 4612e098d222bd30042ed909a474c88cd773850f Mon Sep 17 00:00:00 2001 From: Basten Gao Date: Mon, 15 May 2023 20:07:32 +0800 Subject: [PATCH 6/9] Fix error chain from pkgerrors (#552) --- pkgerrors/stacktrace.go | 23 ++++++++++++++++++++--- pkgerrors/stacktrace_test.go | 9 +++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pkgerrors/stacktrace.go b/pkgerrors/stacktrace.go index 01420e6..2f62ffd 100644 --- a/pkgerrors/stacktrace.go +++ b/pkgerrors/stacktrace.go @@ -42,15 +42,32 @@ func frameField(f errors.Frame, s *state, c rune) string { // MarshalStack implements pkg/errors stack trace marshaling. // -// zerolog.ErrorStackMarshaler = MarshalStack +// zerolog.ErrorStackMarshaler = MarshalStack func MarshalStack(err error) interface{} { type stackTracer interface { StackTrace() errors.StackTrace } - sterr, ok := err.(stackTracer) - if !ok { + var sterr stackTracer + var ok bool + for err != nil { + sterr, ok = err.(stackTracer) + if ok { + break + } + + u, ok := err.(interface { + Unwrap() error + }) + if !ok { + return nil + } + + err = u.Unwrap() + } + if sterr == nil { return nil } + st := sterr.StackTrace() s := &state{} out := make([]map[string]string, 0, len(st)) diff --git a/pkgerrors/stacktrace_test.go b/pkgerrors/stacktrace_test.go index 4f9838c..5a13832 100644 --- a/pkgerrors/stacktrace_test.go +++ b/pkgerrors/stacktrace_test.go @@ -4,6 +4,7 @@ package pkgerrors import ( "bytes" + "fmt" "regexp" "testing" @@ -17,11 +18,11 @@ func TestLogStack(t *testing.T) { out := &bytes.Buffer{} log := zerolog.New(out) - err := errors.Wrap(errors.New("error message"), "from error") + err := fmt.Errorf("from error: %w", errors.New("error message")) log.Log().Stack().Err(err).Msg("") got := out.String() - want := `\{"stack":\[\{"func":"TestLogStack","line":"20","source":"stacktrace_test.go"\},.*\],"error":"from error: error message"\}\n` + want := `\{"stack":\[\{"func":"TestLogStack","line":"21","source":"stacktrace_test.go"\},.*\],"error":"from error: error message"\}\n` if ok, _ := regexp.MatchString(want, got); !ok { t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want) } @@ -33,11 +34,11 @@ func TestLogStackFromContext(t *testing.T) { out := &bytes.Buffer{} log := zerolog.New(out).With().Stack().Logger() // calling Stack() on log context instead of event - err := errors.Wrap(errors.New("error message"), "from error") + err := fmt.Errorf("from error: %w", errors.New("error message")) log.Log().Err(err).Msg("") // not explicitly calling Stack() got := out.String() - want := `\{"stack":\[\{"func":"TestLogStackFromContext","line":"36","source":"stacktrace_test.go"\},.*\],"error":"from error: error message"\}\n` + want := `\{"stack":\[\{"func":"TestLogStackFromContext","line":"37","source":"stacktrace_test.go"\},.*\],"error":"from error: error message"\}\n` if ok, _ := regexp.MatchString(want, got); !ok { t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want) } From b662f088b9b76644b34df7eecd4053100a7c0c01 Mon Sep 17 00:00:00 2001 From: Harish Kukreja Date: Sun, 11 Jun 2023 11:20:21 -0400 Subject: [PATCH 7/9] docs: context.Timestamp uses zerolog.TimeFieldFormat (#554) --- context.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/context.go b/context.go index f398e31..39397d9 100644 --- a/context.go +++ b/context.go @@ -329,8 +329,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 { From 9070d49a1a4154c819e9c5ae6c923f3cc916d959 Mon Sep 17 00:00:00 2001 From: stergiotis Date: Mon, 19 Jun 2023 01:30:44 +0200 Subject: [PATCH 8/9] Add event method RawCBOR analogous to RawJSON (#556) CBOR is encoded as data-url in JSON encoding and tagged in CBOR encoding. --- encoder_cbor.go | 3 +++ encoder_json.go | 12 ++++++++++ event.go | 12 ++++++++++ internal/cbor/cbor.go | 3 ++- internal/cbor/decode_stream.go | 40 ++++++++++++++++++++++++++++++++++ internal/cbor/string.go | 22 +++++++++++++++++++ log_test.go | 3 ++- 7 files changed, 93 insertions(+), 2 deletions(-) diff --git a/encoder_cbor.go b/encoder_cbor.go index 7b0dafe..36cb994 100644 --- a/encoder_cbor.go +++ b/encoder_cbor.go @@ -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. diff --git a/encoder_json.go b/encoder_json.go index 0e0450e..6f96c68 100644 --- a/encoder_json.go +++ b/encoder_json.go @@ -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) diff --git a/event.go b/event.go index 2e736c8..5fb4653 100644 --- a/event.go +++ b/event.go @@ -318,6 +318,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 { diff --git a/internal/cbor/cbor.go b/internal/cbor/cbor.go index bc54e37..1bf1443 100644 --- a/internal/cbor/cbor.go +++ b/internal/cbor/cbor.go @@ -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 diff --git a/internal/cbor/decode_stream.go b/internal/cbor/decode_stream.go index fc16f98..616bed6 100644 --- a/internal/cbor/decode_stream.go +++ b/internal/cbor/decode_stream.go @@ -5,6 +5,7 @@ package cbor import ( "bufio" "bytes" + "encoding/base64" "fmt" "io" "math" @@ -213,6 +214,31 @@ func decodeString(src *bufio.Reader, noQuotes bool) []byte { } return append(result, '"') } +func decodeStringToDataUrl(src *bufio.Reader, mimeType string) []byte { + pb := readByte(src) + major := pb & maskOutAdditionalType + minor := pb & maskOutMajorType + if major != majorTypeByteString { + panic(fmt.Errorf("Major type is: %d in decodeString", major)) + } + length := decodeIntAdditionalType(src, minor) + l := int(length) + enc := base64.StdEncoding + lEnc := enc.EncodedLen(l) + result := make([]byte, len("\"data:;base64,\"")+len(mimeType)+lEnc) + dest := result + u := copy(dest, "\"data:") + dest = dest[u:] + u = copy(dest, mimeType) + dest = dest[u:] + u = copy(dest, ";base64,") + dest = dest[u:] + pbs := readNBytes(src, l) + enc.Encode(dest, pbs) + dest = dest[lEnc:] + dest[0] = '"' + return result +} func decodeUTF8String(src *bufio.Reader) []byte { pb := readByte(src) @@ -349,6 +375,20 @@ func decodeTagData(src *bufio.Reader) []byte { switch minor { case additionalTypeTimestamp: return decodeTimeStamp(src) + case additionalTypeIntUint8: + val := decodeIntAdditionalType(src, minor) + switch byte(val) { + case additionalTypeEmbeddedCBOR: + pb := readByte(src) + dataMajor := pb & maskOutAdditionalType + if dataMajor != majorTypeByteString { + panic(fmt.Errorf("Unsupported embedded Type: %d in decodeEmbeddedCBOR", dataMajor)) + } + src.UnreadByte() + return decodeStringToDataUrl(src, "application/cbor") + default: + panic(fmt.Errorf("Unsupported Additional Tag Type: %d in decodeTagData", val)) + } // Tag value is larger than 256 (so uint16). case additionalTypeIntUint16: diff --git a/internal/cbor/string.go b/internal/cbor/string.go index a33890a..9fc9a4f 100644 --- a/internal/cbor/string.go +++ b/internal/cbor/string.go @@ -93,3 +93,25 @@ func AppendEmbeddedJSON(dst, s []byte) []byte { } return append(dst, s...) } + +// AppendEmbeddedCBOR adds a tag and embeds input CBOR as such. +func AppendEmbeddedCBOR(dst, s []byte) []byte { + major := majorTypeTags + minor := additionalTypeEmbeddedCBOR + + // Append the TAG to indicate this is Embedded JSON. + dst = append(dst, major|additionalTypeIntUint8) + dst = append(dst, minor) + + // Append the CBOR Object as Byte String. + major = majorTypeByteString + + l := len(s) + if l <= additionalMax { + lb := byte(l) + dst = append(dst, major|lb) + } else { + dst = appendCborTypePrefix(dst, major, uint64(l)) + } + return append(dst, s...) +} diff --git a/log_test.go b/log_test.go index aa84750..0e64c49 100644 --- a/log_test.go +++ b/log_test.go @@ -320,6 +320,7 @@ func TestFields(t *testing.T) { Bytes("bytes", []byte("bar")). Hex("hex", []byte{0x12, 0xef}). RawJSON("json", []byte(`{"some":"json"}`)). + RawCBOR("cbor", []byte{0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05}). Func(func(e *Event) { e.Str("func", "func_output") }). AnErr("some_err", nil). Err(errors.New("some error")). @@ -344,7 +345,7 @@ func TestFields(t *testing.T) { Time("time", time.Time{}). TimeDiff("diff", now, now.Add(-10*time.Second)). Msg("") - if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","string":"foo","stringer":"127.0.0.1","stringer_nil":null,"bytes":"bar","hex":"12ef","json":{"some":"json"},"func":"func_output","error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"IPv4":"192.168.0.100","IPv6":"2001:db8:85a3::8a2e:370:7334","Mac":"00:14:22:01:23:45","Prefix":"192.168.0.100/24","float32":11.1234,"float64":12.321321321,"dur":1000,"time":"0001-01-01T00:00:00Z","diff":10000}`+"\n"; got != want { + if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","string":"foo","stringer":"127.0.0.1","stringer_nil":null,"bytes":"bar","hex":"12ef","json":{"some":"json"},"cbor":"data:application/cbor;base64,gwGCAgOCBAU=","func":"func_output","error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"IPv4":"192.168.0.100","IPv6":"2001:db8:85a3::8a2e:370:7334","Mac":"00:14:22:01:23:45","Prefix":"192.168.0.100/24","float32":11.1234,"float64":12.321321321,"dur":1000,"time":"0001-01-01T00:00:00Z","diff":10000}`+"\n"; got != want { t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want) } } From 61485f38578672cdb7019c32230055a2c70a4620 Mon Sep 17 00:00:00 2001 From: finkandreas Date: Wed, 12 Jul 2023 14:29:38 +0200 Subject: [PATCH 9/9] Fix #564 (#565) This could be a potential fix for #564 --- log.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/log.go b/log.go index 0b51676..e6f6f7c 100644 --- a/log.go +++ b/log.go @@ -309,7 +309,9 @@ func (l Logger) Sample(s Sampler) Logger { // Hook returns a logger with the h Hook. func (l Logger) Hook(h Hook) Logger { - l.hooks = append(l.hooks, h) + newHooks := make([]Hook, len(l.hooks), len(l.hooks)+1) + copy(newHooks, l.hooks) + l.hooks = append(newHooks, h) return l }