diff --git a/zap_development_handler.go b/zap_development_handler.go index 4a38961..8d51d96 100644 --- a/zap_development_handler.go +++ b/zap_development_handler.go @@ -16,6 +16,12 @@ import ( // scanner loop will never capture them var zapDevLogsPrefixRe = regexp.MustCompile("^(?P\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}-\\d{4})\\s+(?P\\w{4,5})\\s+(?P\\S+)\\s+(?P[^{]+?)\\s+(?P{.+})$") +// Zap Development Logs when run in Docker-Compose are nearly identical to before +// Fields are tab separated instead of whitespace +// Timestamp is now in ... +// Everything else remains the same +var zapDevDCLogsPrefixRe = regexp.MustCompile("^(?P\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z)\t(?P\\w{4,5})\t(?P\\S+)\t(?P[^{]+?)\t(?P{.+})$") + // This is not obviously an RFC-compliant format and is not a constant in the // time package which is worrisome but this pattern does work. const someRFC = "2006-01-02T15:04:05.000-0700" diff --git a/zap_development_handler_test.go b/zap_development_handler_test.go index 307fe92..a654cb8 100644 --- a/zap_development_handler_test.go +++ b/zap_development_handler_test.go @@ -36,7 +36,7 @@ func Test_zapDevLogsPrefixRe(t *testing.T) { wantJSON: `{"rand_index": 1}`, }, { - name: "error message with caller info", + name: "error message", logLine: logLinesByLevel["ERROR"], @@ -47,7 +47,7 @@ func Test_zapDevLogsPrefixRe(t *testing.T) { wantJSON: `{"rand_index": 3}`, }, { - name: "fatal message with caller info and exit status", + name: "fatal message", logLine: logLinesByLevel["FATAL"], wantTS: "2021-02-05T15:45:04.425-0700", wantLevel: "FATAL", @@ -68,7 +68,7 @@ func Test_zapDevLogsPrefixRe(t *testing.T) { }, { - name: "warning message with caller info", + name: "warning message", logLine: logLinesByLevel["WARN"], @@ -117,6 +117,118 @@ func Test_zapDevLogsPrefixRe(t *testing.T) { } } +var dcLogLinesByLevel = map[string][]byte{ + "DEBUG": []byte("2021-02-06T22:55:22.004Z\tDEBUG\tzapper/zapper.go:17\tsome message 1\t{\"rand_index\": 1}"), + "ERROR": []byte("2021-02-06T22:55:22.008Z\tERROR\tzapper/zapper.go:17\tsome message 2\t{\"rand_index\": 2}"), + "FATAL": []byte("2021-02-06T22:55:22.009Z\tFATAL\tzapper/zapper.go:17\tsome message 5\t{\"rand_index\": 1}"), + "INFO": []byte("2021-02-06T22:55:22.009Z\tINFO\tzapper/zapper.go:17\tsome message 3\t{\"rand_index\": 2}"), + "WARN": []byte("2021-02-06T22:55:22.009Z\tWARN\tzapper/zapper.go:17\tsome message 4\t{\"rand_index\": 4}"), +} + +func Test_zapDCDevLogsPrefixRe(t *testing.T) { + tests := []struct { + name string + logLine []byte + wantTS string + wantLevel string + wantLocation string + wantMessage string + wantJSON string + }{ + { + name: "debug message", + + logLine: dcLogLinesByLevel["DEBUG"], + + wantTS: "2021-02-06T22:55:22.004Z", + wantLevel: "DEBUG", + wantLocation: "zapper/zapper.go:17", + wantMessage: "some message 1", + wantJSON: `{"rand_index": 1}`, + }, + { + name: "error message", + + logLine: dcLogLinesByLevel["ERROR"], + + wantTS: "2021-02-06T22:55:22.008Z", + wantLevel: "ERROR", + wantLocation: "zapper/zapper.go:17", + wantMessage: "some message 2", + wantJSON: `{"rand_index": 2}`, + }, + { + name: "fatal message", + + logLine: dcLogLinesByLevel["FATAL"], + + wantTS: "2021-02-06T22:55:22.009Z", + wantLevel: "FATAL", + wantLocation: "zapper/zapper.go:17", + wantMessage: "some message 5", + wantJSON: `{"rand_index": 1}`, + }, + { + name: "info message", + + logLine: dcLogLinesByLevel["INFO"], + + wantTS: "2021-02-06T22:55:22.009Z", + wantLevel: "INFO", + wantLocation: "zapper/zapper.go:17", + wantMessage: "some message 3", + wantJSON: `{"rand_index": 2}`, + }, + { + name: "warn message", + + logLine: dcLogLinesByLevel["WARN"], + + wantTS: "2021-02-06T22:55:22.009Z", + wantLevel: "WARN", + wantLocation: "zapper/zapper.go:17", + wantMessage: "some message 4", + wantJSON: `{"rand_index": 4}`, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + matches := zapDevDCLogsPrefixRe.FindSubmatch(test.logLine) + if matches != nil { + result := make(map[string]string) + for i, name := range zapDevLogsPrefixRe.SubexpNames() { + if i != 0 && name != "" { + result[name] = string(matches[i]) + } + } + + if result["timestamp"] != test.wantTS { + t.Errorf("want %q, got %q, want != got", test.wantTS, result["timestamp"]) + } + + if result["level"] != test.wantLevel { + t.Errorf("want %q, got %q, want != got", test.wantLevel, result["level"]) + } + + if result["location"] != test.wantLocation { + t.Errorf("want %q, got %q, want != got", test.wantLocation, result["location"]) + } + + if result["message"] != test.wantMessage { + t.Errorf("want %q, got %q, want != got", test.wantMessage, result["message"]) + } + + if result["jsonbody"] != test.wantJSON { + t.Errorf("want %q, got %q, want != got", test.wantJSON, result["jsonbody"]) + } + } else { + t.Errorf("regular expression did not match log line") + } + }) + } +} + func Test_tryZapDevPrefix(t *testing.T) { tests := []struct { name string