Compare commits
10 Commits
97e8f3922b
...
3a569c99c0
Author | SHA1 | Date |
---|---|---|
a | 3a569c99c0 | |
finkandreas | 61485f3857 | |
stergiotis | 9070d49a1a | |
Harish Kukreja | b662f088b9 | |
Basten Gao | 4612e098d2 | |
Angus | 8981d80ed3 | |
Koung | 927516bcf1 | |
Kirill | a712f61936 | |
dependabot[bot] | 64a5863c5e | |
dependabot[bot] | 1f50797d7d |
|
@ -9,7 +9,7 @@ jobs:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
|
|
28
README.md
28
README.md
|
@ -30,7 +30,7 @@ Find out [who uses zlog](https://tuxpa.in/a/zlog/wiki/Who-uses-zlog) and add you
|
||||||
* [Sampling](#log-sampling)
|
* [Sampling](#log-sampling)
|
||||||
* [Hooks](#hooks)
|
* [Hooks](#hooks)
|
||||||
* [Contextual fields](#contextual-logging)
|
* [Contextual fields](#contextual-logging)
|
||||||
* `context.Context` integration
|
* [`context.Context` integration](#contextcontext-integration)
|
||||||
* [Integration with `net/http`](#integration-with-nethttp)
|
* [Integration with `net/http`](#integration-with-nethttp)
|
||||||
* [JSON and CBOR encoding formats](#binary-encoding)
|
* [JSON and CBOR encoding formats](#binary-encoding)
|
||||||
* [Pretty logging for development](#pretty-logging)
|
* [Pretty logging for development](#pretty-logging)
|
||||||
|
@ -505,7 +505,7 @@ log.Ctx(ctx).Info().Msg("hello world")
|
||||||
### Set as standard logger output
|
### Set as standard logger output
|
||||||
|
|
||||||
```go
|
```go
|
||||||
log := zlog.New(os.Stdout).With().
|
stdlog := zlog.New(os.Stdout).With().
|
||||||
Str("foo", "bar").
|
Str("foo", "bar").
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
|
@ -517,6 +517,30 @@ stdlog.Print("hello world")
|
||||||
// Output: {"foo":"bar","message":"hello world"}
|
// Output: {"foo":"bar","message":"hello world"}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### context.Context integration
|
||||||
|
|
||||||
|
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:
|
||||||
|
```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`
|
### Integration with `net/http`
|
||||||
|
|
||||||
The `tuxpa.in/a/zlog/hlog` package provides some helpers to integrate zlog with `http.Handler`.
|
The `tuxpa.in/a/zlog/hlog` package provides some helpers to integrate zlog with `http.Handler`.
|
||||||
|
|
|
@ -329,8 +329,9 @@ func (ts timestampHook) Run(e *Event, level Level, msg string) {
|
||||||
|
|
||||||
var th = timestampHook{}
|
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 zlog.TimeFieldFormat.
|
||||||
// To customize the key name, change zlog.TimestampFieldName.
|
// To customize the key name, change zlog.TimestampFieldName.
|
||||||
|
// To customize the time format, change zlog.TimeFieldFormat.
|
||||||
//
|
//
|
||||||
// NOTE: It won't dedupe the "time" key if the *Context has one already.
|
// NOTE: It won't dedupe the "time" key if the *Context has one already.
|
||||||
func (c Context) Timestamp() Context {
|
func (c Context) Timestamp() Context {
|
||||||
|
|
|
@ -24,6 +24,9 @@ func init() {
|
||||||
func appendJSON(dst []byte, j []byte) []byte {
|
func appendJSON(dst []byte, j []byte) []byte {
|
||||||
return cbor.AppendEmbeddedJSON(dst, j)
|
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
|
// decodeIfBinaryToString - converts a binary formatted log msg to a
|
||||||
// JSON formatted String Log message.
|
// JSON formatted String Log message.
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build !binary_log
|
||||||
// +build !binary_log
|
// +build !binary_log
|
||||||
|
|
||||||
package zlog
|
package zlog
|
||||||
|
@ -6,6 +7,7 @@ package zlog
|
||||||
// JSON encoded byte stream.
|
// JSON encoded byte stream.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"tuxpa.in/a/zlog/internal/json"
|
"tuxpa.in/a/zlog/internal/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,6 +27,17 @@ func init() {
|
||||||
func appendJSON(dst []byte, j []byte) []byte {
|
func appendJSON(dst []byte, j []byte) []byte {
|
||||||
return append(dst, j...)
|
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 {
|
func decodeIfBinaryToString(in []byte) string {
|
||||||
return string(in)
|
return string(in)
|
||||||
|
|
12
event.go
12
event.go
|
@ -318,6 +318,18 @@ func (e *Event) RawJSON(key string, b []byte) *Event {
|
||||||
return e
|
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.
|
// AnErr adds the field key with serialized err to the *Event context.
|
||||||
// If err is nil, no field is added.
|
// If err is nil, no field is added.
|
||||||
func (e *Event) AnErr(key string, err error) *Event {
|
func (e *Event) AnErr(key string, err error) *Event {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -6,7 +6,7 @@ require (
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0
|
github.com/coreos/go-systemd/v22 v22.5.0
|
||||||
github.com/mattn/go-colorable v0.1.12
|
github.com/mattn/go-colorable v0.1.12
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rs/xid v1.4.0
|
github.com/rs/xid v1.5.0
|
||||||
github.com/rs/zerolog v1.28.0
|
github.com/rs/zerolog v1.28.0
|
||||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect
|
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect
|
||||||
)
|
)
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -8,8 +8,9 @@ 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/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 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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.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=
|
||||||
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
|
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
|
||||||
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
|
@ -26,7 +26,8 @@ const (
|
||||||
additionalTypeBreak byte = 31
|
additionalTypeBreak byte = 31
|
||||||
|
|
||||||
// Tag Sub-types.
|
// 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
|
// Extended Tags - from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
|
||||||
additionalTypeTagNetworkAddr uint16 = 260
|
additionalTypeTagNetworkAddr uint16 = 260
|
||||||
|
|
|
@ -5,6 +5,7 @@ package cbor
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
@ -213,6 +214,31 @@ func decodeString(src *bufio.Reader, noQuotes bool) []byte {
|
||||||
}
|
}
|
||||||
return append(result, '"')
|
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 {
|
func decodeUTF8String(src *bufio.Reader) []byte {
|
||||||
pb := readByte(src)
|
pb := readByte(src)
|
||||||
|
@ -349,6 +375,20 @@ func decodeTagData(src *bufio.Reader) []byte {
|
||||||
switch minor {
|
switch minor {
|
||||||
case additionalTypeTimestamp:
|
case additionalTypeTimestamp:
|
||||||
return decodeTimeStamp(src)
|
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).
|
// Tag value is larger than 256 (so uint16).
|
||||||
case additionalTypeIntUint16:
|
case additionalTypeIntUint16:
|
||||||
|
|
|
@ -93,3 +93,25 @@ func AppendEmbeddedJSON(dst, s []byte) []byte {
|
||||||
}
|
}
|
||||||
return append(dst, s...)
|
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...)
|
||||||
|
}
|
||||||
|
|
4
log.go
4
log.go
|
@ -308,7 +308,9 @@ func (l Logger) Sample(s Sampler) Logger {
|
||||||
|
|
||||||
// Hook returns a logger with the h Hook.
|
// Hook returns a logger with the h Hook.
|
||||||
func (l Logger) Hook(h Hook) Logger {
|
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
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -320,6 +320,7 @@ func TestFields(t *testing.T) {
|
||||||
Bytes("bytes", []byte("bar")).
|
Bytes("bytes", []byte("bar")).
|
||||||
Hex("hex", []byte{0x12, 0xef}).
|
Hex("hex", []byte{0x12, 0xef}).
|
||||||
RawJSON("json", []byte(`{"some":"json"}`)).
|
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") }).
|
Func(func(e *Event) { e.Str("func", "func_output") }).
|
||||||
AnErr("some_err", nil).
|
AnErr("some_err", nil).
|
||||||
Err(errors.New("some error")).
|
Err(errors.New("some error")).
|
||||||
|
@ -344,7 +345,7 @@ func TestFields(t *testing.T) {
|
||||||
Time("time", time.Time{}).
|
Time("time", time.Time{}).
|
||||||
TimeDiff("diff", now, now.Add(-10*time.Second)).
|
TimeDiff("diff", now, now.Add(-10*time.Second)).
|
||||||
Msg("")
|
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)
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,15 +42,32 @@ func frameField(f errors.Frame, s *state, c rune) string {
|
||||||
|
|
||||||
// MarshalStack implements pkg/errors stack trace marshaling.
|
// MarshalStack implements pkg/errors stack trace marshaling.
|
||||||
//
|
//
|
||||||
// zlog.ErrorStackMarshaler = MarshalStack
|
// zlog.ErrorStackMarshaler = MarshalStack
|
||||||
func MarshalStack(err error) interface{} {
|
func MarshalStack(err error) interface{} {
|
||||||
type stackTracer interface {
|
type stackTracer interface {
|
||||||
StackTrace() errors.StackTrace
|
StackTrace() errors.StackTrace
|
||||||
}
|
}
|
||||||
sterr, ok := err.(stackTracer)
|
var sterr stackTracer
|
||||||
if !ok {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
st := sterr.StackTrace()
|
st := sterr.StackTrace()
|
||||||
s := &state{}
|
s := &state{}
|
||||||
out := make([]map[string]string, 0, len(st))
|
out := make([]map[string]string, 0, len(st))
|
||||||
|
|
|
@ -4,6 +4,7 @@ package pkgerrors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -17,11 +18,11 @@ func TestLogStack(t *testing.T) {
|
||||||
out := &bytes.Buffer{}
|
out := &bytes.Buffer{}
|
||||||
log := zlog.New(out)
|
log := zlog.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("")
|
log.Log().Stack().Err(err).Msg("")
|
||||||
|
|
||||||
got := out.String()
|
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 {
|
if ok, _ := regexp.MatchString(want, got); !ok {
|
||||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||||
}
|
}
|
||||||
|
@ -33,11 +34,11 @@ func TestLogStackFromContext(t *testing.T) {
|
||||||
out := &bytes.Buffer{}
|
out := &bytes.Buffer{}
|
||||||
log := zlog.New(out).With().Stack().Logger() // calling Stack() on log context instead of event
|
log := zlog.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()
|
log.Log().Err(err).Msg("") // not explicitly calling Stack()
|
||||||
|
|
||||||
got := out.String()
|
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 {
|
if ok, _ := regexp.MatchString(want, got); !ok {
|
||||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue