1package level
2
3import "github.com/go-kit/kit/log"
4
5// Error returns a logger that includes a Key/ErrorValue pair.
6func Error(logger log.Logger) log.Logger {
7	return log.WithPrefix(logger, Key(), ErrorValue())
8}
9
10// Warn returns a logger that includes a Key/WarnValue pair.
11func Warn(logger log.Logger) log.Logger {
12	return log.WithPrefix(logger, Key(), WarnValue())
13}
14
15// Info returns a logger that includes a Key/InfoValue pair.
16func Info(logger log.Logger) log.Logger {
17	return log.WithPrefix(logger, Key(), InfoValue())
18}
19
20// Debug returns a logger that includes a Key/DebugValue pair.
21func Debug(logger log.Logger) log.Logger {
22	return log.WithPrefix(logger, Key(), DebugValue())
23}
24
25// NewFilter wraps next and implements level filtering. See the commentary on
26// the Option functions for a detailed description of how to configure levels.
27// If no options are provided, all leveled log events created with Debug,
28// Info, Warn or Error helper methods are squelched and non-leveled log
29// events are passed to next unmodified.
30func NewFilter(next log.Logger, options ...Option) log.Logger {
31	l := &logger{
32		next: next,
33	}
34	for _, option := range options {
35		option(l)
36	}
37	return l
38}
39
40type logger struct {
41	next           log.Logger
42	allowed        level
43	squelchNoLevel bool
44	errNotAllowed  error
45	errNoLevel     error
46}
47
48func (l *logger) Log(keyvals ...interface{}) error {
49	var hasLevel, levelAllowed bool
50	for i := 1; i < len(keyvals); i += 2 {
51		if v, ok := keyvals[i].(*levelValue); ok {
52			hasLevel = true
53			levelAllowed = l.allowed&v.level != 0
54			break
55		}
56	}
57	if !hasLevel && l.squelchNoLevel {
58		return l.errNoLevel
59	}
60	if hasLevel && !levelAllowed {
61		return l.errNotAllowed
62	}
63	return l.next.Log(keyvals...)
64}
65
66// Option sets a parameter for the leveled logger.
67type Option func(*logger)
68
69// AllowAll is an alias for AllowDebug.
70func AllowAll() Option {
71	return AllowDebug()
72}
73
74// AllowDebug allows error, warn, info and debug level log events to pass.
75func AllowDebug() Option {
76	return allowed(levelError | levelWarn | levelInfo | levelDebug)
77}
78
79// AllowInfo allows error, warn and info level log events to pass.
80func AllowInfo() Option {
81	return allowed(levelError | levelWarn | levelInfo)
82}
83
84// AllowWarn allows error and warn level log events to pass.
85func AllowWarn() Option {
86	return allowed(levelError | levelWarn)
87}
88
89// AllowError allows only error level log events to pass.
90func AllowError() Option {
91	return allowed(levelError)
92}
93
94// AllowNone allows no leveled log events to pass.
95func AllowNone() Option {
96	return allowed(0)
97}
98
99func allowed(allowed level) Option {
100	return func(l *logger) { l.allowed = allowed }
101}
102
103// ErrNotAllowed sets the error to return from Log when it squelches a log
104// event disallowed by the configured Allow[Level] option. By default,
105// ErrNotAllowed is nil; in this case the log event is squelched with no
106// error.
107func ErrNotAllowed(err error) Option {
108	return func(l *logger) { l.errNotAllowed = err }
109}
110
111// SquelchNoLevel instructs Log to squelch log events with no level, so that
112// they don't proceed through to the wrapped logger. If SquelchNoLevel is set
113// to true and a log event is squelched in this way, the error value
114// configured with ErrNoLevel is returned to the caller.
115func SquelchNoLevel(squelch bool) Option {
116	return func(l *logger) { l.squelchNoLevel = squelch }
117}
118
119// ErrNoLevel sets the error to return from Log when it squelches a log event
120// with no level. By default, ErrNoLevel is nil; in this case the log event is
121// squelched with no error.
122func ErrNoLevel(err error) Option {
123	return func(l *logger) { l.errNoLevel = err }
124}
125
126// NewInjector wraps next and returns a logger that adds a Key/level pair to
127// the beginning of log events that don't already contain a level. In effect,
128// this gives a default level to logs without a level.
129func NewInjector(next log.Logger, level Value) log.Logger {
130	return &injector{
131		next:  next,
132		level: level,
133	}
134}
135
136type injector struct {
137	next  log.Logger
138	level interface{}
139}
140
141func (l *injector) Log(keyvals ...interface{}) error {
142	for i := 1; i < len(keyvals); i += 2 {
143		if _, ok := keyvals[i].(*levelValue); ok {
144			return l.next.Log(keyvals...)
145		}
146	}
147	kvs := make([]interface{}, len(keyvals)+2)
148	kvs[0], kvs[1] = key, l.level
149	copy(kvs[2:], keyvals)
150	return l.next.Log(kvs...)
151}
152
153// Value is the interface that each of the canonical level values implement.
154// It contains unexported methods that prevent types from other packages from
155// implementing it and guaranteeing that NewFilter can distinguish the levels
156// defined in this package from all other values.
157type Value interface {
158	String() string
159	levelVal()
160}
161
162// Key returns the unique key added to log events by the loggers in this
163// package.
164func Key() interface{} { return key }
165
166// ErrorValue returns the unique value added to log events by Error.
167func ErrorValue() Value { return errorValue }
168
169// WarnValue returns the unique value added to log events by Warn.
170func WarnValue() Value { return warnValue }
171
172// InfoValue returns the unique value added to log events by Info.
173func InfoValue() Value { return infoValue }
174
175// DebugValue returns the unique value added to log events by Warn.
176func DebugValue() Value { return debugValue }
177
178var (
179	// key is of type interface{} so that it allocates once during package
180	// initialization and avoids allocating every time the value is added to a
181	// []interface{} later.
182	key interface{} = "level"
183
184	errorValue = &levelValue{level: levelError, name: "error"}
185	warnValue  = &levelValue{level: levelWarn, name: "warn"}
186	infoValue  = &levelValue{level: levelInfo, name: "info"}
187	debugValue = &levelValue{level: levelDebug, name: "debug"}
188)
189
190type level byte
191
192const (
193	levelDebug level = 1 << iota
194	levelInfo
195	levelWarn
196	levelError
197)
198
199type levelValue struct {
200	name string
201	level
202}
203
204func (v *levelValue) String() string { return v.name }
205func (v *levelValue) levelVal()      {}
206