diff --git a/common/flogging/core.go b/common/flogging/core.go index 2e03173..8b828e4 100644 --- a/common/flogging/core.go +++ b/common/flogging/core.go @@ -15,11 +15,10 @@ type Encoding int8 const ( CONSOLE = iota JSON - LOGFMT ) // EncodingSelector is used to determine whether log records are -// encoded as JSON or in human readable CONSOLE or LOGFMT formats. +// encoded as JSON or in human-readable CONSOLE format. type EncodingSelector interface { Encoding() Encoding } diff --git a/common/flogging/fabenc/encoder.go b/common/flogging/fabenc/encoder.go index 4d19a09..c5450af 100644 --- a/common/flogging/fabenc/encoder.go +++ b/common/flogging/fabenc/encoder.go @@ -7,18 +7,29 @@ SPDX-License-Identifier: Apache-2.0 package fabenc import ( + "errors" + "fmt" "io" + "maps" + "slices" "time" - zaplogfmt "github.com/sykesm/zap-logfmt" + "github.com/go-logfmt/logfmt" "go.uber.org/zap/buffer" "go.uber.org/zap/zapcore" ) // A FormatEncoder is a zapcore.Encoder that formats log records according to a -// go-logging based format specifier. +// go-logging based format specifier. Structured fields are appended to the +// formatted record in logfmt (key=value) form: context added via With is +// emitted first, sorted by key, followed by the entry's own fields in the order +// they were supplied. Fields are not de-duplicated, so a repeated key is +// emitted once per occurrence with its own value. +// +// The embedded MapObjectEncoder provides the zapcore.ObjectEncoder +// implementation used to accumulate the With context. type FormatEncoder struct { - zapcore.Encoder + *zapcore.MapObjectEncoder formatters []Formatter pool buffer.Pool } @@ -30,51 +41,85 @@ type Formatter interface { func NewFormatEncoder(formatters ...Formatter) *FormatEncoder { return &FormatEncoder{ - Encoder: zaplogfmt.NewEncoder(zapcore.EncoderConfig{ - MessageKey: "", // disable - LevelKey: "", // disable - TimeKey: "", // disable - NameKey: "", // disable - CallerKey: "", // disable - StacktraceKey: "", // disable - LineEnding: "\n", - EncodeDuration: zapcore.StringDurationEncoder, - EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { - enc.AppendString(t.Format("2006-01-02T15:04:05.999Z07:00")) - }, - }), - formatters: formatters, - pool: buffer.NewPool(), + MapObjectEncoder: zapcore.NewMapObjectEncoder(), + formatters: formatters, + pool: buffer.NewPool(), } } // Clone creates a new instance of this encoder with the same configuration. func (f *FormatEncoder) Clone() zapcore.Encoder { + clone := zapcore.NewMapObjectEncoder() + maps.Copy(clone.Fields, f.Fields) return &FormatEncoder{ - Encoder: f.Encoder.Clone(), - formatters: f.formatters, - pool: f.pool, + MapObjectEncoder: clone, + formatters: f.formatters, + pool: f.pool, } } -// EncodeEntry formats a zap log record. The structured fields are formatted by a -// zapcore.ConsoleEncoder and are appended as JSON to the end of the formatted entry. +// EncodeEntry formats a zap log record. The With context is appended sorted by +// key, followed by this entry's fields in insertion order, all in logfmt form. // All entries are terminated by a newline. func (f *FormatEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { line := f.pool.Get() - for _, f := range f.formatters { - f.Format(line, entry, fields) + for _, formatter := range f.formatters { + formatter.Format(line, entry, fields) } - encodedFields, err := f.Encoder.EncodeEntry(entry, fields) - if err != nil { - return nil, err + type keyVal struct { + key string + val any } - if line.Len() > 0 && encodedFields.Len() != 1 { + + // Assemble the output: the With context first, sorted by key (map order is + // unrecoverable), then this entry's fields in the order supplied. + keyVals := make([]keyVal, 0, len(f.Fields)+len(fields)) + for _, key := range slices.Sorted(maps.Keys(f.Fields)) { + keyVals = append(keyVals, keyVal{key: key, val: f.Fields[key]}) + } + for _, field := range fields { + // Fields are not de-duplicated, so a repeated key is preserved with its own value, as + // the original logfmt encoder did. Thus, we decode each field on its own map encoder. + mapEncoder := zapcore.NewMapObjectEncoder() + field.AddTo(mapEncoder) + // Some fields are skipped, so we need to check if it was actually added. + if v, ok := mapEncoder.Fields[field.Key]; ok { + keyVals = append(keyVals, keyVal{key: field.Key, val: v}) + } + } + + // Separate the first field from the formatted prefix; logfmt inserts + // the separators between subsequent fields itself. + if len(keyVals) > 0 && line.Len() > 0 { line.AppendString(" ") } - line.AppendString(encodedFields.String()) - encodedFields.Free() + + enc := logfmt.NewEncoder(line) + for _, kv := range keyVals { + if err := encodeKeyValue(enc, kv.key, kv.val); err != nil { + return nil, err + } + } + + line.AppendString("\n") return line, nil } + +func encodeKeyValue(enc *logfmt.Encoder, key string, value any) error { + if t, ok := value.(time.Time); ok { + // Normalizes values that logfmt would otherwise render differently + // than intended. Timestamps use a millisecond-precision layout instead of the + // nanosecond-precision encoding.TextMarshaler output. + value = t.Format("2006-01-02T15:04:05.999Z07:00") + } + + err := enc.EncodeKeyval(key, value) + if errors.Is(err, logfmt.ErrUnsupportedValueType) { + // logfmt rejects composite types (structs, maps, slices, ...); fall + // back to their fmt representation, matching what EncodeKeyvals() does. + err = enc.EncodeKeyval(key, fmt.Sprint(value)) + } + return err +} diff --git a/common/flogging/fabenc/encoder_test.go b/common/flogging/fabenc/encoder_test.go index c43de56..800167d 100644 --- a/common/flogging/fabenc/encoder_test.go +++ b/common/flogging/fabenc/encoder_test.go @@ -7,7 +7,6 @@ SPDX-License-Identifier: Apache-2.0 package fabenc_test import ( - "errors" "fmt" "runtime" "testing" @@ -16,7 +15,6 @@ import ( "github.com/hyperledger/fabric-lib-go/common/flogging/fabenc" "github.com/stretchr/testify/require" "go.uber.org/zap" - "go.uber.org/zap/buffer" "go.uber.org/zap/zapcore" ) @@ -63,18 +61,57 @@ func TestEncodeEntry(t *testing.T) { } } -type brokenEncoder struct{ zapcore.Encoder } +func TestEncodeFieldsFailed(t *testing.T) { + enc := fabenc.NewFormatEncoder() + // A key that reduces to nothing once invalid runes are stripped cannot be + // encoded as logfmt, so EncodeEntry surfaces the error. + _, err := enc.EncodeEntry(zapcore.Entry{}, []zapcore.Field{zap.String(" ", "value")}) + require.Error(t, err) +} -func (b *brokenEncoder) EncodeEntry(zapcore.Entry, []zapcore.Field) (*buffer.Buffer, error) { - return nil, errors.New("broken encoder") +// TestEncodeEntryPreservesOrder verifies that an entry's own fields are emitted +// in insertion order rather than sorted by key. +func TestEncodeEntryPreservesOrder(t *testing.T) { + enc := fabenc.NewFormatEncoder() + line, err := enc.EncodeEntry(zapcore.Entry{}, []zapcore.Field{ + zap.String("zebra", "z"), + zap.Int("apple", 1), + zap.String("mango", "m"), + }) + require.NoError(t, err) + require.Equal(t, "zebra=z apple=1 mango=m\n", line.String()) } -func TestEncodeFieldsFailed(t *testing.T) { +// TestEncodeEntryPreservesDuplicateKeys verifies that repeated keys are not +// merged: each occurrence is emitted with its own value. The With context is +// emitted (sorted) before the entry's fields, and a key present in both the +// context and the entry appears in each. +func TestEncodeEntryPreservesDuplicateKeys(t *testing.T) { enc := fabenc.NewFormatEncoder() - enc.Encoder = &brokenEncoder{} + enc.Fields["ctx"] = "c" // With context + enc.Fields["dup"] = "from-with" + + line, err := enc.EncodeEntry(zapcore.Entry{}, []zapcore.Field{ + zap.String("dup", "from-field"), // same key as the context entry + zap.String("zzz", "z"), + zap.String("zzz", "z2"), // duplicated within the entry + }) + require.NoError(t, err) + require.Equal(t, "ctx=c dup=from-with dup=from-field zzz=z zzz=z2\n", line.String()) +} - _, err := enc.EncodeEntry(zapcore.Entry{}, nil) - require.EqualError(t, err, "broken encoder") +// TestEncodeEntrySkipsValuelessFields verifies that a field which adds no value +// under its key (e.g. zap.Skip, whose key is empty) is dropped rather than +// emitted as an invalid key. +func TestEncodeEntrySkipsValuelessFields(t *testing.T) { + enc := fabenc.NewFormatEncoder() + line, err := enc.EncodeEntry(zapcore.Entry{}, []zapcore.Field{ + zap.Skip(), + zap.String("k", "v"), + zap.Skip(), + }) + require.NoError(t, err) + require.Equal(t, "k=v\n", line.String()) } func TestFormatEncoderClone(t *testing.T) { diff --git a/common/flogging/global_test.go b/common/flogging/global_test.go index 3ed1867..c4f67de 100644 --- a/common/flogging/global_test.go +++ b/common/flogging/global_test.go @@ -66,23 +66,6 @@ func TestGlobalInitJSON(t *testing.T) { require.Regexp(t, `{"level":"debug","ts":\d+.\d+,"name":"testlogger","caller":"flogging/global_test.go:\d+","msg":"this is a message"}\s+`, buf.String()) } -func TestGlobalInitLogfmt(t *testing.T) { - flogging.Reset() - defer flogging.Reset() - - buf := &bytes.Buffer{} - flogging.Init(flogging.Config{ - Format: "logfmt", - LogSpec: "DEBUG", - Writer: buf, - }) - - logger := flogging.MustGetLogger("testlogger") - logger.Debug("this is a message") - - require.Regexp(t, `^ts=\d+.\d+ level=debug name=testlogger caller=flogging/global_test.go:\d+ msg="this is a message"`, buf.String()) -} - func TestGlobalInitPanic(t *testing.T) { flogging.Reset() defer flogging.Reset() diff --git a/common/flogging/logging.go b/common/flogging/logging.go index cc5af1c..6509eda 100644 --- a/common/flogging/logging.go +++ b/common/flogging/logging.go @@ -13,7 +13,6 @@ import ( "sync" "github.com/hyperledger/fabric-lib-go/common/flogging/fabenc" - zaplogfmt "github.com/sykesm/zap-logfmt" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -90,7 +89,7 @@ func (l *Logging) Apply(c Config) error { c.LogSpec = defaultLevel.String() } - err = l.LoggerLevels.ActivateSpec(c.LogSpec) + err = l.ActivateSpec(c.LogSpec) if err != nil { return err } @@ -119,11 +118,6 @@ func (l *Logging) SetFormat(format string) error { return nil } - if format == "logfmt" { - l.encoding = LOGFMT - return nil - } - formatters, err := fabenc.ParseFormat(format) if err != nil { return err @@ -211,7 +205,6 @@ func (l *Logging) ZapLogger(name string) *zap.Logger { Encoders: map[Encoding]zapcore.Encoder{ JSON: zapcore.NewJSONEncoder(l.encoderConfig), CONSOLE: fabenc.NewFormatEncoder(l.multiFormatter), - LOGFMT: zaplogfmt.NewEncoder(l.encoderConfig), }, Selector: l, Output: l, diff --git a/go.mod b/go.mod index ebb3354..1558394 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.25.10 require ( github.com/go-kit/kit v0.13.0 + github.com/go-logfmt/logfmt v0.6.1 github.com/go-viper/mapstructure/v2 v2.5.0 github.com/miekg/pkcs11 v1.1.2 github.com/onsi/ginkgo/v2 v2.28.3 @@ -12,7 +13,6 @@ require ( github.com/prometheus/client_golang v1.23.2 github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 - github.com/sykesm/zap-logfmt v0.0.4 go.uber.org/zap v1.28.0 golang.org/x/sync v0.20.0 golang.org/x/tools v0.45.0 @@ -26,7 +26,6 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/google/go-cmp v0.7.0 // indirect diff --git a/go.sum b/go.sum index 8db6c02..e9addd1 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= @@ -7,7 +6,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -38,17 +36,12 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg= github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -67,7 +60,6 @@ github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc= github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -80,7 +72,6 @@ github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9Z github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= @@ -95,15 +86,10 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/sykesm/zap-logfmt v0.0.4 h1:U2WzRvmIWG1wDLCFY3sz8UeEmsdHQjHFNlIdmroVFaI= -github.com/sykesm/zap-logfmt v0.0.4/go.mod h1:AuBd9xQjAe3URrWT1BBDk2v2onAZHkZkWRMiYZXiZWA= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -112,58 +98,34 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/github.com/spf13/viper/viper.go b/vendor/github.com/spf13/viper/viper.go index 2cc9014..34a9479 100644 --- a/vendor/github.com/spf13/viper/viper.go +++ b/vendor/github.com/spf13/viper/viper.go @@ -417,7 +417,7 @@ func (v *Viper) GetEnvPrefix() string { func (v *Viper) mergeWithEnvPrefix(in string) string { if v.envPrefix != "" { - return strings.ToUpper(v.envPrefix + "_" + v.envKeyReplacer.Replace(in)) + return strings.ToUpper(v.envPrefix + "_" + in) } return strings.ToUpper(in) @@ -950,8 +950,7 @@ func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error { } // TODO: struct keys should be enough? - s := v.getSettings(keys) - return decode(s, v.defaultDecoderConfig(rawVal, opts...)) + return decode(v.getSettings(keys), v.defaultDecoderConfig(rawVal, opts...)) } func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]string, error) { diff --git a/vendor/github.com/sykesm/zap-logfmt/.gitignore b/vendor/github.com/sykesm/zap-logfmt/.gitignore deleted file mode 100644 index 7a6353d..0000000 --- a/vendor/github.com/sykesm/zap-logfmt/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.envrc diff --git a/vendor/github.com/sykesm/zap-logfmt/.travis.yml b/vendor/github.com/sykesm/zap-logfmt/.travis.yml deleted file mode 100644 index 7ce1f7a..0000000 --- a/vendor/github.com/sykesm/zap-logfmt/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: go - -matrix: - include: - - go: "1.13.x" - install: true - - go: "1.14.x" - install: true - - go: "1.15.x" - install: true - -script: go test -race ./... diff --git a/vendor/github.com/sykesm/zap-logfmt/LICENSE b/vendor/github.com/sykesm/zap-logfmt/LICENSE deleted file mode 100644 index 43a1c32..0000000 --- a/vendor/github.com/sykesm/zap-logfmt/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Jonathan Sternberg -Copyright (c) 2019 Matthew Sykes - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/sykesm/zap-logfmt/README.md b/vendor/github.com/sykesm/zap-logfmt/README.md deleted file mode 100644 index 751f288..0000000 --- a/vendor/github.com/sykesm/zap-logfmt/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# Logfmt Encoder - -This package provides a logfmt encoder for [zap][zap]. - -It is a fork of [github.com/jsternberg/zap-logfmt][jsternberg] that improves -the handling of reflected fields and encodes arrays and objects instead of -dropping them from logs. While logging simple fields is preferred for many -reasons, having ugly data is often better than missing data. - -[![Build Status](https://travis-ci.org/sykesm/zap-logfmt.svg?branch=master)](https://travis-ci.org/sykesm/zap-logfmt) -[![GoDoc](https://godoc.org/github.com/sykesm/zap-logfmt?status.svg)](https://godoc.org/github.com/sykesm/zap-logfmt) - -## Usage - -The encoder is easy to configure. Simply create a new core with an instance of -the logfmt encoder and use it with your preferred logging interface. - -```go -package main - -import ( - "os" - - "github.com/sykesm/zap-logfmt" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -func main() { - config := zap.NewProductionEncoderConfig() - logger := zap.New(zapcore.NewCore( - zaplogfmt.NewEncoder(config), - os.Stdout, - zapcore.DebugLevel, - )) - logger.Info("Hello World") -} -``` - -## Arrays, Objects, and Reflected Fields - -While it's best to avoid complex data types in log fields, there are times -when they sneak in. When complex fields are included in log records, they will -be encoded, but they won't be very pretty. - -### Arrays - -Arrays are encoded as a comma separated list of values within square brackets. -This format is very similar to JSON encoding. Arrays of simple scalars remain -quite readable but including elements that require quoting will result in very -ugly records. - -### Objects - -Objects are encoded as a space separated list of _key=value_ pairs. Because -this format includes an equals sign, the encoded object will require quoting. -If any value in the object requires quoting, the required escapes will make -the encoded field pretty difficult for humans to read. - -### Channels and Functions - -Channels and functions are encoded as their type and their address. There -aren't many meaningful ways to log channels and functions... - -### Maps and Structs - -Maps and structs are encoded as strings that contain the result of `fmt.Sprint`. - -## Namespaces - -Namespaces are supported. If a namespace is opened, all of the keys will -be prepended with the namespace name. For example, with the namespace -`foo` and the key `bar`, you would get a key of `foo.bar`. - -[zap]: https://github.com/uber-go/zap -[jsternberg]: https://github.com/jsternberg/zap-logfmt diff --git a/vendor/github.com/sykesm/zap-logfmt/encoder.go b/vendor/github.com/sykesm/zap-logfmt/encoder.go deleted file mode 100644 index 9e960cc..0000000 --- a/vendor/github.com/sykesm/zap-logfmt/encoder.go +++ /dev/null @@ -1,527 +0,0 @@ -// Package zaplogfmt provides a zap encoder that formats log entries in -// "logfmt" format. -package zaplogfmt - -import ( - "bytes" - "encoding" - "encoding/base64" - "encoding/json" - "fmt" - "math" - "reflect" - "strings" - "sync" - "time" - "unicode/utf8" - - "go.uber.org/zap/buffer" - "go.uber.org/zap/zapcore" -) - -var ( - logfmtPool = sync.Pool{ - New: func() interface{} { return &logfmtEncoder{} }, - } - bufferpool = buffer.NewPool() -) - -func getEncoder() *logfmtEncoder { - return logfmtPool.Get().(*logfmtEncoder) -} - -func putEncoder(enc *logfmtEncoder) { - enc.EncoderConfig = nil - enc.buf = nil - enc.namespaces = nil - enc.arrayLiteral = false - logfmtPool.Put(enc) -} - -type logfmtEncoder struct { - *zapcore.EncoderConfig - buf *buffer.Buffer - namespaces []string - arrayLiteral bool -} - -// NewEncoder creates an encoder writes logfmt formatted log entries. -func NewEncoder(cfg zapcore.EncoderConfig) zapcore.Encoder { - return &logfmtEncoder{ - EncoderConfig: &cfg, - buf: bufferpool.Get(), - } -} - -func (enc *logfmtEncoder) AddArray(key string, arr zapcore.ArrayMarshaler) error { - enc.addKey(key) - return enc.AppendArray(arr) -} - -func (enc *logfmtEncoder) AddBinary(key string, value []byte) { - enc.AddString(key, base64.StdEncoding.EncodeToString(value)) -} - -func (enc *logfmtEncoder) AddBool(key string, value bool) { - enc.addKey(key) - enc.AppendBool(value) -} - -func (enc *logfmtEncoder) AddByteString(key string, value []byte) { - enc.addKey(key) - enc.AppendByteString(value) -} - -func (enc *logfmtEncoder) AddComplex64(k string, v complex64) { enc.AddComplex128(k, complex128(v)) } -func (enc *logfmtEncoder) AddComplex128(key string, value complex128) { - enc.addKey(key) - enc.AppendComplex128(value) -} - -func (enc *logfmtEncoder) AddDuration(key string, value time.Duration) { - enc.addKey(key) - enc.AppendDuration(value) -} - -func (enc *logfmtEncoder) AddFloat32(key string, value float32) { - enc.addKey(key) - enc.AppendFloat32(value) -} - -func (enc *logfmtEncoder) AddFloat64(key string, value float64) { - enc.addKey(key) - enc.AppendFloat64(value) -} - -func (enc *logfmtEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) } -func (enc *logfmtEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) } -func (enc *logfmtEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) } -func (enc *logfmtEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) } -func (enc *logfmtEncoder) AddInt64(key string, value int64) { - enc.addKey(key) - enc.AppendInt64(value) -} - -func (enc *logfmtEncoder) AddObject(key string, obj zapcore.ObjectMarshaler) error { - enc.addKey(key) - return enc.AppendObject(obj) -} - -func (enc *logfmtEncoder) AddReflected(key string, value interface{}) error { - enc.addKey(key) - return enc.AppendReflected(value) -} - -func (enc *logfmtEncoder) AddString(key, value string) { - enc.addKey(key) - enc.AppendString(value) -} - -func (enc *logfmtEncoder) AddTime(key string, value time.Time) { - enc.addKey(key) - enc.AppendTime(value) -} - -func (enc *logfmtEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) } -func (enc *logfmtEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) } -func (enc *logfmtEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) } -func (enc *logfmtEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) } -func (enc *logfmtEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) } -func (enc *logfmtEncoder) AddUint64(key string, value uint64) { - enc.addKey(key) - enc.AppendUint64(value) -} - -func (enc *logfmtEncoder) AppendArray(arr zapcore.ArrayMarshaler) error { - marshaler := enc.clone() - marshaler.namespaces = nil - marshaler.arrayLiteral = true - - marshaler.buf.AppendByte('[') - err := arr.MarshalLogArray(marshaler) - if err == nil { - marshaler.buf.AppendByte(']') - enc.AppendByteString(marshaler.buf.Bytes()) - } else { - enc.AppendByteString(nil) - } - marshaler.buf.Free() - putEncoder(marshaler) - return err -} - -func (enc *logfmtEncoder) AppendBool(value bool) { - if value { - enc.AppendString("true") - } else { - enc.AppendString("false") - } -} - -func (enc *logfmtEncoder) AppendByteString(value []byte) { - enc.addSeparator() - - needsQuotes := bytes.IndexFunc(value, needsQuotedValueRune) != -1 - if needsQuotes { - enc.buf.AppendByte('"') - } - enc.safeAddByteString(value) - if needsQuotes { - enc.buf.AppendByte('"') - } -} - -func (enc *logfmtEncoder) AppendComplex64(v complex64) { enc.AppendComplex128(complex128(v)) } -func (enc *logfmtEncoder) AppendComplex128(value complex128) { - enc.addSeparator() - - // Cast to a platform-independent, fixed-size type. - r, i := float64(real(value)), float64(imag(value)) - enc.buf.AppendFloat(r, 64) - enc.buf.AppendByte('+') - enc.buf.AppendFloat(i, 64) - enc.buf.AppendByte('i') -} - -func (enc *logfmtEncoder) AppendDuration(value time.Duration) { - cur := enc.buf.Len() - if enc.EncodeDuration != nil { - enc.EncodeDuration(value, enc) - } - if cur == enc.buf.Len() { - enc.AppendInt64(int64(value)) - } -} - -func (enc *logfmtEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) } -func (enc *logfmtEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) } -func (enc *logfmtEncoder) appendFloat(val float64, bitSize int) { - enc.addSeparator() - - switch { - case math.IsNaN(val): - enc.buf.AppendString(`NaN`) - case math.IsInf(val, 1): - enc.buf.AppendString(`+Inf`) - case math.IsInf(val, -1): - enc.buf.AppendString(`-Inf`) - default: - enc.buf.AppendFloat(val, bitSize) - } -} - -func (enc *logfmtEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) } -func (enc *logfmtEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) } -func (enc *logfmtEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) } -func (enc *logfmtEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) } -func (enc *logfmtEncoder) AppendInt64(value int64) { - enc.addSeparator() - enc.buf.AppendInt(value) -} - -func (enc *logfmtEncoder) AppendObject(obj zapcore.ObjectMarshaler) error { - marshaler := enc.clone() - marshaler.namespaces = nil - - err := obj.MarshalLogObject(marshaler) - if err == nil { - enc.AppendByteString(marshaler.buf.Bytes()) - } else { - enc.AppendByteString(nil) - } - marshaler.buf.Free() - putEncoder(marshaler) - return err -} - -func (enc *logfmtEncoder) AppendReflected(value interface{}) error { - switch v := value.(type) { - case nil: - enc.AppendString("null") - case error: - enc.AppendString(v.Error()) - case []byte: - enc.AppendByteString(v) - case fmt.Stringer: - enc.AppendString(v.String()) - case encoding.TextMarshaler: - b, err := v.MarshalText() - if err != nil { - return err - } - enc.AppendString(string(b)) - case json.Marshaler: - b, err := v.MarshalJSON() - if err != nil { - return err - } - enc.AppendString(string(b)) - default: - rvalue := reflect.ValueOf(value) - switch rvalue.Kind() { - case reflect.Bool: - enc.AppendBool(rvalue.Bool()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - enc.AppendInt64(rvalue.Int()) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - enc.AppendUint64(rvalue.Uint()) - case reflect.Float32: - enc.appendFloat(rvalue.Float(), 32) - case reflect.Float64: - enc.AppendFloat64(rvalue.Float()) - case reflect.String: - enc.AppendString(rvalue.String()) - case reflect.Complex64, reflect.Complex128: - enc.AppendComplex128(rvalue.Complex()) - case reflect.Chan, reflect.Func: - enc.AppendString(fmt.Sprintf("%T(%p)", value, value)) - case reflect.Map, reflect.Struct: - enc.AppendString(fmt.Sprint(value)) - case reflect.Array, reflect.Slice: - enc.AppendArray(zapcore.ArrayMarshalerFunc(func(ae zapcore.ArrayEncoder) error { - for i := 0; i < rvalue.Len(); i++ { - ae.AppendReflected(rvalue.Index(i).Interface()) - } - return nil - })) - case reflect.Interface, reflect.Ptr: - return enc.AppendReflected(rvalue.Elem().Interface()) - } - } - return nil -} - -func (enc *logfmtEncoder) AppendString(value string) { - enc.addSeparator() - - needsQuotes := strings.IndexFunc(value, needsQuotedValueRune) != -1 - if needsQuotes { - enc.buf.AppendByte('"') - } - enc.safeAddString(value) - if needsQuotes { - enc.buf.AppendByte('"') - } -} - -func (enc *logfmtEncoder) AppendTime(value time.Time) { - cur := enc.buf.Len() - if enc.EncodeTime != nil { - enc.EncodeTime(value, enc) - } - if cur == enc.buf.Len() { - enc.AppendInt64(value.UnixNano()) - } -} - -func (enc *logfmtEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) } -func (enc *logfmtEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) } -func (enc *logfmtEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) } -func (enc *logfmtEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) } -func (enc *logfmtEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) } -func (enc *logfmtEncoder) AppendUint64(value uint64) { - enc.addSeparator() - enc.buf.AppendUint(value) -} - -func (enc *logfmtEncoder) Clone() zapcore.Encoder { - clone := enc.clone() - clone.buf.Write(enc.buf.Bytes()) - return clone -} - -func (enc *logfmtEncoder) clone() *logfmtEncoder { - clone := getEncoder() - clone.EncoderConfig = enc.EncoderConfig - clone.buf = bufferpool.Get() - clone.namespaces = enc.namespaces - return clone -} - -func (enc *logfmtEncoder) OpenNamespace(key string) { - key = strings.Map(keyRuneFilter, key) - enc.namespaces = append(enc.namespaces, key) -} - -func (enc *logfmtEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { - final := enc.clone() - if final.TimeKey != "" { - final.AddTime(final.TimeKey, ent.Time) - } - if final.LevelKey != "" { - final.addKey(final.LevelKey) - cur := final.buf.Len() - if final.EncodeLevel != nil { - final.EncodeLevel(ent.Level, final) - } - if cur == final.buf.Len() { - // User-supplied EncodeLevel was a no-op. Fall back to strings to keep - // output valid. - final.AppendString(ent.Level.String()) - } - } - if ent.LoggerName != "" && final.NameKey != "" { - final.addKey(final.NameKey) - cur := final.buf.Len() - if final.EncodeName != nil { - final.EncodeName(ent.LoggerName, final) - } - if cur == final.buf.Len() { - // User-supplied EncodeName was a no-op. Fall back to strings to - // keep output valid. - final.AppendString(ent.LoggerName) - } - } - if ent.Caller.Defined && final.CallerKey != "" { - final.addKey(final.CallerKey) - cur := final.buf.Len() - if final.EncodeCaller != nil { - final.EncodeCaller(ent.Caller, final) - } - if cur == final.buf.Len() { - // User-supplied EncodeCaller was a no-op. Fall back to strings to - // keep output valid. - final.AppendString(ent.Caller.String()) - } - } - if final.MessageKey != "" { - final.addKey(enc.MessageKey) - final.AppendString(ent.Message) - } - if enc.buf.Len() > 0 { - if final.buf.Len() > 0 { - final.buf.AppendByte(' ') - } - final.buf.Write(enc.buf.Bytes()) - } - addFields(final, fields) - if ent.Stack != "" && final.StacktraceKey != "" { - final.AddString(final.StacktraceKey, ent.Stack) - } - if final.LineEnding != "" { - final.buf.AppendString(final.LineEnding) - } else { - final.buf.AppendString(zapcore.DefaultLineEnding) - } - - ret := final.buf - putEncoder(final) - return ret, nil -} - -func (enc *logfmtEncoder) addSeparator() { - if !enc.arrayLiteral { - return - } - - last := enc.buf.Len() - 1 - if last >= 0 && enc.buf.Bytes()[last] != '[' { - enc.buf.AppendByte(',') - } -} - -func (enc *logfmtEncoder) addKey(key string) { - key = strings.Map(keyRuneFilter, key) - if enc.buf.Len() > 0 { - enc.buf.AppendByte(' ') - } - for _, ns := range enc.namespaces { - enc.safeAddString(ns) - enc.buf.AppendByte('.') - } - enc.safeAddString(key) - enc.buf.AppendByte('=') -} - -// safeAddString JSON-escapes a string and appends it to the internal buffer. -// Unlike the standard library's encoder, it doesn't attempt to protect the -// user from browser vulnerabilities or JSONP-related problems. -func (enc *logfmtEncoder) safeAddString(s string) { - for i := 0; i < len(s); { - if enc.tryAddRuneSelf(s[i]) { - i++ - continue - } - r, size := utf8.DecodeRuneInString(s[i:]) - if enc.tryAddRuneError(r, size) { - i++ - continue - } - enc.buf.AppendString(s[i : i+size]) - i += size - } -} - -// safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte. -func (enc *logfmtEncoder) safeAddByteString(s []byte) { - for i := 0; i < len(s); { - if enc.tryAddRuneSelf(s[i]) { - i++ - continue - } - r, size := utf8.DecodeRune(s[i:]) - if enc.tryAddRuneError(r, size) { - i++ - continue - } - enc.buf.Write(s[i : i+size]) - i += size - } -} - -// tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte. -func (enc *logfmtEncoder) tryAddRuneSelf(b byte) bool { - if b >= utf8.RuneSelf { - return false - } - if 0x20 <= b && b != '\\' && b != '"' { - enc.buf.AppendByte(b) - return true - } - switch b { - case '\\', '"': - enc.buf.AppendByte('\\') - enc.buf.AppendByte(b) - case '\n': - enc.buf.AppendByte('\\') - enc.buf.AppendByte('n') - case '\r': - enc.buf.AppendByte('\\') - enc.buf.AppendByte('r') - case '\t': - enc.buf.AppendByte('\\') - enc.buf.AppendByte('t') - default: - // Encode bytes < 0x20, except for the escape sequences above. - const _hex = "0123456789abcdef" - enc.buf.AppendString(`\u00`) - enc.buf.AppendByte(_hex[b>>4]) - enc.buf.AppendByte(_hex[b&0xF]) - } - return true -} - -func (enc *logfmtEncoder) tryAddRuneError(r rune, size int) bool { - if r == utf8.RuneError && size == 1 { - enc.buf.AppendString(`\ufffd`) - return true - } - return false -} - -func needsQuotedValueRune(r rune) bool { - return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError -} - -func keyRuneFilter(r rune) rune { - if needsQuotedValueRune(r) { - return -1 - } - return r -} - -func addFields(enc zapcore.ObjectEncoder, fields []zapcore.Field) { - for i := range fields { - fields[i].AddTo(enc) - } -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 83c1930..39c241e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -162,9 +162,6 @@ github.com/stretchr/testify/require # github.com/subosito/gotenv v1.6.0 ## explicit; go 1.18 github.com/subosito/gotenv -# github.com/sykesm/zap-logfmt v0.0.4 -## explicit; go 1.13 -github.com/sykesm/zap-logfmt # go.uber.org/multierr v1.11.0 ## explicit; go 1.19 go.uber.org/multierr