-
Notifications
You must be signed in to change notification settings - Fork 2
/
logger.go
148 lines (124 loc) · 4.24 KB
/
logger.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package log
import (
"context"
"fmt"
"time"
"github.com/deixis/spine/contextutil"
)
// Logger is an interface for app loggers
type Logger interface {
// Trace level logs are to follow the code executio step by step
Trace(tag, msg string, fields ...Field)
// Warning level logs are meant to draw attention above a certain threshold
// e.g. wrong credentials, 404 status code returned, upstream node down
Warning(tag, msg string, fields ...Field)
// Error level logs need immediate attention
// The 2AM rule applies here, which means that if you are on call, this log line will wake you up at 2AM
// e.g. all critical upstream nodes are down, disk space is full
Error(tag, msg string, fields ...Field)
// With returns a child logger, and optionally add some context to that logger
With(fields ...Field) Logger
// AddCalldepth adds the given value to calldepth
// Calldepth is the count of the number of
// frames to skip when computing the file name and line number
AddCalldepth(n int) Logger
// Close implements the Closer interface
Close() error
}
// Formatter converts a log line to a specific format, such as JSON
type Formatter interface {
// Format formats the given log line
Format(ctx *Context, tag, msg string, fields ...Field) (string, error)
}
// Printer outputs a log line somewhere, such as stdout, syslog, 3rd party service
type Printer interface {
// Print prints the given log line
Print(ctx *Context, s string) error
// Close implements the Closer interface
Close() error
}
// Level defines log severity
type Level int
// ParseLevel parses a string representation of a log level
func ParseLevel(s string) Level {
switch s {
case "trace":
return LevelTrace
case "warning":
return LevelWarning
case "error":
return LevelError
}
return LevelTrace
}
const (
// LevelTrace displays logs with trace level (and above)
LevelTrace Level = iota
// LevelWarning displays logs with warning level (and above)
LevelWarning
// LevelError displays only logs with error level
LevelError
)
// String returns a string representation of the given level
func (l Level) String() string {
switch l {
case LevelTrace:
return "TR"
case LevelWarning:
return "WN"
case LevelError:
return "ER"
default:
panic(fmt.Sprintf("unknown level <%d>", l))
}
}
// Context carries the log line context (level, timestamp, ...)
type Context struct {
Level Level
Timestamp time.Time
Service string
// File name. Depending on the runtime environment, this
// might be a simple name or a fully-qualified name.
File string
// Line within the source file. 1-based; 0 indicates no line number
// available.
Line int64
}
// Trace calls `Trace` on the context `Logger`
func Trace(ctx contextutil.ValueContext, tag, msg string, fields ...Field) {
FromContext(ctx).AddCalldepth(1).Trace(tag, msg, fields...)
}
// Warn calls `Warning` on the context `Logger`
func Warn(ctx contextutil.ValueContext, tag, msg string, fields ...Field) {
FromContext(ctx).AddCalldepth(1).Warning(tag, msg, fields...)
}
// Err calls `Error` on the context `Logger`
func Err(ctx contextutil.ValueContext, tag, msg string, fields ...Field) {
FromContext(ctx).AddCalldepth(1).Error(tag, msg, fields...)
}
type contextKey struct{}
var activeContextKey = contextKey{}
// FromContext returns a `Logger` instance associated with `ctx`, or
// `NopLogger` if no `Logger` instance could be found.
func FromContext(ctx contextutil.ValueContext) Logger {
val := ctx.Value(activeContextKey)
if o, ok := val.(Logger); ok {
return o
}
return NopLogger()
}
// WithContext returns a copy of parent in which the `Logger` is stored
func WithContext(ctx context.Context, l Logger) context.Context {
return context.WithValue(ctx, activeContextKey, l)
}
// NopLogger returns a no-op `Logger`
func NopLogger() Logger {
return &nopLogger{}
}
type nopLogger struct{}
func (l *nopLogger) Trace(tag, msg string, fields ...Field) {}
func (l *nopLogger) Warning(tag, msg string, fields ...Field) {}
func (l *nopLogger) Error(tag, msg string, fields ...Field) {}
func (l *nopLogger) With(fields ...Field) Logger { return &nopLogger{} }
func (l *nopLogger) AddCalldepth(n int) Logger { return &nopLogger{} }
func (l *nopLogger) Close() error { return nil }