Codebase list golang-github-go-kit-kit / 72d4c4d
log: Add level.NewInjector and export Key and [Level]Value functions. Chris Hines 7 years ago
2 changed file(s) with 99 addition(s) and 31 deletion(s). Raw diff Collapse all Expand all
11
22 import "github.com/go-kit/kit/log"
33
4 // Error returns a logger that includes an error level keyval.
4 // Error returns a logger that includes a Key/ErrorValue pair.
55 func Error(logger log.Logger) log.Logger {
6 return log.NewContext(logger).WithPrefix(levelKey, errorLevelValue)
6 return log.NewContext(logger).WithPrefix(key, errorValue)
77 }
88
9 // Warn returns a logger that includes a warn level keyval.
9 // Warn returns a logger that includes a Key/WarnValue pair.
1010 func Warn(logger log.Logger) log.Logger {
11 return log.NewContext(logger).WithPrefix(levelKey, warnLevelValue)
11 return log.NewContext(logger).WithPrefix(key, warnValue)
1212 }
1313
14 // Info returns a logger that includes an info level keyval.
14 // Info returns a logger that includes a Key/InfoValue pair.
1515 func Info(logger log.Logger) log.Logger {
16 return log.NewContext(logger).WithPrefix(levelKey, infoLevelValue)
16 return log.NewContext(logger).WithPrefix(key, infoValue)
1717 }
1818
19 // Debug returns a logger that includes a debug level keyval.
19 // Debug returns a logger that includes a Key/DebugValue pair.
2020 func Debug(logger log.Logger) log.Logger {
21 return log.NewContext(logger).WithPrefix(levelKey, debugLevelValue)
21 return log.NewContext(logger).WithPrefix(key, debugValue)
2222 }
2323
2424 // NewFilter wraps next and implements level filtering. See the commentary on
122122 return func(l *logger) { l.errNoLevel = err }
123123 }
124124
125 func NewInjector(next log.Logger, level Value) log.Logger {
126 return &injector{
127 next: next,
128 level: level,
129 }
130 }
131
132 type injector struct {
133 next log.Logger
134 level interface{}
135 }
136
137 func (l *injector) Log(keyvals ...interface{}) error {
138 for i := 1; i < len(keyvals); i += 2 {
139 if _, ok := keyvals[i].(*levelValue); ok {
140 return l.next.Log(keyvals...)
141 }
142 }
143 kvs := make([]interface{}, len(keyvals)+2)
144 kvs[0], kvs[1] = key, l.level
145 copy(kvs[2:], keyvals)
146 return l.next.Log(kvs...)
147 }
148
149 type Value interface {
150 String() string
151 levelVal()
152 }
153
154 func Key() interface{} { return key }
155 func ErrorValue() Value { return errorValue }
156 func WarnValue() Value { return warnValue }
157 func InfoValue() Value { return infoValue }
158 func DebugValue() Value { return debugValue }
159
125160 var (
126 levelKey interface{} = "level"
127 errorLevelValue = &levelValue{level: levelError, name: "error"}
128 warnLevelValue = &levelValue{level: levelWarn, name: "warn"}
129 infoLevelValue = &levelValue{level: levelInfo, name: "info"}
130 debugLevelValue = &levelValue{level: levelDebug, name: "debug"}
161 key interface{} = "level"
162 errorValue = &levelValue{level: levelError, name: "error"}
163 warnValue = &levelValue{level: levelWarn, name: "warn"}
164 infoValue = &levelValue{level: levelInfo, name: "info"}
165 debugValue = &levelValue{level: levelDebug, name: "debug"}
131166 )
132167
133168 type level byte
144179 level
145180 }
146181
147 func (v *levelValue) String() string {
148 return v.name
149 }
182 func (v *levelValue) String() string { return v.name }
183 func (v *levelValue) levelVal() {}
1111 )
1212
1313 func TestVariousLevels(t *testing.T) {
14 for _, testcase := range []struct {
14 testCases := []struct {
15 name string
1516 allowed level.Option
1617 want string
1718 }{
1819 {
20 "AllowAll",
1921 level.AllowAll(),
2022 strings.Join([]string{
2123 `{"level":"debug","this is":"debug log"}`,
2527 }, "\n"),
2628 },
2729 {
30 "AllowDebug",
2831 level.AllowDebug(),
2932 strings.Join([]string{
3033 `{"level":"debug","this is":"debug log"}`,
3437 }, "\n"),
3538 },
3639 {
40 "AllowDebug",
3741 level.AllowInfo(),
3842 strings.Join([]string{
3943 `{"level":"info","this is":"info log"}`,
4246 }, "\n"),
4347 },
4448 {
49 "AllowWarn",
4550 level.AllowWarn(),
4651 strings.Join([]string{
4752 `{"level":"warn","this is":"warn log"}`,
4954 }, "\n"),
5055 },
5156 {
57 "AllowError",
5258 level.AllowError(),
5359 strings.Join([]string{
5460 `{"level":"error","this is":"error log"}`,
5561 }, "\n"),
5662 },
5763 {
64 "AllowNone",
5865 level.AllowNone(),
5966 ``,
6067 },
61 } {
62 var buf bytes.Buffer
63 logger := level.NewFilter(log.NewJSONLogger(&buf), testcase.allowed)
64
65 level.Debug(logger).Log("this is", "debug log")
66 level.Info(logger).Log("this is", "info log")
67 level.Warn(logger).Log("this is", "warn log")
68 level.Error(logger).Log("this is", "error log")
69
70 if want, have := testcase.want, strings.TrimSpace(buf.String()); want != have {
71 t.Errorf("given Allowed=%v: want\n%s\nhave\n%s", testcase.allowed, want, have)
72 }
68 }
69
70 for _, tc := range testCases {
71 t.Run(tc.name, func(t *testing.T) {
72 var buf bytes.Buffer
73 logger := level.NewFilter(log.NewJSONLogger(&buf), tc.allowed)
74
75 level.Debug(logger).Log("this is", "debug log")
76 level.Info(logger).Log("this is", "info log")
77 level.Warn(logger).Log("this is", "warn log")
78 level.Error(logger).Log("this is", "error log")
79
80 if want, have := tc.want, strings.TrimSpace(buf.String()); want != have {
81 t.Errorf("\nwant:\n%s\nhave:\n%s", want, have)
82 }
83 })
7384 }
7485 }
7586
135146 logger = log.NewContext(logger).With("caller", log.DefaultCaller)
136147
137148 level.Info(logger).Log("foo", "bar")
138 if want, have := `level=info caller=level_test.go:138 foo=bar`, strings.TrimSpace(buf.String()); want != have {
149 if want, have := `level=info caller=level_test.go:149 foo=bar`, strings.TrimSpace(buf.String()); want != have {
139150 t.Errorf("\nwant '%s'\nhave '%s'", want, have)
140151 }
141152 }
151162 logger = level.NewFilter(logger, level.AllowAll())
152163
153164 level.Info(logger).Log("foo", "bar")
154 if want, have := `caller=level_test.go:154 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have {
165 if want, have := `caller=level_test.go:165 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have {
155166 t.Errorf("\nwant '%s'\nhave '%s'", want, have)
156167 }
157168 }
186197 })
187198 }
188199 }
200
201 func TestInjector(t *testing.T) {
202 var (
203 output []interface{}
204 logger log.Logger
205 )
206
207 logger = log.LoggerFunc(func(keyvals ...interface{}) error {
208 output = keyvals
209 return nil
210 })
211 logger = level.NewInjector(logger, level.InfoValue())
212
213 logger.Log("foo", "bar")
214 if got, want := len(output), 4; got != want {
215 t.Errorf("missing level not injected: got len==%d, want len==%d", got, want)
216 }
217
218 level.Error(logger).Log("foo", "bar")
219 if got, want := len(output), 4; got != want {
220 t.Errorf("leveled record modified: got len==%d, want len==%d", got, want)
221 }
222 }