Add a gRPC compatibility wrapper (#402)
Add a small `zapgrpc` package for gRPC compatibility.
Peter Edge authored 7 years ago
Akshay Shah committed 7 years ago
2 | 2 | BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem |
3 | 3 | PKGS ?= $(shell glide novendor) |
4 | 4 | # Many Go tools take file globs or directories as arguments instead of packages. |
5 | PKG_FILES ?= *.go zapcore benchmarks buffer zaptest zaptest/observer internal/bufferpool internal/exit internal/multierror internal/color | |
5 | PKG_FILES ?= *.go zapcore benchmarks buffer zapgrpc zaptest zaptest/observer internal/bufferpool internal/exit internal/multierror internal/color | |
6 | 6 | |
7 | 7 | COVERALLS_IGNORE := internal/readme/readme.go |
8 | 8 |
0 | // Copyright (c) 2016 Uber Technologies, Inc. | |
1 | // | |
2 | // Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | // of this software and associated documentation files (the "Software"), to deal | |
4 | // in the Software without restriction, including without limitation the rights | |
5 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | // copies of the Software, and to permit persons to whom the Software is | |
7 | // furnished to do so, subject to the following conditions: | |
8 | // | |
9 | // The above copyright notice and this permission notice shall be included in | |
10 | // all copies or substantial portions of the Software. | |
11 | // | |
12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | // THE SOFTWARE. | |
19 | ||
20 | // Package zapgrpc provides a logger that is compatible with grpclog. | |
21 | package zapgrpc // import "go.uber.org/zap/zapgrpc" | |
22 | ||
23 | import "go.uber.org/zap" | |
24 | ||
25 | // An Option overrides a Logger's default configuration. | |
26 | type Option interface { | |
27 | apply(*Logger) | |
28 | } | |
29 | ||
30 | type optionFunc func(*Logger) | |
31 | ||
32 | func (f optionFunc) apply(log *Logger) { | |
33 | f(log) | |
34 | } | |
35 | ||
36 | // WithDebug configures a Logger to print at zap's DebugLevel instead of | |
37 | // InfoLevel. | |
38 | func WithDebug() Option { | |
39 | return optionFunc(func(logger *Logger) { | |
40 | logger.print = (*zap.SugaredLogger).Debug | |
41 | logger.printf = (*zap.SugaredLogger).Debugf | |
42 | }) | |
43 | } | |
44 | ||
45 | // NewLogger returns a new Logger. | |
46 | // | |
47 | // By default, Loggers print at zap's InfoLevel. | |
48 | func NewLogger(l *zap.Logger, options ...Option) *Logger { | |
49 | logger := &Logger{ | |
50 | log: l.Sugar(), | |
51 | fatal: (*zap.SugaredLogger).Fatal, | |
52 | fatalf: (*zap.SugaredLogger).Fatalf, | |
53 | print: (*zap.SugaredLogger).Info, | |
54 | printf: (*zap.SugaredLogger).Infof, | |
55 | } | |
56 | for _, option := range options { | |
57 | option.apply(logger) | |
58 | } | |
59 | return logger | |
60 | } | |
61 | ||
62 | // Logger adapts zap's Logger to be compatible with grpclog.Logger. | |
63 | type Logger struct { | |
64 | log *zap.SugaredLogger | |
65 | fatal func(*zap.SugaredLogger, ...interface{}) | |
66 | fatalf func(*zap.SugaredLogger, string, ...interface{}) | |
67 | print func(*zap.SugaredLogger, ...interface{}) | |
68 | printf func(*zap.SugaredLogger, string, ...interface{}) | |
69 | } | |
70 | ||
71 | // Fatal implements grpclog.Logger. | |
72 | func (l *Logger) Fatal(args ...interface{}) { | |
73 | l.fatal(l.log, args...) | |
74 | } | |
75 | ||
76 | // Fatalf implements grpclog.Logger. | |
77 | func (l *Logger) Fatalf(format string, args ...interface{}) { | |
78 | l.fatalf(l.log, format, args...) | |
79 | } | |
80 | ||
81 | // Fatalln implements grpclog.Logger. | |
82 | func (l *Logger) Fatalln(args ...interface{}) { | |
83 | l.fatal(l.log, args...) | |
84 | } | |
85 | ||
86 | // Print implements grpclog.Logger. | |
87 | func (l *Logger) Print(args ...interface{}) { | |
88 | l.print(l.log, args...) | |
89 | } | |
90 | ||
91 | // Printf implements grpclog.Logger. | |
92 | func (l *Logger) Printf(format string, args ...interface{}) { | |
93 | l.printf(l.log, format, args...) | |
94 | } | |
95 | ||
96 | // Println implements grpclog.Logger. | |
97 | func (l *Logger) Println(args ...interface{}) { | |
98 | l.print(l.log, args...) | |
99 | } |
0 | // Copyright (c) 2016 Uber Technologies, Inc. | |
1 | // | |
2 | // Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | // of this software and associated documentation files (the "Software"), to deal | |
4 | // in the Software without restriction, including without limitation the rights | |
5 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | // copies of the Software, and to permit persons to whom the Software is | |
7 | // furnished to do so, subject to the following conditions: | |
8 | // | |
9 | // The above copyright notice and this permission notice shall be included in | |
10 | // all copies or substantial portions of the Software. | |
11 | // | |
12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | // THE SOFTWARE. | |
19 | ||
20 | package zapgrpc | |
21 | ||
22 | import ( | |
23 | "testing" | |
24 | ||
25 | "go.uber.org/zap" | |
26 | "go.uber.org/zap/zapcore" | |
27 | "go.uber.org/zap/zaptest/observer" | |
28 | ||
29 | "github.com/stretchr/testify/require" | |
30 | ) | |
31 | ||
32 | func TestLoggerInfoExpected(t *testing.T) { | |
33 | checkMessages(t, zapcore.DebugLevel, nil, zapcore.InfoLevel, []string{ | |
34 | "hello", | |
35 | "world", | |
36 | "foo", | |
37 | }, func(logger *Logger) { | |
38 | logger.Print("hello") | |
39 | logger.Printf("world") | |
40 | logger.Println("foo") | |
41 | }) | |
42 | } | |
43 | ||
44 | func TestLoggerDebugExpected(t *testing.T) { | |
45 | checkMessages(t, zapcore.DebugLevel, []Option{WithDebug()}, zapcore.DebugLevel, []string{ | |
46 | "hello", | |
47 | "world", | |
48 | "foo", | |
49 | }, func(logger *Logger) { | |
50 | logger.Print("hello") | |
51 | logger.Printf("world") | |
52 | logger.Println("foo") | |
53 | }) | |
54 | } | |
55 | ||
56 | func TestLoggerDebugSuppressed(t *testing.T) { | |
57 | checkMessages(t, zapcore.InfoLevel, []Option{WithDebug()}, zapcore.DebugLevel, nil, func(logger *Logger) { | |
58 | logger.Print("hello") | |
59 | logger.Printf("world") | |
60 | logger.Println("foo") | |
61 | }) | |
62 | } | |
63 | ||
64 | func TestLoggerFatalExpected(t *testing.T) { | |
65 | checkMessages(t, zapcore.DebugLevel, nil, zapcore.FatalLevel, []string{ | |
66 | "hello", | |
67 | "world", | |
68 | "foo", | |
69 | }, func(logger *Logger) { | |
70 | logger.Fatal("hello") | |
71 | logger.Fatalf("world") | |
72 | logger.Fatalln("foo") | |
73 | }) | |
74 | } | |
75 | ||
76 | func checkMessages( | |
77 | t testing.TB, | |
78 | enab zapcore.LevelEnabler, | |
79 | opts []Option, | |
80 | expectedLevel zapcore.Level, | |
81 | expectedMessages []string, | |
82 | f func(*Logger), | |
83 | ) { | |
84 | if expectedLevel == zapcore.FatalLevel { | |
85 | expectedLevel = zapcore.WarnLevel | |
86 | } | |
87 | withLogger(enab, opts, func(logger *Logger, observedLogs *observer.ObservedLogs) { | |
88 | f(logger) | |
89 | logEntries := observedLogs.All() | |
90 | require.Equal(t, len(expectedMessages), len(logEntries)) | |
91 | for i, logEntry := range logEntries { | |
92 | require.Equal(t, expectedLevel, logEntry.Level) | |
93 | require.Equal(t, expectedMessages[i], logEntry.Message) | |
94 | } | |
95 | }) | |
96 | } | |
97 | ||
98 | func withLogger( | |
99 | enab zapcore.LevelEnabler, | |
100 | opts []Option, | |
101 | f func(*Logger, *observer.ObservedLogs), | |
102 | ) { | |
103 | core, observedLogs := observer.New(enab) | |
104 | f(NewLogger(zap.New(core), append(opts, withWarn())...), observedLogs) | |
105 | } | |
106 | ||
107 | // withWarn redirects the fatal level to the warn level, which makes testing | |
108 | // easier. | |
109 | func withWarn() Option { | |
110 | return optionFunc(func(logger *Logger) { | |
111 | logger.fatal = (*zap.SugaredLogger).Warn | |
112 | logger.fatalf = (*zap.SugaredLogger).Warnf | |
113 | }) | |
114 | } |