-
Notifications
You must be signed in to change notification settings - Fork 512
/
log.go
120 lines (101 loc) · 3.77 KB
/
log.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
// SPDX-License-Identifier: AGPL-3.0-only
// Provenance-includes-location: https://github.com/cortexproject/cortex/blob/master/pkg/util/log/log.go
// Provenance-includes-license: Apache-2.0
// Provenance-includes-copyright: The Cortex Authors.
package log
import (
"fmt"
"io"
"os"
"time"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
dslog "github.com/grafana/dskit/log"
"github.com/prometheus/client_golang/prometheus"
)
var (
// Logger is a shared go-kit logger.
// TODO: Change all components to take a non-global logger via their constructors.
// Prefer accepting a non-global logger as an argument.
Logger = log.NewNopLogger()
bufferedLogger *dslog.BufferedLogger
)
type RateLimitedLoggerCfg struct {
Enabled bool
LogsPerSecond float64
LogsBurstSize int
Registry prometheus.Registerer
}
// InitLogger initialises the global gokit logger (util_log.Logger) and returns that logger.
func InitLogger(logFormat string, logLevel dslog.Level, buffered bool, rateLimitedCfg RateLimitedLoggerCfg) log.Logger {
writer := getWriter(buffered)
logger := dslog.NewGoKitWithWriter(logFormat, writer)
if rateLimitedCfg.Enabled {
// use UTC timestamps and skip 6 stack frames if rate limited logger is needed.
logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.Caller(6))
logger = dslog.NewRateLimitedLogger(logger, rateLimitedCfg.LogsPerSecond, rateLimitedCfg.LogsBurstSize, rateLimitedCfg.Registry)
} else {
// use UTC timestamps and skip 5 stack frames if no rate limited logger is needed.
logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.Caller(5))
}
// Must put the level filter last for efficiency.
logger = newFilter(logger, logLevel)
// Set global logger.
Logger = logger
return logger
}
// Pass through Logger and implement the DebugEnabled interface that spanlogger looks for.
type levelFilter struct {
log.Logger
debugEnabled bool
}
func newFilter(logger log.Logger, lvl dslog.Level) log.Logger {
return &levelFilter{
Logger: level.NewFilter(logger, lvl.Option),
debugEnabled: lvl.String() == "debug", // Using inside knowledge about the hierarchy of possible options.
}
}
func (f *levelFilter) DebugEnabled() bool {
return f.debugEnabled
}
func getWriter(buffered bool) io.Writer {
writer := os.Stderr
if buffered {
var (
logEntries uint32 = 256 // buffer up to 256 log lines in memory before flushing to a write(2) syscall
logBufferSize uint32 = 10e6 // 10MB
flushTimeout = 100 * time.Millisecond // flush the buffer after 100ms regardless of how full it is, to prevent losing many logs in case of ungraceful termination
)
// retain a reference to this logger because it doesn't conform to the standard Logger interface,
// and we can't unwrap it to get the underlying logger when we flush on shutdown
bufferedLogger = dslog.NewBufferedLogger(writer, logEntries,
dslog.WithFlushPeriod(flushTimeout),
dslog.WithPrellocatedBuffer(logBufferSize),
)
return bufferedLogger
}
return log.NewSyncWriter(writer)
}
// CheckFatal prints an error and exits with error code 1 if err is non-nil
func CheckFatal(location string, err error) {
if err != nil {
logger := level.Error(Logger)
if location != "" {
logger = log.With(logger, "msg", "error "+location)
}
// %+v gets the stack trace from errors using github.com/pkg/errors
logger.Log("err", fmt.Sprintf("%+v", err))
if err = Flush(); err != nil {
fmt.Fprintln(os.Stderr, "Could not flush logger", err)
}
os.Exit(1)
}
}
// Flush forces the buffered logger, if configured, to flush to the underlying writer
// This is typically only called when the application is shutting down.
func Flush() error {
if bufferedLogger != nil {
return bufferedLogger.Flush()
}
return nil
}