github.com/matrixorigin/matrixone@v0.7.0/pkg/common/log/logger.go (about) 1 // Copyright 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package log 16 17 import ( 18 "context" 19 "fmt" 20 "strings" 21 "time" 22 23 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 24 "github.com/matrixorigin/matrixone/pkg/util/trace" 25 "go.uber.org/zap" 26 "go.uber.org/zap/zapcore" 27 ) 28 29 // GetServiceLogger returns service logger, it will using the service as the logger name, and 30 // append FieldNameServiceUUID field to the logger 31 func GetServiceLogger(logger *zap.Logger, service metadata.ServiceType, uuid string) *MOLogger { 32 return wrap(logger. 33 Named(fmt.Sprintf("%s-service", strings.ToLower(service.String()))). 34 With(zap.String(FieldNameServiceUUID, uuid))) 35 } 36 37 // GetModuleLogger returns the module logger, it will add ".module" to logger name. 38 // e.g. if the logger's name is cn-service, module is txn, the new logger's name is 39 // "cn-service.txn". 40 func GetModuleLogger(logger *MOLogger, module Module) *MOLogger { 41 return wrap(logger.logger.Named(string(module))) 42 } 43 44 // With creates a child logger and adds structured context to it. Fields added 45 // to the child don't affect the parent, and vice versa. 46 func (l *MOLogger) With(fields ...zap.Field) *MOLogger { 47 return newMOLogger(l.logger.With(fields...), l.ctx) 48 } 49 50 // Named adds a new path segment to the logger's name. Segments are joined by 51 // periods. By default, Loggers are unnamed. 52 func (l *MOLogger) Named(name string) *MOLogger { 53 return newMOLogger(l.logger.Named(name), l.ctx) 54 } 55 56 func (l *MOLogger) WithContext(ctx context.Context) *MOLogger { 57 if ctx == nil || ctx == context.TODO() || ctx == context.Background() { 58 panic("nil, context.TODO() and context.Background() are not supported") 59 } 60 if sc := trace.SpanFromContext(ctx).SpanContext(); trace.IsEnable() && sc.IsEmpty() { 61 panic("context with empty SpanContext are not supported") 62 } 63 return newMOLogger(l.logger, ctx) 64 } 65 66 func newMOLogger(logger *zap.Logger, ctx context.Context) *MOLogger { 67 return &MOLogger{ 68 logger: logger, 69 ctx: ctx, 70 m: map[int]*zap.Logger{ 71 1: logger.WithOptions(zap.AddCallerSkip(1)), 72 2: logger.WithOptions(zap.AddCallerSkip(2)), 73 3: logger.WithOptions(zap.AddCallerSkip(3)), 74 }, 75 } 76 } 77 78 // WithProcess if the current log belongs to a certain process, the process name and process ID 79 // can be recorded. When analyzing the log, all related logs can be retrieved according to the 80 // process ID. 81 func (l *MOLogger) WithProcess(process Process) *MOLogger { 82 return l.With(zap.String(FieldNameProcess, string(process))) 83 } 84 85 // Enabled returns true if the level is enabled 86 func (l *MOLogger) Enabled(level zapcore.Level) bool { 87 return l.logger.Core().Enabled(level) 88 } 89 90 // RawLogger returns the raw zap logger 91 func (l *MOLogger) RawLogger() *zap.Logger { 92 return l.logger 93 } 94 95 // Info shortcuts to print info log 96 func (l *MOLogger) Info(msg string, fields ...zap.Field) bool { 97 return l.Log(msg, DefaultLogOptions().WithLevel(zap.InfoLevel).AddCallerSkip(1), fields...) 98 } 99 100 // InfoAction shortcuts to print info action log 101 func (l *MOLogger) InfoAction(msg string, fields ...zap.Field) func() { 102 return l.LogAction(msg, DefaultLogOptions().WithLevel(zap.InfoLevel).AddCallerSkip(1), fields...) 103 } 104 105 // Debug shortcuts to print debug log 106 func (l *MOLogger) Debug(msg string, fields ...zap.Field) bool { 107 return l.Log(msg, DefaultLogOptions().WithLevel(zap.DebugLevel).AddCallerSkip(1), fields...) 108 } 109 110 // InfoDebugAction shortcuts to print debug action log 111 func (l *MOLogger) InfoDebugAction(msg string, fields ...zap.Field) func() { 112 return l.LogAction(msg, DefaultLogOptions().WithLevel(zap.DebugLevel).AddCallerSkip(1), fields...) 113 } 114 115 // Error shortcuts to print error log 116 func (l *MOLogger) Error(msg string, fields ...zap.Field) bool { 117 return l.Log(msg, DefaultLogOptions().WithLevel(zap.ErrorLevel).AddCallerSkip(1), fields...) 118 } 119 120 // Warn shortcuts to print warn log 121 func (l *MOLogger) Warn(msg string, fields ...zap.Field) bool { 122 return l.Log(msg, DefaultLogOptions().WithLevel(zap.WarnLevel).AddCallerSkip(1), fields...) 123 } 124 125 // Panic shortcuts to print panic log 126 func (l *MOLogger) Panic(msg string, fields ...zap.Field) bool { 127 return l.Log(msg, DefaultLogOptions().WithLevel(zap.PanicLevel).AddCallerSkip(1), fields...) 128 } 129 130 // Fatal shortcuts to print fatal log 131 func (l *MOLogger) Fatal(msg string, fields ...zap.Field) bool { 132 return l.Log(msg, DefaultLogOptions().WithLevel(zap.FatalLevel).AddCallerSkip(1), fields...) 133 } 134 135 // Log is the entry point for mo log printing. Return true to indicate that the log 136 // is being recorded by the current LogContext. 137 func (l *MOLogger) Log(msg string, opts LogOptions, fields ...zap.Field) bool { 138 if l.logger == nil { 139 panic("missing logger") 140 } 141 142 for _, fiter := range filters { 143 if !fiter(opts) { 144 return false 145 } 146 } 147 148 if opts.ctx == nil { 149 opts.ctx = l.ctx 150 } 151 152 logger, has := l.m[opts.callerSkip+1] 153 if !has { 154 logger = l.logger 155 } 156 if ce := logger.Check(opts.level, msg); ce != nil { 157 if len(opts.fields) > 0 { 158 fields = append(fields, opts.fields...) 159 } 160 if opts.ctx != nil { 161 fields = append(fields, trace.ContextField(opts.ctx)) 162 } 163 164 ce.Write(fields...) 165 return true 166 } 167 return false 168 } 169 170 // LogAction used to log an action, or generate 2 logs, the first log occurring 171 // at the place where the call is made and the second log occurring at the end 172 // of the function where the LogAction is called, with the additional time consuming. 173 // e.g.: 174 // 175 // func LogActionExample() { 176 // defer log.Info(zapLogger).LogAction("example action")() 177 // } 178 // 179 // This method should often be used to log the elapsed time of a function and, as the 180 // logs appear in pairs, can also be used to check whether a function has been executed. 181 func (l *MOLogger) LogAction(action string, opts LogOptions, fields ...zap.Field) func() { 182 startAt := time.Now() 183 if !l.Log(action, opts.AddCallerSkip(1), fields...) { 184 return nothing 185 } 186 return func() { 187 fields = append(fields, zap.Duration(FieldNameCost, time.Since(startAt))) 188 l.Log(action, opts, fields...) 189 } 190 } 191 192 func wrap(logger *zap.Logger) *MOLogger { 193 return wrapWithContext(logger, nil) 194 } 195 196 func wrapWithContext(logger *zap.Logger, ctx context.Context) *MOLogger { 197 if logger == nil { 198 panic("zap logger is nil") 199 } 200 if ctx != nil && 201 (ctx == context.TODO() || ctx == context.Background()) { 202 panic("TODO and Background are not supported") 203 } 204 205 return newMOLogger( 206 logger.WithOptions(zap.AddStacktrace(zap.ErrorLevel)), 207 ctx, 208 ) 209 } 210 211 func nothing() {} 212 213 // DefaultLogOptions default log options 214 func DefaultLogOptions() LogOptions { 215 return LogOptions{} 216 } 217 218 // WithContext set log trace context. 219 func (opts LogOptions) WithContext(ctx context.Context) LogOptions { 220 if ctx == nil { 221 panic("context is nil") 222 } 223 if ctx == context.TODO() || ctx == context.Background() { 224 panic("TODO and Background contexts are not supported") 225 } 226 if sc := trace.SpanFromContext(ctx).SpanContext(); trace.IsEnable() && sc.IsEmpty() { 227 panic("context with empty SpanContext are not supported") 228 } 229 230 opts.ctx = ctx 231 return opts 232 } 233 234 // WithLevel set log print level 235 func (opts LogOptions) WithLevel(level zapcore.Level) LogOptions { 236 opts.level = level 237 return opts 238 } 239 240 // WithSample sample print the log, using log counts as sampling frequency. First time must output. 241 func (opts LogOptions) WithSample(sampleType SampleType) LogOptions { 242 opts.sampleType = sampleType 243 return opts 244 } 245 246 // AddCallerSkip help to show the logger real caller, by skip n call stack 247 func (opts LogOptions) AddCallerSkip(n int) LogOptions { 248 opts.callerSkip += n 249 return opts 250 } 251 252 // WithProcess if the current log belongs to a certain process, the process name and process ID 253 // can be recorded. When analyzing the log, all related logs can be retrieved according to the 254 // process ID. 255 func (opts LogOptions) WithProcess(process Process, processID string) LogOptions { 256 opts.fields = append(opts.fields, 257 zap.String(FieldNameProcess, string(process)), 258 zap.String(FieldNameProcessID, processID)) 259 return opts 260 }