-
Notifications
You must be signed in to change notification settings - Fork 82
/
logger.go
151 lines (132 loc) · 4.81 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
149
150
151
/*
Copyright 2020 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package logger
import (
"github.com/go-logr/logr"
"github.com/spf13/pflag"
"go.uber.org/zap/zapcore"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)
const (
flagLogEncoding = "log-encoding"
flagLogLevel = "log-level"
)
var levelStrings = map[string]zapcore.Level{
// zap doesn't include trace level as a const, but it accepts any
// int8; logr will convert a log.V(n) to zap's scheme, so e.g.,
// V(2) will be custom debug level -2 in zap (i.e., `trace`
// below).
"trace": zapcore.DebugLevel - 1,
"debug": zapcore.DebugLevel,
"info": zapcore.InfoLevel,
"error": zapcore.ErrorLevel,
}
// These are for convenience when doing log.V(...) to log at a particular level. They correspond to the logr
// equivalents of the zap levels above.
const (
TraceLevel = 2
DebugLevel = 1
InfoLevel = 0
)
var stackLevelStrings = map[string]zapcore.Level{
"trace": zapcore.ErrorLevel,
"debug": zapcore.ErrorLevel,
"info": zapcore.PanicLevel,
"error": zapcore.PanicLevel,
}
// Options contains the configuration options for the runtime logger.
//
// The struct can be used in the main.go file of your controller by binding it to the main flag set, and then utilizing
// the configured options later:
//
// func main() {
// var (
// // other controller specific configuration variables
// loggerOptions logger.Options
// )
//
// // Bind the options to the main flag set, and parse it
// loggerOptions.BindFlags(flag.CommandLine)
// flag.Parse()
//
// // Use the values during the initialisation of the logger
// logger.SetLogger(logger.NewLogger(loggerOptions))
// }
type Options struct {
LogEncoding string
LogLevel string
}
// BindFlags will parse the given pflag.FlagSet for logger option flags and set the Options accordingly.
func (o *Options) BindFlags(fs *pflag.FlagSet) {
fs.StringVar(&o.LogEncoding, flagLogEncoding, "json",
"Log encoding format. Can be 'json' or 'console'.")
fs.StringVar(&o.LogLevel, flagLogLevel, "info",
"Log verbosity level. Can be one of 'trace', 'debug', 'info', 'error'.")
}
// NewLogger returns a logger configured with the given Options, and timestamps set to the ISO8601 format.
func NewLogger(opts Options) logr.Logger {
zapOpts := zap.Options{
EncoderConfigOptions: []zap.EncoderConfigOption{
func(config *zapcore.EncoderConfig) {
config.EncodeTime = zapcore.ISO8601TimeEncoder
},
},
}
switch opts.LogEncoding {
case "console":
zapOpts.EncoderConfigOptions = append(zapOpts.EncoderConfigOptions, func(config *zapcore.EncoderConfig) {
config.EncodeLevel = CapitalLevelEncoder
})
zap.ConsoleEncoder(zapOpts.EncoderConfigOptions...)(&zapOpts)
case "json":
zapOpts.EncoderConfigOptions = append(zapOpts.EncoderConfigOptions, func(config *zapcore.EncoderConfig) {
config.EncodeLevel = LowercaseLevelEncoder
})
zap.JSONEncoder(zapOpts.EncoderConfigOptions...)(&zapOpts)
}
if l, ok := levelStrings[opts.LogLevel]; ok {
zapOpts.Level = l
}
if l, ok := stackLevelStrings[opts.LogLevel]; ok {
zapOpts.StacktraceLevel = l
}
return zap.New(zap.UseFlagOptions(&zapOpts))
}
// SetLogger sets the logger for the controller-runtime and klog packages to the given logger.
// It is not thread-safe, and should be called as early as possible in the program's execution.
func SetLogger(logger logr.Logger) {
ctrl.SetLogger(logger)
klog.SetLoggerWithOptions(logger.WithName("runtime"), klog.ContextualLogger(true))
}
// LowercaseLevelEncoder is a zapcore.LevelEncoder that encodes the level to a lowercase string.
// It has the same behavior as zapcore.LowercaseLevelEncoder, except that it has a special case
// for the trace level, which it encodes as "trace" instead of "Level(-2)".
func LowercaseLevelEncoder(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
if l < zapcore.DebugLevel {
enc.AppendString("trace")
return
}
zapcore.LowercaseLevelEncoder(l, enc)
}
// CapitalLevelEncoder is a zapcore.LevelEncoder that encodes the level to a capitalized string.
// It has the same behavior as zapcore.CapitalLevelEncoder, except that it encodes the trace
// level as "TRACE" instead of "LEVEL(-2)".
func CapitalLevelEncoder(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
if l < zapcore.DebugLevel {
enc.AppendString("TRACE")
return
}
zapcore.CapitalLevelEncoder(l, enc)
}