Skip to content

Commit 6bbd770

Browse files
Merge pull request #28 from vimeo/min-log-levels
Minimum Log Levels
2 parents c88860b + 4384b86 commit 6bbd770

File tree

6 files changed

+144
-18
lines changed

6 files changed

+144
-18
lines changed

emitter/gkelog/emitter.go

+13-6
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,26 @@ var DefaultLogger = alog.New(alog.WithEmitter(Emitter()))
2222
type contextKey string
2323

2424
var (
25-
severityKey = contextKey("severity")
26-
requestKey = contextKey("request")
27-
statusKey = contextKey("status")
28-
latencyKey = contextKey("latency")
29-
traceKey = contextKey("trace")
30-
spanKey = contextKey("span")
25+
severityKey = contextKey("severity")
26+
minSeverityKey = contextKey("minSeverity")
27+
requestKey = contextKey("request")
28+
statusKey = contextKey("status")
29+
latencyKey = contextKey("latency")
30+
traceKey = contextKey("trace")
31+
spanKey = contextKey("span")
3132
)
3233

3334
// WithSeverity returns a copy of parent with the specified severity value.
3435
func WithSeverity(parent context.Context, severity string) context.Context {
3536
return context.WithValue(parent, severityKey, severity)
3637
}
3738

39+
// WithMinSeverity sets the minimum severity to log. Use one of the Severity*
40+
// constants.
41+
func WithMinSeverity(parent context.Context, severity string) context.Context {
42+
return context.WithValue(parent, minSeverityKey, severity)
43+
}
44+
3845
// WithRequest returns a copy of parent with the specified http.Request value.
3946
// It also calls WithRequestTrace to add trace information to the context.
4047
func WithRequest(parent context.Context, req *http.Request) context.Context {

emitter/gkelog/emitter_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,21 @@ func TestLogSeverity(t *testing.T) {
108108
}
109109
}
110110

