From 9d2e5dea6deb0f1eb8edb2d94ba7b0deecca5c0c Mon Sep 17 00:00:00 2001 From: Prashant Varanasi Date: Thu, 12 Nov 2020 13:59:12 -0800 Subject: [PATCH 01/25] Add FAQ question on zap dropping logs due to sampling (#875) Multiple issues have been opened about missing logs (e.g., #874, #588). While sampling is mentioned in the API documentation for `NewProductionConfig`, it may help to add an FAQ question as well. --- FAQ.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/FAQ.md b/FAQ.md index 5ec728875..626bda978 100644 --- a/FAQ.md +++ b/FAQ.md @@ -27,6 +27,13 @@ abstraction, and it lets us add methods without introducing breaking changes. Your applications should define and depend upon an interface that includes just the methods you use. +### Why are some of my logs missing? + +Logs are dropped intentionally by zap when sampling is enabled. The production +configuration (as returned by `NewProductionConfig()` enables sampling which will +cause repeated logs within a second to be sampled. See more details on why sampling +is enabled in [Why sample application logs](https://github.com/uber-go/zap/blob/master/FAQ.md#why-sample-application-logs). + ### Why sample application logs? Applications often experience runs of errors, either because of a bug or From 495658fbf521c5e8a4c1810d66b30e26e7665c3e Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Tue, 24 Nov 2020 11:14:39 -0800 Subject: [PATCH 02/25] travis: Test against stable and oldstable (#882) --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index cfdc69f41..95c2ada6d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,8 @@ env: matrix: include: - - go: 1.13.x - - go: 1.14.x + - go: oldstable + - go: stable env: LINT=1 script: From 4b2b07cf19e2c6f8ecc4f76210a301890661a74c Mon Sep 17 00:00:00 2001 From: LiuYang Date: Wed, 25 Nov 2020 03:15:17 +0800 Subject: [PATCH 03/25] field/error: Handle panic in Error() (#867) We shouldn't panic if the `Error()` method of an `error` panics. ``` type T struct{ msg string } func (t *T) Error() string { return t.msg } // The following panics. var n *T = nil log.Info("panic", zap.Error(n)) ``` Co-authored-by: Abhinav Gupta --- zapcore/error.go | 19 ++++++++++++++++++- zapcore/field.go | 2 +- zapcore/field_test.go | 15 +++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/zapcore/error.go b/zapcore/error.go index 9ba2272c3..f2a07d786 100644 --- a/zapcore/error.go +++ b/zapcore/error.go @@ -22,6 +22,7 @@ package zapcore import ( "fmt" + "reflect" "sync" ) @@ -42,7 +43,23 @@ import ( // ... // ], // } -func encodeError(key string, err error, enc ObjectEncoder) error { +func encodeError(key string, err error, enc ObjectEncoder) (retErr error) { + // Try to capture panics (from nil references or otherwise) when calling + // the Error() method + defer func() { + if rerr := recover(); rerr != nil { + // If it's a nil pointer, just say "". The likeliest causes are a + // error that fails to guard against nil or a nil pointer for a + // value receiver, and in either case, "" is a nice result. + if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() { + enc.AddString(key, "") + return + } + + retErr = fmt.Errorf("PANIC=%v", rerr) + } + }() + basic := err.Error() enc.AddString(key, basic) diff --git a/zapcore/field.go b/zapcore/field.go index 7e255d63e..e0105868e 100644 --- a/zapcore/field.go +++ b/zapcore/field.go @@ -167,7 +167,7 @@ func (f Field) AddTo(enc ObjectEncoder) { case StringerType: err = encodeStringer(f.Key, f.Interface, enc) case ErrorType: - encodeError(f.Key, f.Interface.(error), enc) + err = encodeError(f.Key, f.Interface.(error), enc) case SkipType: break default: diff --git a/zapcore/field_test.go b/zapcore/field_test.go index 44aeee62e..31de0b623 100644 --- a/zapcore/field_test.go +++ b/zapcore/field_test.go @@ -80,6 +80,19 @@ func (o *obj) String() string { return "obj" } +type errObj struct { + kind int + errMsg string +} + +func (eobj *errObj) Error() string { + if eobj.kind == 1 { + panic("panic in Error() method") + } else { + return eobj.errMsg + } +} + func TestUnknownFieldType(t *testing.T) { unknown := Field{Key: "k", String: "foo"} assert.Equal(t, UnknownType, unknown.Type, "Expected zero value of FieldType to be UnknownType.") @@ -102,6 +115,7 @@ func TestFieldAddingError(t *testing.T) { {t: StringerType, iface: &obj{1}, want: empty, err: "PANIC=panic with string"}, {t: StringerType, iface: &obj{2}, want: empty, err: "PANIC=panic with error"}, {t: StringerType, iface: &obj{3}, want: empty, err: "PANIC="}, + {t: ErrorType, iface: &errObj{kind: 1}, want: empty, err: "PANIC=panic in Error() method"}, } for _, tt := range tests { f := Field{Key: "k", Interface: tt.iface, Type: tt.t} @@ -150,6 +164,7 @@ func TestFields(t *testing.T) { {t: SkipType, want: interface{}(nil)}, {t: StringerType, iface: (*url.URL)(nil), want: ""}, {t: StringerType, iface: (*users)(nil), want: ""}, + {t: ErrorType, iface: (*errObj)(nil), want: ""}, } for _, tt := range tests { From 5b4722d3797ca2e22f3c16dbe71a97b9c7783c98 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Tue, 24 Nov 2020 11:55:26 -0800 Subject: [PATCH 04/25] README: use pkg.go.dev instead of godoc.org (#883) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bcea28a19..a3a5c09bd 100644 --- a/README.md +++ b/README.md @@ -123,8 +123,8 @@ Released under the [MIT License](LICENSE.txt). benchmarking against slightly older versions of other packages. Versions are pinned in the [benchmarks/go.mod][] file. [↩](#anchor-versions) -[doc-img]: https://godoc.org/go.uber.org/zap?status.svg -[doc]: https://godoc.org/go.uber.org/zap +[doc-img]: https://pkg.go.dev/badge/go.uber.org/zap +[doc]: https://pkg.go.dev/go.uber.org/zap [ci-img]: https://travis-ci.com/uber-go/zap.svg?branch=master [ci]: https://travis-ci.com/uber-go/zap [cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg From f5a35929e8739154ce9b60d55825cdde1900fc81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=91=E5=8F=A3=E5=A4=A7=E7=99=BD=E9=B9=85?= Date: Thu, 10 Dec 2020 23:57:29 -0800 Subject: [PATCH 05/25] Byte alignment, optimization from 96 to 80 byte (#865) --- logger.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/logger.go b/logger.go index ea484aed1..bdcc5d666 100644 --- a/logger.go +++ b/logger.go @@ -42,14 +42,15 @@ type Logger struct { core zapcore.Core development bool + addCaller bool + onFatal zapcore.CheckWriteAction // default is WriteThenFatal + name string errorOutput zapcore.WriteSyncer - addCaller bool - addStack zapcore.LevelEnabler + addStack zapcore.LevelEnabler callerSkip int - onFatal zapcore.CheckWriteAction // default is WriteThenFatal } // New constructs a new Logger from the provided zapcore.Core and Options. If From a68efdbdd15b7816de33cdbe7e6def2a559bdf64 Mon Sep 17 00:00:00 2001 From: genisysram <70624950+genisysram@users.noreply.github.com> Date: Fri, 11 Dec 2020 23:47:45 +0530 Subject: [PATCH 06/25] travis: Test against ppc64le (#872) --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 95c2ada6d..0a4c5e6ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: go + sudo: false go_import_path: go.uber.org/zap @@ -12,6 +13,10 @@ matrix: - go: oldstable - go: stable env: LINT=1 + - arch: ppc64le + go: oldstable + - arch: ppc64le + go: stable script: - test -z "$LINT" || make lint From 864bed12494e6d6324cb9f8d1fd0f1f349a7ab94 Mon Sep 17 00:00:00 2001 From: Dominik Roos Date: Tue, 2 Feb 2021 07:22:31 +0100 Subject: [PATCH 07/25] http: support additional content type (#903) Support `application/x-www-form-urlencoded` as an additional content type for `AtomicLevel.ServeHTTP`. This is the default content type for `curl -X POST`. With this change, interacting with the HTTP endpoint is a bit more user friendly: ``` curl -X PUT localhost:8080/log/level -d level=debug ``` Additionally, the unit tests for the HTTP handler are transformed to a table driven approach. fixes #902 Co-authored-by: Abhinav Gupta --- http_handler.go | 99 ++++++++++++----- http_handler_test.go | 249 ++++++++++++++++++++++++++----------------- 2 files changed, 229 insertions(+), 119 deletions(-) diff --git a/http_handler.go b/http_handler.go index 1b0ecaca9..1297c33b3 100644 --- a/http_handler.go +++ b/http_handler.go @@ -23,6 +23,7 @@ package zap import ( "encoding/json" "fmt" + "io" "net/http" "go.uber.org/zap/zapcore" @@ -31,47 +32,63 @@ import ( // ServeHTTP is a simple JSON endpoint that can report on or change the current // logging level. // -// GET requests return a JSON description of the current logging level. PUT -// requests change the logging level and expect a payload like: +// GET +// +// The GET request returns a JSON description of the current logging level like: // {"level":"info"} // -// It's perfectly safe to change the logging level while a program is running. +// PUT +// +// The PUT request changes the logging level. It is perfectly safe to change the +// logging level while a program is running. Two content types are supported: +// +// Content-Type: application/x-www-form-urlencoded +// +// With this content type, the level can be provided through the request body or +// a query parameter. The log level is URL encoded like: +// +// level=debug +// +// The request body takes precedence over the query parameter, if both are +// specified. +// +// This content type is the default for a curl PUT request. Following are two +// example curl requests that both set the logging level to debug. +// +// curl -X PUT localhost:8080/log/level?level=debug +// curl -X PUT localhost:8080/log/level -d level=debug +// +// For any other content type, the payload is expected to be JSON encoded and +// look like: +// +// {"level":"info"} +// +// An example curl request could look like this: +// +// curl -X PUT localhost:8080/log/level -H "Content-Type: application/json" -d '{"level":"debug"}' +// func (lvl AtomicLevel) ServeHTTP(w http.ResponseWriter, r *http.Request) { type errorResponse struct { Error string `json:"error"` } type payload struct { - Level *zapcore.Level `json:"level"` + Level zapcore.Level `json:"level"` } enc := json.NewEncoder(w) switch r.Method { - case http.MethodGet: - current := lvl.Level() - enc.Encode(payload{Level: ¤t}) - + enc.Encode(payload{Level: lvl.Level()}) case http.MethodPut: - var req payload - - if errmess := func() string { - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - return fmt.Sprintf("Request body must be well-formed JSON: %v", err) - } - if req.Level == nil { - return "Must specify a logging level." - } - return "" - }(); errmess != "" { + requestedLvl, err := decodePutRequest(r.Header.Get("Content-Type"), r) + if err != nil { w.WriteHeader(http.StatusBadRequest) - enc.Encode(errorResponse{Error: errmess}) + enc.Encode(errorResponse{Error: err.Error()}) return } - - lvl.SetLevel(*req.Level) - enc.Encode(req) - + lvl.SetLevel(requestedLvl) + enc.Encode(payload{Level: lvl.Level()}) default: w.WriteHeader(http.StatusMethodNotAllowed) enc.Encode(errorResponse{ @@ -79,3 +96,37 @@ func (lvl AtomicLevel) ServeHTTP(w http.ResponseWriter, r *http.Request) { }) } } + +// Decodes incoming PUT requests and returns the requested logging level. +func decodePutRequest(contentType string, r *http.Request) (zapcore.Level, error) { + if contentType == "application/x-www-form-urlencoded" { + return decodePutURL(r) + } + return decodePutJSON(r.Body) +} + +func decodePutURL(r *http.Request) (zapcore.Level, error) { + lvl := r.FormValue("level") + if lvl == "" { + return 0, fmt.Errorf("must specify logging level") + } + var l zapcore.Level + if err := l.UnmarshalText([]byte(lvl)); err != nil { + return 0, err + } + return l, nil +} + +func decodePutJSON(body io.Reader) (zapcore.Level, error) { + var pld struct { + Level *zapcore.Level `json:"level"` + } + if err := json.NewDecoder(body).Decode(&pld); err != nil { + return 0, fmt.Errorf("malformed request body: %v", err) + } + if pld.Level == nil { + return 0, fmt.Errorf("must specify logging level") + } + return *pld.Level, nil + +} diff --git a/http_handler_test.go b/http_handler_test.go index 474b3c7cd..9fa9c64c1 100644 --- a/http_handler_test.go +++ b/http_handler_test.go @@ -22,110 +22,169 @@ package zap_test import ( "encoding/json" - "fmt" - "io" - "io/ioutil" "net/http" "net/http/httptest" "strings" "testing" - . "go.uber.org/zap" + "go.uber.org/zap" "go.uber.org/zap/zapcore" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func newHandler() (AtomicLevel, *Logger) { - lvl := NewAtomicLevel() - logger := New(zapcore.NewNopCore()) - return lvl, logger -} - -func assertCodeOK(t testing.TB, code int) { - assert.Equal(t, http.StatusOK, code, "Unexpected response status code.") -} - -func assertCodeBadRequest(t testing.TB, code int) { - assert.Equal(t, http.StatusBadRequest, code, "Unexpected response status code.") -} - -func assertCodeMethodNotAllowed(t testing.TB, code int) { - assert.Equal(t, http.StatusMethodNotAllowed, code, "Unexpected response status code.") -} - -func assertResponse(t testing.TB, expectedLevel zapcore.Level, actualBody string) { - assert.Equal(t, fmt.Sprintf(`{"level":"%s"}`, expectedLevel)+"\n", actualBody, "Unexpected response body.") -} - -func assertJSONError(t testing.TB, body string) { - // Don't need to test exact error message, but one should be present. - var payload map[string]interface{} - require.NoError(t, json.Unmarshal([]byte(body), &payload), "Expected error response to be JSON.") - - msg, ok := payload["error"] - require.True(t, ok, "Error message is an unexpected type.") - assert.NotEqual(t, "", msg, "Expected an error message in response.") -} - -func makeRequest(t testing.TB, method string, handler http.Handler, reader io.Reader) (int, string) { - ts := httptest.NewServer(handler) - defer ts.Close() - - req, err := http.NewRequest(method, ts.URL, reader) - require.NoError(t, err, "Error constructing %s request.", method) - - res, err := http.DefaultClient.Do(req) - require.NoError(t, err, "Error making %s request.", method) - defer res.Body.Close() - - body, err := ioutil.ReadAll(res.Body) - require.NoError(t, err, "Error reading request body.") - - return res.StatusCode, string(body) -} - -func TestHTTPHandlerGetLevel(t *testing.T) { - lvl, _ := newHandler() - code, body := makeRequest(t, "GET", lvl, nil) - assertCodeOK(t, code) - assertResponse(t, lvl.Level(), body) -} - -func TestHTTPHandlerPutLevel(t *testing.T) { - lvl, _ := newHandler() - - code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{"level":"warn"}`)) - - assertCodeOK(t, code) - assertResponse(t, lvl.Level(), body) -} - -func TestHTTPHandlerPutUnrecognizedLevel(t *testing.T) { - lvl, _ := newHandler() - code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{"level":"unrecognized-level"}`)) - assertCodeBadRequest(t, code) - assertJSONError(t, body) -} - -func TestHTTPHandlerNotJSON(t *testing.T) { - lvl, _ := newHandler() - code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{`)) - assertCodeBadRequest(t, code) - assertJSONError(t, body) -} - -func TestHTTPHandlerNoLevelSpecified(t *testing.T) { - lvl, _ := newHandler() - code, body := makeRequest(t, "PUT", lvl, strings.NewReader(`{}`)) - assertCodeBadRequest(t, code) - assertJSONError(t, body) -} - -func TestHTTPHandlerMethodNotAllowed(t *testing.T) { - lvl, _ := newHandler() - code, body := makeRequest(t, "POST", lvl, strings.NewReader(`{`)) - assertCodeMethodNotAllowed(t, code) - assertJSONError(t, body) +func TestAtomicLevelServeHTTP(t *testing.T) { + tests := []struct { + desc string + method string + query string + contentType string + body string + expectedCode int + expectedLevel zapcore.Level + }{ + { + desc: "GET", + method: http.MethodGet, + expectedCode: http.StatusOK, + expectedLevel: zap.InfoLevel, + }, + { + desc: "PUT JSON", + method: http.MethodPut, + expectedCode: http.StatusOK, + expectedLevel: zap.WarnLevel, + body: `{"level":"warn"}`, + }, + { + desc: "PUT URL encoded", + method: http.MethodPut, + expectedCode: http.StatusOK, + expectedLevel: zap.WarnLevel, + contentType: "application/x-www-form-urlencoded", + body: "level=warn", + }, + { + desc: "PUT query parameters", + method: http.MethodPut, + query: "?level=warn", + expectedCode: http.StatusOK, + expectedLevel: zap.WarnLevel, + contentType: "application/x-www-form-urlencoded", + }, + { + desc: "body takes precedence over query", + method: http.MethodPut, + query: "?level=info", + expectedCode: http.StatusOK, + expectedLevel: zap.WarnLevel, + contentType: "application/x-www-form-urlencoded", + body: "level=warn", + }, + { + desc: "JSON ignores query", + method: http.MethodPut, + query: "?level=info", + expectedCode: http.StatusOK, + expectedLevel: zap.WarnLevel, + body: `{"level":"warn"}`, + }, + { + desc: "PUT JSON unrecognized", + method: http.MethodPut, + expectedCode: http.StatusBadRequest, + body: `{"level":"unrecognized"}`, + }, + { + desc: "PUT URL encoded unrecognized", + method: http.MethodPut, + expectedCode: http.StatusBadRequest, + contentType: "application/x-www-form-urlencoded", + body: "level=unrecognized", + }, + { + desc: "PUT JSON malformed", + method: http.MethodPut, + expectedCode: http.StatusBadRequest, + body: `{"level":"warn`, + }, + { + desc: "PUT URL encoded malformed", + method: http.MethodPut, + query: "?level=%", + expectedCode: http.StatusBadRequest, + contentType: "application/x-www-form-urlencoded", + }, + { + desc: "PUT Query parameters malformed", + method: http.MethodPut, + expectedCode: http.StatusBadRequest, + contentType: "application/x-www-form-urlencoded", + body: "level=%", + }, + { + desc: "PUT JSON unspecified", + method: http.MethodPut, + expectedCode: http.StatusBadRequest, + body: `{}`, + }, + { + desc: "PUT URL encoded unspecified", + method: http.MethodPut, + expectedCode: http.StatusBadRequest, + contentType: "application/x-www-form-urlencoded", + body: "", + }, + { + desc: "POST JSON", + method: http.MethodPost, + expectedCode: http.StatusMethodNotAllowed, + body: `{"level":"warn"}`, + }, + { + desc: "POST URL", + method: http.MethodPost, + expectedCode: http.StatusMethodNotAllowed, + contentType: "application/x-www-form-urlencoded", + body: "level=warn", + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + lvl := zap.NewAtomicLevel() + lvl.SetLevel(zapcore.InfoLevel) + + server := httptest.NewServer(lvl) + defer server.Close() + + req, err := http.NewRequest(tt.method, server.URL+tt.query, strings.NewReader(tt.body)) + require.NoError(t, err, "Error constructing %s request.", req.Method) + if tt.contentType != "" { + req.Header.Set("Content-Type", tt.contentType) + } + + res, err := http.DefaultClient.Do(req) + require.NoError(t, err, "Error making %s request.", req.Method) + defer res.Body.Close() + + require.Equal(t, tt.expectedCode, res.StatusCode, "Unexpected status code.") + if tt.expectedCode != http.StatusOK { + // Don't need to test exact error message, but one should be present. + var pld struct { + Error string `json:"error"` + } + require.NoError(t, json.NewDecoder(res.Body).Decode(&pld), "Decoding response body") + assert.NotEmpty(t, pld.Error, "Expected an error message") + return + } + + var pld struct { + Level zapcore.Level `json:"level"` + } + require.NoError(t, json.NewDecoder(res.Body).Decode(&pld), "Decoding response body") + assert.Equal(t, tt.expectedLevel, pld.Level, "Unexpected logging level returned") + }) + } } From 9f3c0ee8caf4e5ba2370654c251b27a4a3dc71c5 Mon Sep 17 00:00:00 2001 From: Shubhendra Singh Chauhan Date: Thu, 4 Feb 2021 02:01:18 +0530 Subject: [PATCH 08/25] Fix: code quality issues using DeepSource (#907) --- logger.go | 2 +- zapcore/console_encoder.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/logger.go b/logger.go index bdcc5d666..553f258e7 100644 --- a/logger.go +++ b/logger.go @@ -335,7 +335,7 @@ func getCallerFrame(skip int) (frame runtime.Frame, ok bool) { const skipOffset = 2 // skip getCallerFrame and Callers pc := make([]uintptr, 1) - numFrames := runtime.Callers(skip+skipOffset, pc[:]) + numFrames := runtime.Callers(skip+skipOffset, pc) if numFrames < 1 { return } diff --git a/zapcore/console_encoder.go b/zapcore/console_encoder.go index 3b68f8c0c..2307af404 100644 --- a/zapcore/console_encoder.go +++ b/zapcore/console_encoder.go @@ -56,7 +56,7 @@ type consoleEncoder struct { // encoder configuration, it will omit any element whose key is set to the empty // string. func NewConsoleEncoder(cfg EncoderConfig) Encoder { - if len(cfg.ConsoleSeparator) == 0 { + if cfg.ConsoleSeparator == "" { // Use a default delimiter of '\t' for backwards compatibility cfg.ConsoleSeparator = "\t" } From dca7c25204b05b0bb372c05542a06a0e8fc26bb7 Mon Sep 17 00:00:00 2001 From: Prashant Varanasi Date: Mon, 8 Feb 2021 09:03:36 -0800 Subject: [PATCH 09/25] Optimize Sugar logger for calls with a single string arg (#913) Currently, the Sugar logger uses fmt.Sprint in all cases when the template is empty. However, this call is unnecessary if there's a single string type argument, as we can use it directly. With this optimization, we reduce the cost and avoid an unnecessary alloc: ``` > benchcmp pre post benchmark old ns/op new ns/op delta BenchmarkSugarSingleStrArg-10 636 570 -10.38% benchmark old allocs new allocs delta BenchmarkSugarSingleStrArg-10 1 0 -100.00% ``` --- sugar.go | 27 +++++++++++++++++++-------- sugar_test.go | 8 ++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/sugar.go b/sugar.go index 77ca227f4..4084dada7 100644 --- a/sugar.go +++ b/sugar.go @@ -222,19 +222,30 @@ func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interf return } - // Format with Sprint, Sprintf, or neither. - msg := template - if msg == "" && len(fmtArgs) > 0 { - msg = fmt.Sprint(fmtArgs...) - } else if msg != "" && len(fmtArgs) > 0 { - msg = fmt.Sprintf(template, fmtArgs...) - } - + msg := getMessage(template, fmtArgs) if ce := s.base.Check(lvl, msg); ce != nil { ce.Write(s.sweetenFields(context)...) } } +// getMessage format with Sprint, Sprintf, or neither. +func getMessage(template string, fmtArgs []interface{}) string { + if len(fmtArgs) == 0 { + return template + } + + if template != "" { + return fmt.Sprintf(template, fmtArgs...) + } + + if len(fmtArgs) == 1 { + if str, ok := fmtArgs[0].(string); ok { + return str + } + } + return fmt.Sprint(fmtArgs...) +} + func (s *SugaredLogger) sweetenFields(args []interface{}) []Field { if len(args) == 0 { return nil diff --git a/sugar_test.go b/sugar_test.go index 5f4bb83b9..ac7b92064 100644 --- a/sugar_test.go +++ b/sugar_test.go @@ -368,3 +368,11 @@ func TestSugarAddCallerFail(t *testing.T) { "Expected original message to survive failures in runtime.Caller.") }) } + +func BenchmarkSugarSingleStrArg(b *testing.B) { + withSugar(b, InfoLevel, nil /* opts* */, func(log *SugaredLogger, logs *observer.ObservedLogs) { + for i := 0; i < b.N; i++ { + log.Info("hello world") + } + }) +} From d5dd706d23b1060c02bc4eae9d760d6540bbf4c6 Mon Sep 17 00:00:00 2001 From: Darrel Herbst Date: Tue, 9 Feb 2021 17:04:46 -0500 Subject: [PATCH 10/25] Remove outdated information, make dependencies is no longer necessary. (#915) --- CONTRIBUTING.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9454bbaf0..5cd965687 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,12 +25,6 @@ git remote add upstream https://github.com/uber-go/zap.git git fetch upstream ``` -Install zap's dependencies: - -``` -make dependencies -``` - Make sure that the tests and the linters pass: ``` From b73d9b50dfd260018e53964625dc2355d6631808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Th=C3=B6mmes?= Date: Fri, 12 Feb 2021 17:10:01 +0100 Subject: [PATCH 11/25] tools: Move to submodule (#914) This moves development tool dependencies to a subdirectory so that these are not added as dependencies of zap. --- Makefile | 4 ++-- go.mod | 2 -- tools/go.mod | 9 +++++++++ tools/go.sum | 29 +++++++++++++++++++++++++++++ tools_test.go => tools/tools.go | 2 +- 5 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 tools/go.mod create mode 100644 tools/go.sum rename tools_test.go => tools/tools.go (98%) diff --git a/Makefile b/Makefile index dfaf6406e..d7d22717d 100644 --- a/Makefile +++ b/Makefile @@ -35,10 +35,10 @@ lint: $(GOLINT) $(STATICCHECK) @[ ! -s lint.log ] $(GOLINT): - go install golang.org/x/lint/golint + cd tools && go install golang.org/x/lint/golint $(STATICCHECK): - go install honnef.co/go/tools/cmd/staticcheck + cd tools && go install honnef.co/go/tools/cmd/staticcheck .PHONY: test test: diff --git a/go.mod b/go.mod index 6ef4db70e..4d75a7f1e 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,5 @@ require ( github.com/stretchr/testify v1.4.0 go.uber.org/atomic v1.6.0 go.uber.org/multierr v1.5.0 - golang.org/x/lint v0.0.0-20190930215403-16217165b5de gopkg.in/yaml.v2 v2.2.2 - honnef.co/go/tools v0.0.1-2019.2.3 ) diff --git a/tools/go.mod b/tools/go.mod new file mode 100644 index 000000000..ecf102536 --- /dev/null +++ b/tools/go.mod @@ -0,0 +1,9 @@ +module go.uber.org/zap/tools + +require ( + golang.org/x/lint v0.0.0-20190930215403-16217165b5de + golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 // indirect + honnef.co/go/tools v0.0.1-2019.2.3 +) + +go 1.13 diff --git a/tools/go.sum b/tools/go.sum new file mode 100644 index 000000000..6273acd76 --- /dev/null +++ b/tools/go.sum @@ -0,0 +1,29 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +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 h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +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/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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +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-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/tools_test.go b/tools/tools.go similarity index 98% rename from tools_test.go rename to tools/tools.go index 67e9f5801..e12570210 100644 --- a/tools_test.go +++ b/tools/tools.go @@ -20,7 +20,7 @@ // +build tools -package zap +package tools import ( // Tools we use during development. From 6f4d0936853ff4db6434e8087ce0e2c57174286a Mon Sep 17 00:00:00 2001 From: Mikhail Mazurskiy <126021+ash2k@users.noreply.github.com> Date: Sat, 13 Feb 2021 08:10:49 +1100 Subject: [PATCH 12/25] Add support for grpclog.LoggerV2 (#881) gRPC has an updated [logger interface][1] that the v1 API has been deprecated in favor of. [1]: https://pkg.go.dev/google.golang.org/grpc/grpclog#LoggerV2 This adds support for it to the existing gRPC adapter in Zap. Fixes #534 Closes #538 Co-authored-by: Prashant Varanasi Co-authored-by: Abhinav Gupta --- Makefile | 2 +- zapgrpc/internal/test/README.md | 2 + zapgrpc/internal/test/go.mod | 11 ++ zapgrpc/internal/test/go.sum | 123 ++++++++++++++++++ zapgrpc/internal/test/grpc_test.go | 51 ++++++++ zapgrpc/zapgrpc.go | 199 ++++++++++++++++++++++++----- zapgrpc/zapgrpc_test.go | 180 +++++++++++++++++++++++--- 7 files changed, 522 insertions(+), 46 deletions(-) create mode 100644 zapgrpc/internal/test/README.md create mode 100644 zapgrpc/internal/test/go.mod create mode 100644 zapgrpc/internal/test/go.sum create mode 100644 zapgrpc/internal/test/grpc_test.go diff --git a/Makefile b/Makefile index d7d22717d..cd22d480b 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem # Directories containing independent Go modules. # # We track coverage only for the main module. -MODULE_DIRS = . ./benchmarks +MODULE_DIRS = . ./benchmarks ./zapgrpc/internal/test # Many Go tools take file globs or directories as arguments instead of packages. GO_FILES := $(shell \ diff --git a/zapgrpc/internal/test/README.md b/zapgrpc/internal/test/README.md new file mode 100644 index 000000000..b2f3f0f80 --- /dev/null +++ b/zapgrpc/internal/test/README.md @@ -0,0 +1,2 @@ +This submodule exists to test zapgrpc against grpc-go without adding a +dependency on grpc-go to Zap. diff --git a/zapgrpc/internal/test/go.mod b/zapgrpc/internal/test/go.mod new file mode 100644 index 000000000..a8b1683a7 --- /dev/null +++ b/zapgrpc/internal/test/go.mod @@ -0,0 +1,11 @@ +module go.uber.org/zap/zapgrpc/internal/test + +go 1.15 + +require ( + github.com/stretchr/testify v1.5.1 + go.uber.org/zap v1.16.0 + google.golang.org/grpc v1.35.0 +) + +replace go.uber.org/zap => ../../.. diff --git a/zapgrpc/internal/test/go.sum b/zapgrpc/internal/test/go.sum new file mode 100644 index 000000000..735587620 --- /dev/null +++ b/zapgrpc/internal/test/go.sum @@ -0,0 +1,123 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +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.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +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/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +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/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +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 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/zapgrpc/internal/test/grpc_test.go b/zapgrpc/internal/test/grpc_test.go new file mode 100644 index 000000000..f4befeb26 --- /dev/null +++ b/zapgrpc/internal/test/grpc_test.go @@ -0,0 +1,51 @@ +// Copyright (c) 2021 Uber Technologies, Inc. +// +// 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. + +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zapgrpc" + "go.uber.org/zap/zaptest/observer" + "google.golang.org/grpc/grpclog" +) + +func TestLoggerV2(t *testing.T) { + core, observedLogs := observer.New(zapcore.InfoLevel) + zlog := zap.New(core) + + grpclog.SetLoggerV2(zapgrpc.NewLogger(zlog)) + + grpclog.Info("hello from grpc") + + logs := observedLogs.TakeAll() + require.Len(t, logs, 1, "Expected one log entry.") + entry := logs[0] + + assert.Equal(t, zapcore.InfoLevel, entry.Level, + "Log entry level did not match.") + assert.Equal(t, "hello from grpc", entry.Message, + "Log entry message did not match.") +} diff --git a/zapgrpc/zapgrpc.go b/zapgrpc/zapgrpc.go index 1181e6a0d..356e12741 100644 --- a/zapgrpc/zapgrpc.go +++ b/zapgrpc/zapgrpc.go @@ -21,7 +21,31 @@ // Package zapgrpc provides a logger that is compatible with grpclog. package zapgrpc // import "go.uber.org/zap/zapgrpc" -import "go.uber.org/zap" +import ( + "fmt" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// See https://github.com/grpc/grpc-go/blob/v1.35.0/grpclog/loggerv2.go#L77-L86 +const ( + grpcLvlInfo = 0 + grpcLvlWarn = 1 + grpcLvlError = 2 + grpcLvlFatal = 3 +) + +var ( + // _grpcToZapLevel maps gRPC log levels to zap log levels. + // See https://pkg.go.dev/go.uber.org/zap@v1.16.0/zapcore#Level + _grpcToZapLevel = map[int]zapcore.Level{ + grpcLvlInfo: zapcore.InfoLevel, + grpcLvlWarn: zapcore.WarnLevel, + grpcLvlError: zapcore.ErrorLevel, + grpcLvlFatal: zapcore.FatalLevel, + } +) // An Option overrides a Logger's default configuration. type Option interface { @@ -36,23 +60,49 @@ func (f optionFunc) apply(log *Logger) { // WithDebug configures a Logger to print at zap's DebugLevel instead of // InfoLevel. +// It only affects the Printf, Println and Print methods, which are only used in the gRPC v1 grpclog.Logger API. +// Deprecated: use grpclog.SetLoggerV2() for v2 API. func WithDebug() Option { return optionFunc(func(logger *Logger) { - logger.print = (*zap.SugaredLogger).Debug - logger.printf = (*zap.SugaredLogger).Debugf + logger.print = &printer{ + enab: logger.levelEnabler, + level: zapcore.DebugLevel, + print: logger.delegate.Debug, + printf: logger.delegate.Debugf, + } + }) +} + +// withWarn redirects the fatal level to the warn level, which makes testing +// easier. This is intentionally unexported. +func withWarn() Option { + return optionFunc(func(logger *Logger) { + logger.fatal = &printer{ + enab: logger.levelEnabler, + level: zapcore.WarnLevel, + print: logger.delegate.Warn, + printf: logger.delegate.Warnf, + } }) } // NewLogger returns a new Logger. -// -// By default, Loggers print at zap's InfoLevel. func NewLogger(l *zap.Logger, options ...Option) *Logger { logger := &Logger{ - log: l.Sugar(), - fatal: (*zap.SugaredLogger).Fatal, - fatalf: (*zap.SugaredLogger).Fatalf, - print: (*zap.SugaredLogger).Info, - printf: (*zap.SugaredLogger).Infof, + delegate: l.Sugar(), + levelEnabler: l.Core(), + } + logger.print = &printer{ + enab: logger.levelEnabler, + level: zapcore.InfoLevel, + print: logger.delegate.Info, + printf: logger.delegate.Infof, + } + logger.fatal = &printer{ + enab: logger.levelEnabler, + level: zapcore.FatalLevel, + print: logger.delegate.Fatal, + printf: logger.delegate.Fatalf, } for _, option := range options { option.apply(logger) @@ -60,41 +110,132 @@ func NewLogger(l *zap.Logger, options ...Option) *Logger { return logger } -// Logger adapts zap's Logger to be compatible with grpclog.Logger. -type Logger struct { - log *zap.SugaredLogger - fatal func(*zap.SugaredLogger, ...interface{}) - fatalf func(*zap.SugaredLogger, string, ...interface{}) - print func(*zap.SugaredLogger, ...interface{}) - printf func(*zap.SugaredLogger, string, ...interface{}) +// printer implements Print, Printf, and Println operations for a Zap level. +// +// We use it to customize Debug vs Info, and Warn vs Fatal for Print and Fatal +// respectively. +type printer struct { + enab zapcore.LevelEnabler + level zapcore.Level + print func(...interface{}) + printf func(string, ...interface{}) } -// Fatal implements grpclog.Logger. -func (l *Logger) Fatal(args ...interface{}) { - l.fatal(l.log, args...) +func (v *printer) Print(args ...interface{}) { + v.print(args...) } -// Fatalf implements grpclog.Logger. -func (l *Logger) Fatalf(format string, args ...interface{}) { - l.fatalf(l.log, format, args...) +func (v *printer) Printf(format string, args ...interface{}) { + v.printf(format, args...) } -// Fatalln implements grpclog.Logger. -func (l *Logger) Fatalln(args ...interface{}) { - l.fatal(l.log, args...) +func (v *printer) Println(args ...interface{}) { + if v.enab.Enabled(v.level) { + v.print(sprintln(args)) + } +} + +// Logger adapts zap's Logger to be compatible with grpclog.LoggerV2 and the deprecated grpclog.Logger. +type Logger struct { + delegate *zap.SugaredLogger + levelEnabler zapcore.LevelEnabler + print *printer + fatal *printer + // printToDebug bool + // fatalToWarn bool } // Print implements grpclog.Logger. +// Deprecated: use Info(). func (l *Logger) Print(args ...interface{}) { - l.print(l.log, args...) + l.print.Print(args...) } // Printf implements grpclog.Logger. +// Deprecated: use Infof(). func (l *Logger) Printf(format string, args ...interface{}) { - l.printf(l.log, format, args...) + l.print.Printf(format, args...) } // Println implements grpclog.Logger. +// Deprecated: use Info(). func (l *Logger) Println(args ...interface{}) { - l.print(l.log, args...) + l.print.Println(args...) +} + +// Info implements grpclog.LoggerV2. +func (l *Logger) Info(args ...interface{}) { + l.delegate.Info(args...) +} + +// Infoln implements grpclog.LoggerV2. +func (l *Logger) Infoln(args ...interface{}) { + if l.levelEnabler.Enabled(zapcore.InfoLevel) { + l.delegate.Info(sprintln(args)) + } +} + +// Infof implements grpclog.LoggerV2. +func (l *Logger) Infof(format string, args ...interface{}) { + l.delegate.Infof(format, args...) +} + +// Warning implements grpclog.LoggerV2. +func (l *Logger) Warning(args ...interface{}) { + l.delegate.Warn(args...) +} + +// Warningln implements grpclog.LoggerV2. +func (l *Logger) Warningln(args ...interface{}) { + if l.levelEnabler.Enabled(zapcore.WarnLevel) { + l.delegate.Warn(sprintln(args)) + } +} + +// Warningf implements grpclog.LoggerV2. +func (l *Logger) Warningf(format string, args ...interface{}) { + l.delegate.Warnf(format, args...) +} + +// Error implements grpclog.LoggerV2. +func (l *Logger) Error(args ...interface{}) { + l.delegate.Error(args...) +} + +// Errorln implements grpclog.LoggerV2. +func (l *Logger) Errorln(args ...interface{}) { + if l.levelEnabler.Enabled(zapcore.ErrorLevel) { + l.delegate.Error(sprintln(args)) + } +} + +// Errorf implements grpclog.LoggerV2. +func (l *Logger) Errorf(format string, args ...interface{}) { + l.delegate.Errorf(format, args...) +} + +// Fatal implements grpclog.LoggerV2. +func (l *Logger) Fatal(args ...interface{}) { + l.fatal.Print(args...) +} + +// Fatalln implements grpclog.LoggerV2. +func (l *Logger) Fatalln(args ...interface{}) { + l.fatal.Println(args...) +} + +// Fatalf implements grpclog.LoggerV2. +func (l *Logger) Fatalf(format string, args ...interface{}) { + l.fatal.Printf(format, args...) +} + +// V implements grpclog.LoggerV2. +func (l *Logger) V(level int) bool { + return l.levelEnabler.Enabled(_grpcToZapLevel[level]) +} + +func sprintln(args []interface{}) string { + s := fmt.Sprintln(args...) + // Drop the new line character added by Sprintln + return s[:len(s)-1] } diff --git a/zapgrpc/zapgrpc_test.go b/zapgrpc/zapgrpc_test.go index 036f3d764..a231d65ec 100644 --- a/zapgrpc/zapgrpc_test.go +++ b/zapgrpc/zapgrpc_test.go @@ -21,6 +21,7 @@ package zapgrpc import ( + "fmt" "testing" "go.uber.org/zap" @@ -33,44 +34,200 @@ import ( func TestLoggerInfoExpected(t *testing.T) { checkMessages(t, zapcore.DebugLevel, nil, zapcore.InfoLevel, []string{ "hello", - "world", + "s1s21 2 3s34s56", + "hello world", + "", "foo", + "foo bar", + "s1 s2 1 2 3 s3 4 s5 6", + "hello", + "s1s21 2 3s34s56", + "hello world", + "", + "foo", + "foo bar", + "s1 s2 1 2 3 s3 4 s5 6", }, func(logger *Logger) { + logger.Info("hello") + logger.Info("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) + logger.Infof("%s world", "hello") + logger.Infoln() + logger.Infoln("foo") + logger.Infoln("foo", "bar") + logger.Infoln("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) logger.Print("hello") - logger.Printf("world") + logger.Print("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) + logger.Printf("%s world", "hello") + logger.Println() logger.Println("foo") + logger.Println("foo", "bar") + logger.Println("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) }) } func TestLoggerDebugExpected(t *testing.T) { checkMessages(t, zapcore.DebugLevel, []Option{WithDebug()}, zapcore.DebugLevel, []string{ "hello", - "world", + "s1s21 2 3s34s56", + "hello world", + "", "foo", + "foo bar", + "s1 s2 1 2 3 s3 4 s5 6", }, func(logger *Logger) { logger.Print("hello") - logger.Printf("world") + logger.Print("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) + logger.Printf("%s world", "hello") + logger.Println() logger.Println("foo") + logger.Println("foo", "bar") + logger.Println("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) }) } func TestLoggerDebugSuppressed(t *testing.T) { checkMessages(t, zapcore.InfoLevel, []Option{WithDebug()}, zapcore.DebugLevel, nil, func(logger *Logger) { logger.Print("hello") - logger.Printf("world") + logger.Printf("%s world", "hello") + logger.Println() logger.Println("foo") + logger.Println("foo", "bar") + }) +} + +func TestLoggerWarningExpected(t *testing.T) { + checkMessages(t, zapcore.DebugLevel, nil, zapcore.WarnLevel, []string{ + "hello", + "s1s21 2 3s34s56", + "hello world", + "", + "foo", + "foo bar", + "s1 s2 1 2 3 s3 4 s5 6", + }, func(logger *Logger) { + logger.Warning("hello") + logger.Warning("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) + logger.Warningf("%s world", "hello") + logger.Warningln() + logger.Warningln("foo") + logger.Warningln("foo", "bar") + logger.Warningln("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) + }) +} + +func TestLoggerErrorExpected(t *testing.T) { + checkMessages(t, zapcore.DebugLevel, nil, zapcore.ErrorLevel, []string{ + "hello", + "s1s21 2 3s34s56", + "hello world", + "", + "foo", + "foo bar", + "s1 s2 1 2 3 s3 4 s5 6", + }, func(logger *Logger) { + logger.Error("hello") + logger.Error("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) + logger.Errorf("%s world", "hello") + logger.Errorln() + logger.Errorln("foo") + logger.Errorln("foo", "bar") + logger.Errorln("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) }) } func TestLoggerFatalExpected(t *testing.T) { checkMessages(t, zapcore.DebugLevel, nil, zapcore.FatalLevel, []string{ "hello", - "world", + "s1s21 2 3s34s56", + "hello world", + "", "foo", + "foo bar", + "s1 s2 1 2 3 s3 4 s5 6", }, func(logger *Logger) { logger.Fatal("hello") - logger.Fatalf("world") + logger.Fatal("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) + logger.Fatalf("%s world", "hello") + logger.Fatalln() logger.Fatalln("foo") + logger.Fatalln("foo", "bar") + logger.Fatalln("s1", "s2", 1, 2, 3, "s3", 4, "s5", 6) + }) +} + +func TestLoggerV(t *testing.T) { + tests := []struct { + zapLevel zapcore.Level + grpcEnabled []int + grpcDisabled []int + }{ + { + zapLevel: zapcore.DebugLevel, + grpcEnabled: []int{grpcLvlInfo, grpcLvlWarn, grpcLvlError, grpcLvlFatal}, + grpcDisabled: []int{}, // everything is enabled, nothing is disabled + }, + { + zapLevel: zapcore.InfoLevel, + grpcEnabled: []int{grpcLvlInfo, grpcLvlWarn, grpcLvlError, grpcLvlFatal}, + grpcDisabled: []int{}, // everything is enabled, nothing is disabled + }, + { + zapLevel: zapcore.WarnLevel, + grpcEnabled: []int{grpcLvlWarn, grpcLvlError, grpcLvlFatal}, + grpcDisabled: []int{grpcLvlInfo}, + }, + { + zapLevel: zapcore.ErrorLevel, + grpcEnabled: []int{grpcLvlError, grpcLvlFatal}, + grpcDisabled: []int{grpcLvlInfo, grpcLvlWarn}, + }, + { + zapLevel: zapcore.DPanicLevel, + grpcEnabled: []int{grpcLvlFatal}, + grpcDisabled: []int{grpcLvlInfo, grpcLvlWarn, grpcLvlError}, + }, + { + zapLevel: zapcore.PanicLevel, + grpcEnabled: []int{grpcLvlFatal}, + grpcDisabled: []int{grpcLvlInfo, grpcLvlWarn, grpcLvlError}, + }, + { + zapLevel: zapcore.FatalLevel, + grpcEnabled: []int{grpcLvlFatal}, + grpcDisabled: []int{grpcLvlInfo, grpcLvlWarn, grpcLvlError}, + }, + } + for _, tst := range tests { + for _, grpcLvl := range tst.grpcEnabled { + t.Run(fmt.Sprintf("enabled %s %d", tst.zapLevel, grpcLvl), func(t *testing.T) { + checkLevel(t, tst.zapLevel, true, func(logger *Logger) bool { + return logger.V(grpcLvl) + }) + }) + } + for _, grpcLvl := range tst.grpcDisabled { + t.Run(fmt.Sprintf("disabled %s %d", tst.zapLevel, grpcLvl), func(t *testing.T) { + checkLevel(t, tst.zapLevel, false, func(logger *Logger) bool { + return logger.V(grpcLvl) + }) + }) + } + } +} + +func checkLevel( + t testing.TB, + enab zapcore.LevelEnabler, + expectedBool bool, + f func(*Logger) bool, +) { + withLogger(enab, nil, func(logger *Logger, observedLogs *observer.ObservedLogs) { + actualBool := f(logger) + if expectedBool { + require.True(t, actualBool) + } else { + require.False(t, actualBool) + } }) } @@ -104,12 +261,3 @@ func withLogger( core, observedLogs := observer.New(enab) f(NewLogger(zap.New(core), append(opts, withWarn())...), observedLogs) } - -// withWarn redirects the fatal level to the warn level, which makes testing -// easier. -func withWarn() Option { - return optionFunc(func(logger *Logger) { - logger.fatal = (*zap.SugaredLogger).Warn - logger.fatalf = (*zap.SugaredLogger).Warnf - }) -} From 016a93b0ebe33f4a7911de21facb5fdb10306783 Mon Sep 17 00:00:00 2001 From: Prashant Varanasi Date: Tue, 23 Mar 2021 08:27:47 -0700 Subject: [PATCH 13/25] Support multi-field encoding using zap.Inline (#912) Fixes #876 Currently, a `zap.Field` can only represent a single key-value. Add `zap.Inline` to allow adding multiple fields to the current namespace from a type implementing `zap.ObjectMarshaler`. This also solves a more general problem: a single `zap.Field` can now be used to add multiple key/value pairs. --- example_test.go | 39 +++++++++++++++++++++++++++++++++++++++ field.go | 10 ++++++++++ field_test.go | 1 + zapcore/field.go | 5 +++++ zapcore/field_test.go | 23 ++++++++++++++++++++++- 5 files changed, 77 insertions(+), 1 deletion(-) diff --git a/example_test.go b/example_test.go index ab5733f45..28474d0cd 100644 --- a/example_test.go +++ b/example_test.go @@ -165,6 +165,45 @@ func ExampleNamespace() { // {"level":"info","msg":"tracked some metrics","metrics":{"counter":1}} } +type addr struct { + IP string + Port int +} + +type request struct { + URL string + Listen addr + Remote addr +} + +func (a addr) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddString("ip", a.IP) + enc.AddInt("port", a.Port) + return nil +} + +func (r request) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddString("url", r.URL) + zap.Inline(r.Listen).AddTo(enc) + return enc.AddObject("remote", r.Remote) +} + +func ExampleObject() { + logger := zap.NewExample() + defer logger.Sync() + + req := &request{ + URL: "/test", + Listen: addr{"127.0.0.1", 8080}, + Remote: addr{"127.0.0.1", 31200}, + } + logger.Info("new request, in nested object", zap.Object("req", req)) + logger.Info("new request, inline", zap.Inline(req)) + // Output: + // {"level":"info","msg":"new request, in nested object","req":{"url":"/test","ip":"127.0.0.1","port":8080,"remote":{"ip":"127.0.0.1","port":31200}}} + // {"level":"info","msg":"new request, inline","url":"/test","ip":"127.0.0.1","port":8080,"remote":{"ip":"127.0.0.1","port":31200}} +} + func ExampleNewStdLog() { logger := zap.NewExample() defer logger.Sync() diff --git a/field.go b/field.go index 3c0d7d957..bbb745db5 100644 --- a/field.go +++ b/field.go @@ -400,6 +400,16 @@ func Object(key string, val zapcore.ObjectMarshaler) Field { return Field{Key: key, Type: zapcore.ObjectMarshalerType, Interface: val} } +// Inline constructs a Field that is similar to Object, but it +// will add the elements of the provided ObjectMarshaler to the +// current namespace. +func Inline(val zapcore.ObjectMarshaler) Field { + return zapcore.Field{ + Type: zapcore.InlineMarshalerType, + Interface: val, + } +} + // Any takes a key and an arbitrary value and chooses the best way to represent // them as a field, falling back to a reflection-based approach only if // necessary. diff --git a/field_test.go b/field_test.go index fbfc635d5..010e6fb4d 100644 --- a/field_test.go +++ b/field_test.go @@ -123,6 +123,7 @@ func TestFieldConstructors(t *testing.T) { {"Reflect", Field{Key: "k", Type: zapcore.ReflectType}, Reflect("k", nil)}, {"Stringer", Field{Key: "k", Type: zapcore.StringerType, Interface: addr}, Stringer("k", addr)}, {"Object", Field{Key: "k", Type: zapcore.ObjectMarshalerType, Interface: name}, Object("k", name)}, + {"Inline", Field{Type: zapcore.InlineMarshalerType, Interface: name}, Inline(name)}, {"Any:ObjectMarshaler", Any("k", name), Object("k", name)}, {"Any:ArrayMarshaler", Any("k", bools([]bool{true})), Array("k", bools([]bool{true}))}, {"Any:Stringer", Any("k", addr), Stringer("k", addr)}, diff --git a/zapcore/field.go b/zapcore/field.go index e0105868e..29daaace9 100644 --- a/zapcore/field.go +++ b/zapcore/field.go @@ -39,6 +39,9 @@ const ( ArrayMarshalerType // ObjectMarshalerType indicates that the field carries an ObjectMarshaler. ObjectMarshalerType + // InlineMarshalerType indicates that the field carries an ObjectMarshaler + // that should be inlined. + InlineMarshalerType // BinaryType indicates that the field carries an opaque binary blob. BinaryType // BoolType indicates that the field carries a bool. @@ -115,6 +118,8 @@ func (f Field) AddTo(enc ObjectEncoder) { err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler)) case ObjectMarshalerType: err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler)) + case InlineMarshalerType: + err = f.Interface.(ObjectMarshaler).MarshalLogObject(enc) case BinaryType: enc.AddBinary(f.Key, f.Interface.([]byte)) case BoolType: diff --git a/zapcore/field_test.go b/zapcore/field_test.go index 31de0b623..c4363297c 100644 --- a/zapcore/field_test.go +++ b/zapcore/field_test.go @@ -111,6 +111,7 @@ func TestFieldAddingError(t *testing.T) { }{ {t: ArrayMarshalerType, iface: users(-1), want: []interface{}{}, err: "too few users"}, {t: ObjectMarshalerType, iface: users(-1), want: map[string]interface{}{}, err: "too few users"}, + {t: InlineMarshalerType, iface: users(-1), want: nil, err: "too few users"}, {t: StringerType, iface: obj{}, want: empty, err: "PANIC=interface conversion: zapcore_test.obj is not fmt.Stringer: missing method String"}, {t: StringerType, iface: &obj{1}, want: empty, err: "PANIC=panic with string"}, {t: StringerType, iface: &obj{2}, want: empty, err: "PANIC=panic with error"}, @@ -136,7 +137,6 @@ func TestFields(t *testing.T) { }{ {t: ArrayMarshalerType, iface: users(2), want: []interface{}{"user", "user"}}, {t: ObjectMarshalerType, iface: users(2), want: map[string]interface{}{"users": 2}}, - {t: BinaryType, iface: []byte("foo"), want: []byte("foo")}, {t: BoolType, i: 0, want: false}, {t: ByteStringType, iface: []byte("foo"), want: "foo"}, {t: Complex128Type, iface: 1 + 2i, want: 1 + 2i}, @@ -180,6 +180,27 @@ func TestFields(t *testing.T) { } } +func TestInlineMarshaler(t *testing.T) { + enc := NewMapObjectEncoder() + + topLevelStr := Field{Key: "k", Type: StringType, String: "s"} + topLevelStr.AddTo(enc) + + inlineObj := Field{Key: "ignored", Type: InlineMarshalerType, Interface: users(10)} + inlineObj.AddTo(enc) + + nestedObj := Field{Key: "nested", Type: ObjectMarshalerType, Interface: users(11)} + nestedObj.AddTo(enc) + + assert.Equal(t, map[string]interface{}{ + "k": "s", + "users": 10, + "nested": map[string]interface{}{ + "users": 11, + }, + }, enc.Fields) +} + func TestEquals(t *testing.T) { // Values outside the UnixNano range were encoded incorrectly (#737, #803). timeOutOfRangeHigh := time.Unix(0, math.MaxInt64).Add(time.Nanosecond) From 8d5e39eb83032fbab6b775fce9d53377e44f20b9 Mon Sep 17 00:00:00 2001 From: r-hang <42982339+r-hang@users.noreply.github.com> Date: Tue, 23 Mar 2021 09:42:34 -0700 Subject: [PATCH 14/25] Add FilterFieldKey to zaptest/observer (#928) Adds functionality to filter zap.Field by key. This makes testing for field existence regardless of value more convenient. resolves https://github.com/uber-go/zap/issues/816 --- zaptest/observer/observer.go | 12 ++++++++++++ zaptest/observer/observer_test.go | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/zaptest/observer/observer.go b/zaptest/observer/observer.go index 78f5be45d..6ae58f5d6 100644 --- a/zaptest/observer/observer.go +++ b/zaptest/observer/observer.go @@ -104,6 +104,18 @@ func (o *ObservedLogs) FilterField(field zapcore.Field) *ObservedLogs { }) } +// FilterFieldKey filters entries to those that have the specified key. +func (o *ObservedLogs) FilterFieldKey(key string) *ObservedLogs { + return o.filter(func(e LoggedEntry) bool { + for _, ctxField := range e.Context { + if ctxField.Key == key { + return true + } + } + return false + }) +} + func (o *ObservedLogs) filter(match func(LoggedEntry) bool) *ObservedLogs { o.mu.RLock() defer o.mu.RUnlock() diff --git a/zaptest/observer/observer_test.go b/zaptest/observer/observer_test.go index e1a0da78c..4e8139493 100644 --- a/zaptest/observer/observer_test.go +++ b/zaptest/observer/observer_test.go @@ -149,6 +149,14 @@ func TestFilters(t *testing.T) { Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "any slice"}, Context: []zapcore.Field{zap.Any("slice", []string{"a"})}, }, + { + Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "msg 2"}, + Context: []zapcore.Field{zap.Int("b", 2), zap.Namespace("filterMe")}, + }, + { + Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "any slice"}, + Context: []zapcore.Field{zap.Any("filterMe", []string{"b"})}, + }, } logger, sink := New(zap.InfoLevel) @@ -206,6 +214,11 @@ func TestFilters(t *testing.T) { filtered: sink.FilterField(zap.Any("slice", []string{"a"})), want: logs[6:7], }, + { + msg: "filter field key", + filtered: sink.FilterFieldKey("filterMe"), + want: logs[7:9], + }, } for _, tt := range tests { From 92549f9c3d6a120dad5ed54b4b22c93a5bdca4ba Mon Sep 17 00:00:00 2001 From: Tim Soslow Date: Mon, 29 Mar 2021 12:53:01 -0500 Subject: [PATCH 15/25] Update dependencies to fix vulnerabilities (#931) - go.uber.org/atomic@1.6.0 - go.uber.org/multierr@1.5.0. Removes a lot of no longer needed dependencies and fixes vulnerabilities including the following: - golang.org/x/crypto (CVE-2020-9283) - golang.org/x/text (CVE-2020-14040) --- benchmarks/go.mod | 2 +- benchmarks/go.sum | 8 +++---- go.mod | 4 ++-- go.sum | 46 ++++-------------------------------- zapgrpc/internal/test/go.sum | 8 +++---- 5 files changed, 15 insertions(+), 53 deletions(-) diff --git a/benchmarks/go.mod b/benchmarks/go.mod index 3b3284409..de9fc1b5a 100644 --- a/benchmarks/go.mod +++ b/benchmarks/go.mod @@ -10,7 +10,7 @@ require ( github.com/go-stack/stack v1.8.0 // indirect github.com/rs/zerolog v1.16.0 github.com/sirupsen/logrus v1.4.2 - go.uber.org/multierr v1.5.0 + go.uber.org/multierr v1.6.0 go.uber.org/zap v0.0.0-00010101000000-000000000000 gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec ) diff --git a/benchmarks/go.sum b/benchmarks/go.sum index 251316f4d..114c83c6b 100644 --- a/benchmarks/go.sum +++ b/benchmarks/go.sum @@ -69,10 +69,10 @@ github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eN github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/go.mod b/go.mod index 4d75a7f1e..dddad98c7 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.13 require ( github.com/pkg/errors v0.8.1 github.com/stretchr/testify v1.4.0 - go.uber.org/atomic v1.6.0 - go.uber.org/multierr v1.5.0 + go.uber.org/atomic v1.7.0 + go.uber.org/multierr v1.6.0 gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index 99cdb93ea..7e0a7444a 100644 --- a/go.sum +++ b/go.sum @@ -1,56 +1,18 @@ -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 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/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 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 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -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 h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= -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/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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -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 h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/zapgrpc/internal/test/go.sum b/zapgrpc/internal/test/go.sum index 735587620..cd13440e9 100644 --- a/zapgrpc/internal/test/go.sum +++ b/zapgrpc/internal/test/go.sum @@ -47,10 +47,10 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= From 15dca18fe151506ed559175ea07865d48ec5f1de Mon Sep 17 00:00:00 2001 From: Prashant Varanasi Date: Tue, 20 Apr 2021 14:53:04 -0700 Subject: [PATCH 16/25] zapcore: Cleanup copy in NewMultiWriteSyncer (#934) The copy was originally in place due to https://github.com/golang/go/issues/7809 Since that issue was fixed in Go 1.3 a few years ago, it seems safe to drop the copy. --- zapcore/write_syncer.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zapcore/write_syncer.go b/zapcore/write_syncer.go index 209e25fe2..d4a1af3d0 100644 --- a/zapcore/write_syncer.go +++ b/zapcore/write_syncer.go @@ -91,8 +91,7 @@ func NewMultiWriteSyncer(ws ...WriteSyncer) WriteSyncer { if len(ws) == 1 { return ws[0] } - // Copy to protect against https://github.com/golang/go/issues/7809 - return multiWriteSyncer(append([]WriteSyncer(nil), ws...)) + return multiWriteSyncer(ws) } // See https://golang.org/src/io/multi.go From 9a9e13fa983b5391fb6d2dbaedd2cb2865123c82 Mon Sep 17 00:00:00 2001 From: Dmitriy Shirchenko Date: Mon, 17 May 2021 15:17:02 -0700 Subject: [PATCH 17/25] Switch from Travis to GitHub Actions (#940) We're deprecating use of Travis for our OSS projects, so switch to GitHub Actions for it. Unfortunately, this required dropping tests we had against ppc64le because [GitHub Workflows doesn't support it][1]. [1]: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#github-hosted-runners --- .github/workflows/go.yml | 52 ++++++++++++++++++++++++++++++++++++++++ .travis.yml | 28 ---------------------- README.md | 4 ++-- 3 files changed, 54 insertions(+), 30 deletions(-) create mode 100644 .github/workflows/go.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 000000000..d174d4129 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,52 @@ +name: Go + +on: + push: + branches: ['*'] + tags: ['v*'] + pull_request: + branches: ['*'] + +jobs: + + build: + runs-on: ubuntu-latest + strategy: + matrix: + go: ["1.15.x", "1.16.x"] + include: + - go: 1.16.x + latest: true + + steps: + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go }} + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Load cached dependencies + uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Download Dependencies + run: go mod download + + - name: Lint + if: matrix.latest + run: make lint + + - name: Test + run: make cover + + - name: Upload coverage to codecov.io + uses: codecov/codecov-action@v1 + + - name: Benchmark + run: make bench diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0a4c5e6ec..000000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: go - -sudo: false - -go_import_path: go.uber.org/zap -env: - global: - - TEST_TIMEOUT_SCALE=10 - - GO111MODULE=on - -matrix: - include: - - go: oldstable - - go: stable - env: LINT=1 - - arch: ppc64le - go: oldstable - - arch: ppc64le - go: stable - -script: - - test -z "$LINT" || make lint - - make test - - make bench - -after_success: - - make cover - - bash <(curl -s https://codecov.io/bash) diff --git a/README.md b/README.md index a3a5c09bd..1e64d6cff 100644 --- a/README.md +++ b/README.md @@ -125,8 +125,8 @@ pinned in the [benchmarks/go.mod][] file. [↩](#anchor-versions) [doc-img]: https://pkg.go.dev/badge/go.uber.org/zap [doc]: https://pkg.go.dev/go.uber.org/zap -[ci-img]: https://travis-ci.com/uber-go/zap.svg?branch=master -[ci]: https://travis-ci.com/uber-go/zap +[ci-img]: https://github.com/uber-go/zap/actions/workflows/go.yml/badge.svg +[ci]: https://github.com/uber-go/zap/actions/workflows/go.yml [cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg [cov]: https://codecov.io/gh/uber-go/zap [benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks From 34ea13cdf0fd1acd606700e3485819cdb40ebb47 Mon Sep 17 00:00:00 2001 From: James Lamb Date: Wed, 19 May 2021 01:38:49 +1000 Subject: [PATCH 18/25] Update dependencies to fix vulnerabilities in (#936) - gopkg.in/yaml.v2 v2.2.2 -> v.2.2.8 CVE-2019-11254 --- benchmarks/go.sum | 5 +++++ go.mod | 6 ++++-- go.sum | 14 ++++++++++---- zapgrpc/internal/test/go.mod | 2 +- zapgrpc/internal/test/go.sum | 7 +++++++ 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/benchmarks/go.sum b/benchmarks/go.sum index 114c83c6b..5a5d873d0 100644 --- a/benchmarks/go.sum +++ b/benchmarks/go.sum @@ -60,10 +60,12 @@ github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= @@ -113,5 +115,8 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/go.mod b/go.mod index dddad98c7..eac229944 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,10 @@ go 1.13 require ( github.com/pkg/errors v0.8.1 - github.com/stretchr/testify v1.4.0 + github.com/stretchr/objx v0.3.0 // indirect + github.com/stretchr/testify v1.7.0 go.uber.org/atomic v1.7.0 go.uber.org/multierr v1.6.0 - gopkg.in/yaml.v2 v2.2.2 + gopkg.in/yaml.v2 v2.2.8 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index 7e0a7444a..54e1ef039 100644 --- a/go.sum +++ b/go.sum @@ -6,13 +6,19 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= +github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/zapgrpc/internal/test/go.mod b/zapgrpc/internal/test/go.mod index a8b1683a7..c8efff4d9 100644 --- a/zapgrpc/internal/test/go.mod +++ b/zapgrpc/internal/test/go.mod @@ -3,7 +3,7 @@ module go.uber.org/zap/zapgrpc/internal/test go 1.15 require ( - github.com/stretchr/testify v1.5.1 + github.com/stretchr/testify v1.7.0 go.uber.org/zap v1.16.0 google.golang.org/grpc v1.35.0 ) diff --git a/zapgrpc/internal/test/go.sum b/zapgrpc/internal/test/go.sum index cd13440e9..ad15e8e39 100644 --- a/zapgrpc/internal/test/go.sum +++ b/zapgrpc/internal/test/go.sum @@ -43,10 +43,13 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 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.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= @@ -117,6 +120,10 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= From 2f8e3311701af01faa0293488f96244c9007f54d Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Tue, 18 May 2021 17:39:33 +0200 Subject: [PATCH 19/25] FAQ: Add zapfilter (#939) This utility allows creating a logger with "advanced" filters like in the following example. It is particularly convenient to use with a CLI flag package or using environment variables. core := zap.NewExample().Core() // *=myns => any level, myns namespace // info,warn:myns.* => info or warn level, any namespace matching myns.* // error=* => everything with error level logger := zap.New(zapfilter.NewFilteringCore(core, zapfilter.MustParseRules("*:myns info,warn:myns.* error:*"))) defer logger.Sync() logger.Debug("top debug") // no match logger.Named("myns").Debug("myns debug") // matches *:myns logger.Named("bar").Debug("bar debug") // no match logger.Named("myns").Named("foo").Debug("myns.foo debug") // no match logger.Info("top info") // no match logger.Named("myns").Info("myns info") // matches *:myns logger.Named("bar").Info("bar info") // no match logger.Named("myns").Named("foo").Info("myns.foo info") // matches info,warn:myns.* logger.Warn("top warn") // no match logger.Named("myns").Warn("myns warn") // matches *:myns logger.Named("bar").Warn("bar warn") // no match logger.Named("myns").Named("foo").Warn("myns.foo warn") // matches info,warn:myns.* logger.Error("top error") // matches error:* logger.Named("myns").Error("myns error") // matches *:myns and error:* logger.Named("bar").Error("bar error") // matches error:* logger.Named("myns").Named("foo").Error("myns.foo error") // matches error:* // Output: // {"level":"debug","logger":"myns","msg":"myns debug"} // {"level":"info","logger":"myns","msg":"myns info"} // {"level":"info","logger":"myns.foo","msg":"myns.foo info"} // {"level":"warn","logger":"myns","msg":"myns warn"} // {"level":"warn","logger":"myns.foo","msg":"myns.foo warn"} // {"level":"error","msg":"top error"} // {"level":"error","logger":"myns","msg":"myns error"} // {"level":"error","logger":"bar","msg":"bar error"} // {"level":"error","logger":"myns.foo","msg":"myns.foo error"} --- FAQ.md | 1 + 1 file changed, 1 insertion(+) diff --git a/FAQ.md b/FAQ.md index 626bda978..b183b20bc 100644 --- a/FAQ.md +++ b/FAQ.md @@ -157,6 +157,7 @@ We're aware of the following extensions, but haven't used them ourselves: | `github.com/fgrosse/zaptest` | Ginkgo | | `github.com/blendle/zapdriver` | Stackdriver | | `github.com/moul/zapgorm` | Gorm | +| `github.com/moul/zapfilter` | Advanced filtering rules | [go-proverbs]: https://go-proverbs.github.io/ [import-path]: https://golang.org/cmd/go/#hdr-Remote_import_paths From 2732714e2ec696d21c612e430adec18f0fb17370 Mon Sep 17 00:00:00 2001 From: tyltr <31768692+tylitianrui@users.noreply.github.com> Date: Tue, 18 May 2021 23:50:15 +0800 Subject: [PATCH 20/25] internal/readme: Simplify if condition (#945) Check for "both true" or "both false" is easily implemented as `x == y`. --- internal/readme/readme.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/readme/readme.go b/internal/readme/readme.go index 8b0609a1b..691005df9 100644 --- a/internal/readme/readme.go +++ b/internal/readme/readme.go @@ -234,7 +234,7 @@ func (b benchmarkRowsByTime) Less(i, j int) bool { leftZap, rightZap := strings.Contains(left.Name, "zap"), strings.Contains(right.Name, "zap") // If neither benchmark is for zap or both are, sort by time. - if !(leftZap || rightZap) || (leftZap && rightZap) { + if leftZap == rightZap { return left.Time.Nanoseconds() < right.Time.Nanoseconds() } // Sort zap benchmark first. From 756fb2a7c81e35de0bc22500d918e265406738aa Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Tue, 18 May 2021 11:00:53 -0700 Subject: [PATCH 21/25] go mod tidy (#947) A recent change to dependencies neglected to run `go mod tidy`. --- go.mod | 1 - go.sum | 2 -- 2 files changed, 3 deletions(-) diff --git a/go.mod b/go.mod index eac229944..6578a3545 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.13 require ( github.com/pkg/errors v0.8.1 - github.com/stretchr/objx v0.3.0 // indirect github.com/stretchr/testify v1.7.0 go.uber.org/atomic v1.7.0 go.uber.org/multierr v1.6.0 diff --git a/go.sum b/go.sum index 54e1ef039..911a87ae1 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,6 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= -github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= From 4110cb4e08f02c6137e517a9b6eef3a3c9f469ec Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Tue, 25 May 2021 09:58:18 -0700 Subject: [PATCH 22/25] lint: Check that 'go mod tidy' was run (#951) In #948, we noticed that some `go.sum` files were outdated. To avoid this in the future, add a `lint` check that verifies that `go mod tidy` does not cause any changes. This will fail with a dirty working tree as well, but in CI, we don't expect that. --- Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Makefile b/Makefile index cd22d480b..9b1bc3b0e 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,12 @@ lint: $(GOLINT) $(STATICCHECK) @echo "Checking for license headers..." @./checklicense.sh | tee -a lint.log @[ ! -s lint.log ] + @echo "Checking 'go mod tidy'..." + @make tidy + @if ! git diff --quiet; then \ + echo "'go mod tidy' resulted in changes or working tree is dirty:"; \ + git --no-pager diff; \ + fi $(GOLINT): cd tools && go install golang.org/x/lint/golint @@ -61,3 +67,7 @@ bench: updatereadme: rm -f README.md cat .readme.tmpl | go run internal/readme/readme.go > README.md + +.PHONY: tidy +tidy: + @$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go mod tidy) &&) true From d3092aa8474274db5f7ff2b18936a7669d583239 Mon Sep 17 00:00:00 2001 From: Manjari Akella Date: Tue, 25 May 2021 11:52:10 -0700 Subject: [PATCH 23/25] Integrate FOSSA (#953) Add a FOSSA check to the build steps. Resolves: GO-468 --- .github/workflows/go.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index d174d4129..ba3cfaabe 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -26,6 +26,11 @@ jobs: - name: Checkout code uses: actions/checkout@v2 + + - name: FOSSA analysis + uses: fossas/fossa-action@v1 + with: + api-key: ${{ secrets.FOSSA_API_KEY }} - name: Load cached dependencies uses: actions/cache@v1 From f612082cb41351ebbefa3a5017790eafae543266 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Tue, 25 May 2021 13:06:24 -0700 Subject: [PATCH 24/25] zapcore/FieldType: Don't change enum values (#955) Although the values of the FieldType enums aren't part of the Zap contract, changing existing values is still a risky change. [apidiff] considers this a brekaing change. ``` Incompatible changes: - BinaryType: value changed from 3 to 4 - BoolType: value changed from 4 to 5 - ByteStringType: value changed from 5 to 6 - Complex128Type: value changed from 6 to 7 - Complex64Type: value changed from 7 to 8 - DurationType: value changed from 8 to 9 - ErrorType: value changed from 26 to 27 - Float32Type: value changed from 10 to 11 - Float64Type: value changed from 9 to 10 - Int16Type: value changed from 13 to 14 - Int32Type: value changed from 12 to 13 - Int64Type: value changed from 11 to 12 - Int8Type: value changed from 14 to 15 - NamespaceType: value changed from 24 to 25 - ReflectType: value changed from 23 to 24 - SkipType: value changed from 27 to 28 - StringType: value changed from 15 to 16 - StringerType: value changed from 25 to 26 - TimeFullType: value changed from 17 to 18 - TimeType: value changed from 16 to 17 - Uint16Type: value changed from 20 to 21 - Uint32Type: value changed from 19 to 20 - Uint64Type: value changed from 18 to 19 - Uint8Type: value changed from 21 to 22 - UintptrType: value changed from 22 to 23 ``` [apidiff]: https://github.com/golang/exp/blob/master/apidiff/README.md Again, although maintianing these values is not part of the Zap contract, in the interest of erring on the side of safety, I'm moving the new FieldType (added in #912) to the bottom to avoid changing the values of the other items. --- zapcore/field.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/zapcore/field.go b/zapcore/field.go index 29daaace9..95bdb0a12 100644 --- a/zapcore/field.go +++ b/zapcore/field.go @@ -39,9 +39,6 @@ const ( ArrayMarshalerType // ObjectMarshalerType indicates that the field carries an ObjectMarshaler. ObjectMarshalerType - // InlineMarshalerType indicates that the field carries an ObjectMarshaler - // that should be inlined. - InlineMarshalerType // BinaryType indicates that the field carries an opaque binary blob. BinaryType // BoolType indicates that the field carries a bool. @@ -95,6 +92,10 @@ const ( ErrorType // SkipType indicates that the field is a no-op. SkipType + + // InlineMarshalerType indicates that the field carries an ObjectMarshaler + // that should be inlined. + InlineMarshalerType ) // A Field is a marshaling operation used to add a key-value pair to a logger's From 75ac0de3010fb584786c0fcd26d7f67244c41b41 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Tue, 25 May 2021 13:30:12 -0700 Subject: [PATCH 25/25] Prepare release v1.17.0 This prepares the v1.17.0 release of Zap. --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa817e6a1..3b99bf0ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 1.17.0 (25 May 2021) + +Bugfixes: +* [#867][]: Encode `` for nil `error` instead of a panic. +* [#931][], [#936][]: Update minimum version constraints to address + vulnerabilities in dependencies. + +Enhancements: +* [#865][]: Improve alignment of fields of the Logger struct, reducing its + size from 96 to 80 bytes. +* [#881][]: Support `grpclog.LoggerV2` in zapgrpc. +* [#903][]: Support URL-encoded POST requests to the AtomicLevel HTTP handler + with the `application/x-www-form-urlencoded` content type. +* [#912][]: Support multi-field encoding with `zap.Inline`. +* [#913][]: Speed up SugaredLogger for calls with a single string. +* [#928][]: Add support for filtering by field name to `zaptest/observer`. + +Thanks to @ash2k, @FMLS, @jimmystewpot, @Oncilla, @tsoslow, @tylitianrui, @withshubh, and @wziww for their contributions to this release. + ## 1.16.0 (1 Sep 2020) Bugfixes: @@ -430,3 +449,12 @@ upgrade to the upcoming stable release. [#854]: https://github.com/uber-go/zap/pull/854 [#861]: https://github.com/uber-go/zap/pull/861 [#862]: https://github.com/uber-go/zap/pull/862 +[#865]: https://github.com/uber-go/zap/pull/865 +[#867]: https://github.com/uber-go/zap/pull/867 +[#881]: https://github.com/uber-go/zap/pull/881 +[#903]: https://github.com/uber-go/zap/pull/903 +[#912]: https://github.com/uber-go/zap/pull/912 +[#913]: https://github.com/uber-go/zap/pull/913 +[#928]: https://github.com/uber-go/zap/pull/928 +[#931]: https://github.com/uber-go/zap/pull/931 +[#936]: https://github.com/uber-go/zap/pull/936