Use variadic function to pass parameters instead of Config struct
Using function to pass optional params makes the API more consistent
with the rest of go-kit packages.
For #427
Victor Vrantchan
6 years ago
12 | 12 | } |
13 | 13 | |
14 | 14 | func BenchmarkNopDisallowedLevel(b *testing.B) { |
15 | benchmarkRunner(b, level.New(log.NewNopLogger(), level.Config{ | |
16 | Allowed: level.AllowInfoAndAbove(), | |
17 | })) | |
15 | benchmarkRunner(b, level.New(log.NewNopLogger(), | |
16 | level.Allowed(level.AllowInfoAndAbove()))) | |
18 | 17 | } |
19 | 18 | |
20 | 19 | func BenchmarkNopAllowedLevel(b *testing.B) { |
21 | benchmarkRunner(b, level.New(log.NewNopLogger(), level.Config{ | |
22 | Allowed: level.AllowAll(), | |
23 | })) | |
20 | benchmarkRunner(b, level.New(log.NewNopLogger(), | |
21 | level.Allowed(level.AllowAll()))) | |
24 | 22 | } |
25 | 23 | |
26 | 24 | func BenchmarkJSONBaseline(b *testing.B) { |
28 | 26 | } |
29 | 27 | |
30 | 28 | func BenchmarkJSONDisallowedLevel(b *testing.B) { |
31 | benchmarkRunner(b, level.New(log.NewJSONLogger(ioutil.Discard), level.Config{ | |
32 | Allowed: level.AllowInfoAndAbove(), | |
33 | })) | |
29 | benchmarkRunner(b, level.New(log.NewJSONLogger(ioutil.Discard), | |
30 | level.Allowed(level.AllowInfoAndAbove()))) | |
34 | 31 | } |
35 | 32 | |
36 | 33 | func BenchmarkJSONAllowedLevel(b *testing.B) { |
37 | benchmarkRunner(b, level.New(log.NewJSONLogger(ioutil.Discard), level.Config{ | |
38 | Allowed: level.AllowAll(), | |
39 | })) | |
34 | benchmarkRunner(b, level.New(log.NewJSONLogger(ioutil.Discard), | |
35 | level.Allowed(level.AllowAll()))) | |
40 | 36 | } |
41 | 37 | |
42 | 38 | func BenchmarkLogfmtBaseline(b *testing.B) { |
44 | 40 | } |
45 | 41 | |
46 | 42 | func BenchmarkLogfmtDisallowedLevel(b *testing.B) { |
47 | benchmarkRunner(b, level.New(log.NewLogfmtLogger(ioutil.Discard), level.Config{ | |
48 | Allowed: level.AllowInfoAndAbove(), | |
49 | })) | |
43 | benchmarkRunner(b, level.New(log.NewLogfmtLogger(ioutil.Discard), | |
44 | level.Allowed(level.AllowInfoAndAbove()))) | |
50 | 45 | } |
51 | 46 | |
52 | 47 | func BenchmarkLogfmtAllowedLevel(b *testing.B) { |
53 | benchmarkRunner(b, level.New(log.NewLogfmtLogger(ioutil.Discard), level.Config{ | |
54 | Allowed: level.AllowAll(), | |
55 | })) | |
48 | benchmarkRunner(b, level.New(log.NewLogfmtLogger(ioutil.Discard), | |
49 | level.Allowed(level.AllowAll()))) | |
56 | 50 | } |
57 | 51 | |
58 | 52 | func benchmarkRunner(b *testing.B, logger log.Logger) { |
5 | 5 | // |
6 | 6 | // var logger log.Logger |
7 | 7 | // logger = log.NewLogfmtLogger(os.Stderr) |
8 | // logger = level.New(logger, level.Config{Allowed: level.AllowInfoAndAbove}) // <-- | |
8 | // logger = level.New(logger, level.Allowed(level.AllowInfoAndAbove())) // <-- | |
9 | 9 | // logger = log.NewContext(logger).With("ts", log.DefaultTimestampUTC) |
10 | 10 | // |
11 | 11 | // Then, at the callsites, use one of the level.Debug, Info, Warn, or Error |
19 | 19 | // |
20 | 20 | // The leveled logger allows precise control over what should happen if a log |
21 | 21 | // event is emitted without a level key, or if a squelched level is used. Check |
22 | // the Config struct for details. And, you can easily use non-default level | |
22 | // the Option functions for details. And, you can easily use non-default level | |
23 | 23 | // values: create new string constants for whatever you want to change, pass |
24 | // them explicitly to the Config struct, and write your own level.Foo-style | |
24 | // them explicitly to the Allowed Option function, and write your own level.Foo-style | |
25 | 25 | // helper methods. |
26 | 26 | package level |
17 | 17 | } |
18 | 18 | |
19 | 19 | // AllowDebugAndAbove allows all of the four default log levels. |
20 | // Its return value may be provided as the Allowed parameter in the Config. | |
20 | // Its return value may be provided with the Allowed Option. | |
21 | 21 | func AllowDebugAndAbove() []string { |
22 | 22 | return []string{errorLevelValue, warnLevelValue, infoLevelValue, debugLevelValue} |
23 | 23 | } |
24 | 24 | |
25 | 25 | // AllowInfoAndAbove allows the default info, warn, and error log levels. |
26 | // Its return value may be provided as the Allowed parameter in the Config. | |
26 | // Its return value may be provided with the Allowed Option. | |
27 | 27 | func AllowInfoAndAbove() []string { |
28 | 28 | return []string{errorLevelValue, warnLevelValue, infoLevelValue} |
29 | 29 | } |
30 | 30 | |
31 | 31 | // AllowWarnAndAbove allows the default warn and error log levels. |
32 | // Its return value may be provided as the Allowed parameter in the Config. | |
32 | // Its return value may be provided with the Allowed Option. | |
33 | 33 | func AllowWarnAndAbove() []string { |
34 | 34 | return []string{errorLevelValue, warnLevelValue} |
35 | 35 | } |
36 | 36 | |
37 | 37 | // AllowErrorOnly allows only the default error log level. |
38 | // Its return value may be provided as the Allowed parameter in the Config. | |
38 | // Its return value may be provided with the Allowed Option. | |
39 | 39 | func AllowErrorOnly() []string { |
40 | 40 | return []string{errorLevelValue} |
41 | 41 | } |
42 | 42 | |
43 | 43 | // AllowNone allows none of the default log levels. |
44 | // Its return value may be provided as the Allowed parameter in the Config. | |
44 | // Its return value may be provided with the Allowed Option. | |
45 | 45 | func AllowNone() []string { |
46 | 46 | return []string{} |
47 | 47 | } |
66 | 66 | return log.NewContext(logger).WithPrefix(levelKey, debugLevelValue) |
67 | 67 | } |
68 | 68 | |
69 | // Config parameterizes the leveled logger. | |
70 | type Config struct { | |
71 | // Allowed enumerates the accepted log levels. If a log event is encountered | |
72 | // with a level key set to a value that isn't explicitly allowed, the event | |
73 | // will be squelched, and ErrNotAllowed returned. | |
74 | Allowed []string | |
75 | ||
76 | // ErrNotAllowed is returned to the caller when Log is invoked with a level | |
77 | // key that hasn't been explicitly allowed. By default, ErrNotAllowed is | |
78 | // nil; in this case, the log event is squelched with no error. | |
79 | ErrNotAllowed error | |
80 | ||
81 | // SquelchNoLevel will squelch log events with no level key, so that they | |
82 | // don't proceed through to the wrapped logger. If SquelchNoLevel is set to | |
83 | // true and a log event is squelched in this way, ErrNoLevel is returned to | |
84 | // the caller. | |
85 | SquelchNoLevel bool | |
86 | ||
87 | // ErrNoLevel is returned to the caller when SquelchNoLevel is true, and Log | |
88 | // is invoked without a level key. By default, ErrNoLevel is nil; in this | |
89 | // case, the log event is squelched with no error. | |
90 | ErrNoLevel error | |
69 | // New wraps the logger and implements level checking. See the commentary on the | |
70 | // Option functions for a detailed description of how to configure levels. | |
71 | func New(next log.Logger, options ...Option) log.Logger { | |
72 | l := logger{ | |
73 | next: next, | |
74 | } | |
75 | for _, option := range options { | |
76 | option(&l) | |
77 | } | |
78 | return &l | |
91 | 79 | } |
92 | 80 | |
93 | // New wraps the logger and implements level checking. See the commentary on the | |
94 | // Config object for a detailed description of how to configure levels. | |
95 | func New(next log.Logger, config Config) log.Logger { | |
96 | return &logger{ | |
97 | next: next, | |
98 | allowed: makeSet(config.Allowed), | |
99 | errNotAllowed: config.ErrNotAllowed, | |
100 | squelchNoLevel: config.SquelchNoLevel, | |
101 | errNoLevel: config.ErrNoLevel, | |
102 | } | |
81 | // Allowed enumerates the accepted log levels. If a log event is encountered | |
82 | // with a level key set to a value that isn't explicitly allowed, the event | |
83 | // will be squelched, and ErrNotAllowed returned. | |
84 | func Allowed(allowed []string) Option { | |
85 | return func(l *logger) { l.allowed = makeSet(allowed) } | |
103 | 86 | } |
87 | ||
88 | // ErrNoLevel is returned to the caller when SquelchNoLevel is true, and Log | |
89 | // is invoked without a level key. By default, ErrNoLevel is nil; in this | |
90 | // case, the log event is squelched with no error. | |
91 | func ErrNotAllowed(err error) Option { | |
92 | return func(l *logger) { l.errNotAllowed = err } | |
93 | } | |
94 | ||
95 | // SquelchNoLevel will squelch log events with no level key, so that they | |
96 | // don't proceed through to the wrapped logger. If SquelchNoLevel is set to | |
97 | // true and a log event is squelched in this way, ErrNoLevel is returned to | |
98 | // the caller. | |
99 | func SquelchNoLevel(squelch bool) Option { | |
100 | return func(l *logger) { l.squelchNoLevel = squelch } | |
101 | } | |
102 | ||
103 | // ErrNoLevel is returned to the caller when SquelchNoLevel is true, and Log | |
104 | // is invoked without a level key. By default, ErrNoLevel is nil; in this | |
105 | // case, the log event is squelched with no error. | |
106 | func ErrNoLevel(err error) Option { | |
107 | return func(l *logger) { l.errNoLevel = err } | |
108 | } | |
109 | ||
110 | // Option sets a parameter for the leveled logger. | |
111 | type Option func(*logger) | |
104 | 112 | |
105 | 113 | type logger struct { |
106 | 114 | next log.Logger |
59 | 59 | }, |
60 | 60 | } { |
61 | 61 | var buf bytes.Buffer |
62 | logger := level.New(log.NewJSONLogger(&buf), level.Config{Allowed: testcase.allowed}) | |
62 | logger := level.New(log.NewJSONLogger(&buf), level.Allowed(testcase.allowed)) | |
63 | 63 | |
64 | 64 | level.Debug(logger).Log("this is", "debug log") |
65 | 65 | level.Info(logger).Log("this is", "info log") |
74 | 74 | |
75 | 75 | func TestErrNotAllowed(t *testing.T) { |
76 | 76 | myError := errors.New("squelched!") |
77 | logger := level.New(log.NewNopLogger(), level.Config{ | |
78 | Allowed: level.AllowWarnAndAbove(), | |
79 | ErrNotAllowed: myError, | |
80 | }) | |
77 | opts := []level.Option{ | |
78 | level.Allowed(level.AllowWarnAndAbove()), | |
79 | level.ErrNotAllowed(myError), | |
80 | } | |
81 | logger := level.New(log.NewNopLogger(), opts...) | |
81 | 82 | |
82 | 83 | if want, have := myError, level.Info(logger).Log("foo", "bar"); want != have { |
83 | 84 | t.Errorf("want %#+v, have %#+v", want, have) |
92 | 93 | myError := errors.New("no level specified") |
93 | 94 | |
94 | 95 | var buf bytes.Buffer |
95 | logger := level.New(log.NewJSONLogger(&buf), level.Config{ | |
96 | SquelchNoLevel: true, | |
97 | ErrNoLevel: myError, | |
98 | }) | |
96 | opts := []level.Option{ | |
97 | level.SquelchNoLevel(true), | |
98 | level.ErrNoLevel(myError), | |
99 | } | |
100 | logger := level.New(log.NewJSONLogger(&buf), opts...) | |
99 | 101 | |
100 | 102 | if want, have := myError, logger.Log("foo", "bar"); want != have { |
101 | 103 | t.Errorf("want %v, have %v", want, have) |
107 | 109 | |
108 | 110 | func TestAllowNoLevel(t *testing.T) { |
109 | 111 | var buf bytes.Buffer |
110 | logger := level.New(log.NewJSONLogger(&buf), level.Config{ | |
111 | SquelchNoLevel: false, | |
112 | ErrNoLevel: errors.New("I should never be returned!"), | |
113 | }) | |
112 | opts := []level.Option{ | |
113 | level.SquelchNoLevel(false), | |
114 | level.ErrNoLevel(errors.New("I should never be returned!")), | |
115 | } | |
116 | logger := level.New(log.NewJSONLogger(&buf), opts...) | |
114 | 117 | |
115 | 118 | if want, have := error(nil), logger.Log("foo", "bar"); want != have { |
116 | 119 | t.Errorf("want %v, have %v", want, have) |
127 | 130 | // log.DefaultCaller as per normal. |
128 | 131 | var logger log.Logger |
129 | 132 | logger = log.NewLogfmtLogger(&buf) |
130 | logger = level.New(logger, level.Config{Allowed: level.AllowAll()}) | |
133 | logger = level.New(logger, level.Allowed(level.AllowAll())) | |
131 | 134 | logger = log.NewContext(logger).With("caller", log.DefaultCaller) |
132 | 135 | |
133 | 136 | level.Info(logger).Log("foo", "bar") |
134 | if want, have := `level=info caller=level_test.go:134 foo=bar`, strings.TrimSpace(buf.String()); want != have { | |
137 | if want, have := `level=info caller=level_test.go:137 foo=bar`, strings.TrimSpace(buf.String()); want != have { | |
135 | 138 | t.Errorf("want %q, have %q", want, have) |
136 | 139 | } |
137 | 140 | } |
144 | 147 | var logger log.Logger |
145 | 148 | logger = log.NewLogfmtLogger(&buf) |
146 | 149 | logger = log.NewContext(logger).With("caller", log.Caller(5)) |
147 | logger = level.New(logger, level.Config{Allowed: level.AllowAll()}) | |
150 | logger = level.New(logger, level.Allowed(level.AllowAll())) | |
148 | 151 | |
149 | 152 | level.Info(logger).Log("foo", "bar") |
150 | if want, have := `caller=level_test.go:150 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have { | |
153 | if want, have := `caller=level_test.go:153 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have { | |
151 | 154 | t.Errorf("want %q, have %q", want, have) |
152 | 155 | } |
153 | 156 | } |