111+
func TestMinLogSeverity(t *testing.T) {
112+
b := &bytes.Buffer{}
113+
ctx := WithMinSeverity(context.Background(), SeverityWarning)
114+
l := alog.New(alog.WithEmitter(Emitter(WithWriter(b))), zeroTimeOpt)
115+
116+
LogInfo(ctx, l, "NOT LOGGED") // because Info is lower than Warning
117+
LogError(ctx, l, "LOGGED")
118+
119+
want := `{"time":"0001-01-01T00:00:00Z", "severity":"ERROR", "message":"LOGGED"}` + "\n"
120+
got := b.String()
121+
if got != want {
122+
t.Errorf("got:\n%s\nwant:\n%s", got, want)
123+
}
124+
}
125+
111126
func TestRequest(t *testing.T) {
112127
b := &bytes.Buffer{}
113128
ctx := context.Background()

emitter/gkelog/severity.go

+21-2
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,32 @@ const (
2121
SeverityEmergency = "EMERGENCY" // One or more systems are unusable.
2222
)
2323

24+
// the priority of each severity level
25+
var severityPriority map[string]uint8 = map[string]uint8{
26+
SeverityDebug: 0,
27+
SeverityInfo: 1,
28+
SeverityNotice: 2,
29+
SeverityWarning: 3,
30+
SeverityError: 4,
31+
SeverityCritical: 5,
32+
SeverityAlert: 6,
33+
SeverityEmergency: 7,
34+
SeverityDefault: 8, // default will almost always log and should probably not be used
35+
}
36+
2437
// Separate private function so that LogSeverity and the other logs functions
2538
// will have the same stack frame depth and thus use the same calldepth value.
2639
// See https://golang.org/pkg/runtime/#Caller and
2740
// https://godoc.org/github.com/vimeo/alog#Logger.Output
2841
func logSeverity(ctx context.Context, logger *alog.Logger, s string, f string, v ...interface{}) {
29-
ctx = WithSeverity(ctx, s)
30-
logger.Output(ctx, 3, fmt.Sprintf(f, v...))
42+
minSeverity := uint8(0)
43+
if minSeverityVal := ctx.Value(minSeverityKey); minSeverityVal != nil {
44+
minSeverity = severityPriority[minSeverityVal.(string)]
45+
}
46+
if severityPriority[s] >= minSeverity {
47+
ctx = WithSeverity(ctx, s)
48+
logger.Output(ctx, 3, fmt.Sprintf(f, v...))
49+
}
3150
}
3251

3352
// LogSeverity writes a log entry using the specified severity

leveled/level_string.go

+27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

leveled/logger.go

+53-10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@ import (
77
"github.com/vimeo/alog/v3"
88
)
99

10+
// Level represents the severity of a log message.
11+
type Level uint8
12+
13+
const (
14+
Debug Level = iota // debug
15+
Info // info
16+
Warning // warning
17+
Error // error
18+
Critical // critical
19+
)
20+
21+
// LevelKey is the tag key associated with a level.
22+
const LevelKey = "level"
23+
1024
// Logger is an interface that implements logging functions for different levels of severity.
1125
type Logger interface {
1226
// Debug logs debugging or trace information.
@@ -25,8 +39,20 @@ type Logger interface {
2539
Critical(ctx context.Context, f string, v ...interface{})
2640
}
2741

42+
// FilteredLogger amends the Logger interface with a Log method that accepts the
43+
// level to log at.
44+
type FilteredLogger interface {
45+
Logger
46+
Log(ctx context.Context, level Level, f string, v ...interface{})
47+
SetMinLevel(level Level)
48+
}
49+
2850
type defaultLogger struct {
2951
*alog.Logger
52+
53+
// Indicates the minimum level to log at. If MinLevel is greater than the
54+
// level of a given log message, the log message will be suppressed.
55+
MinLevel Level
3056
}
3157

3258
// Default returns a Logger that wraps the provided `alog.Logger`.
@@ -39,32 +65,49 @@ func Default(logger *alog.Logger) Logger {
3965
}
4066
}
4167

68+
// Filtered returns a logger that allows for setting the minimum level.
69+
func Filtered(logger *alog.Logger) FilteredLogger {
70+
return &defaultLogger{
71+
Logger: logger,
72+
}
73+
}
74+
4275
// Debug implements Logger.Debug
4376
func (d *defaultLogger) Debug(ctx context.Context, f string, v ...interface{}) {
44-
ctx = alog.AddTags(ctx, "level", "debug")
45-
d.Logger.Output(ctx, 3, fmt.Sprintf(f, v...))
77+
d.Log(ctx, Debug, f, v...)
4678
}
4779

4880
// Info implements Logger.Info
4981
func (d *defaultLogger) Info(ctx context.Context, f string, v ...interface{}) {
50-
ctx = alog.AddTags(ctx, "level", "info")
51-
d.Logger.Output(ctx, 3, fmt.Sprintf(f, v...))
82+
d.Log(ctx, Info, f, v...)
5283
}
5384

5485
// Warning implements Logger.Warning
5586
func (d *defaultLogger) Warning(ctx context.Context, f string, v ...interface{}) {
56-
ctx = alog.AddTags(ctx, "level", "warning")
57-
d.Logger.Output(ctx, 3, fmt.Sprintf(f, v...))
87+
d.Log(ctx, Warning, f, v...)
5888
}
5989

6090
// Error implements Logger.Error
6191
func (d *defaultLogger) Error(ctx context.Context, f string, v ...interface{}) {
62-
ctx = alog.AddTags(ctx, "level", "error")
63-
d.Logger.Output(ctx, 3, fmt.Sprintf(f, v...))
92+
d.Log(ctx, Error, f, v...)
6493
}
6594

6695
// Critical implements Logger.Critical
6796
func (d *defaultLogger) Critical(ctx context.Context, f string, v ...interface{}) {
68-
ctx = alog.AddTags(ctx, "level", "critical")
69-
d.Logger.Output(ctx, 3, fmt.Sprintf(f, v...))
97+
d.Log(ctx, Critical, f, v...)
7098
}
99+
100+
// Log implements FilteredLogger.Log
101+
func (d *defaultLogger) Log(ctx context.Context, level Level, f string, v ...interface{}) {
102+
if level >= d.MinLevel {
103+
ctx = alog.AddTags(ctx, LevelKey, level.String())
104+
d.Logger.Output(ctx, 3, fmt.Sprintf(f, v...))
105+
}
106+
}
107+
108+
// SetMinLevel sets the minimum level that will be logged and implements FilteredLogger.
109+
func (d *defaultLogger) SetMinLevel(level Level) {
110+
d.MinLevel = level
111+
}
112+
113+
//go:generate go run golang.org/x/tools/cmd/stringer@latest -type Level -linecomment

leveled/logger_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,18 @@ func TestLogger(t *testing.T) {
2121
t.Errorf("got: %#q, want: %#q", got, want)
2222
}
2323
}
24+
25+
func TestLogLevels(t *testing.T) {
26+
b := &bytes.Buffer{}
27+
l := Filtered(alog.New(alog.WithEmitter(textlog.Emitter(b))))
28+
l.SetMinLevel(Warning)
29+
30+
ctx := context.Background()
31+
ctx = alog.AddTags(ctx, "key", "value")
32+
l.Error(ctx, "I get logged")
33+
l.Debug(ctx, "I don't get logged")
34+
const want = `[key=value level=error] I get logged` + "\n"
35+
if got := b.String(); got != want {
36+
t.Errorf("got: %#q, want: %#q", got, want)
37+
}
38+
}

0 commit comments

Comments
 (0)