inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/log/log.go (about) 1 // Copyright 2018 The gVisor Authors. 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 implements a library for logging. 16 // 17 // This is separate from the standard logging package because logging may be a 18 // high-impact activity, and therefore we wanted to provide as much flexibility 19 // as possible in the underlying implementation. 20 // 21 // Note that logging should still be considered high-impact, and should not be 22 // done in the hot path. If necessary, logging statements should be protected 23 // with guards regarding the logging level. For example, 24 // 25 // if log.IsLogging(log.Debug) { 26 // log.Debugf(...) 27 // } 28 // 29 // This is because the log.Debugf(...) statement alone will generate a 30 // significant amount of garbage and churn in many cases, even if no log 31 // message is ultimately emitted. 32 package log 33 34 import ( 35 "fmt" 36 "io" 37 stdlog "log" 38 "os" 39 "runtime" 40 "sync/atomic" 41 "time" 42 43 "inet.af/netstack/linewriter" 44 "inet.af/netstack/sync" 45 ) 46 47 // Level is the log level. 48 type Level uint32 49 50 // The following levels are fixed, and can never be changed. Since some control 51 // RPCs allow for changing the level as an integer, it is only possible to add 52 // additional levels, and the existing one cannot be removed. 53 const ( 54 // Warning indicates that output should always be emitted. 55 Warning Level = iota 56 57 // Info indicates that output should normally be emitted. 58 Info 59 60 // Debug indicates that output should not normally be emitted. 61 Debug 62 ) 63 64 func (l Level) String() string { 65 switch l { 66 case Warning: 67 return "Warning" 68 case Info: 69 return "Info" 70 case Debug: 71 return "Debug" 72 default: 73 return fmt.Sprintf("Invalid level: %d", l) 74 } 75 } 76 77 // Emitter is the final destination for logs. 78 type Emitter interface { 79 // Emit emits the given log statement. This allows for control over the 80 // timestamp used for logging. 81 Emit(depth int, level Level, timestamp time.Time, format string, v ...interface{}) 82 } 83 84 // Writer writes the output to the given writer. 85 type Writer struct { 86 // Next is where output is written. 87 Next io.Writer 88 89 // mu protects fields below. 90 mu sync.Mutex 91 92 // errors counts failures to write log messages so it can be reported 93 // when writer start to work again. Needs to be accessed using atomics 94 // to make race detector happy because it's read outside the mutex. 95 errors int32 96 } 97 98 // Write writes out the given bytes, handling non-blocking sockets. 99 func (l *Writer) Write(data []byte) (int, error) { 100 n := 0 101 102 for n < len(data) { 103 w, err := l.Next.Write(data[n:]) 104 n += w 105 106 // Is it a non-blocking socket? 107 if pathErr, ok := err.(*os.PathError); ok && pathErr.Timeout() { 108 runtime.Gosched() 109 continue 110 } 111 112 // Some other error? 113 if err != nil { 114 l.mu.Lock() 115 atomic.AddInt32(&l.errors, 1) 116 l.mu.Unlock() 117 return n, err 118 } 119 } 120 121 // Do we need to end with a '\n'? 122 if len(data) == 0 || data[len(data)-1] != '\n' { 123 l.Write([]byte{'\n'}) 124 } 125 126 // Dirty read in case there were errors (rare). 127 if atomic.LoadInt32(&l.errors) > 0 { 128 l.mu.Lock() 129 defer l.mu.Unlock() 130 131 // Recheck condition under lock. 132 if e := atomic.LoadInt32(&l.errors); e > 0 { 133 msg := fmt.Sprintf("\n*** Dropped %d log messages ***\n", e) 134 if _, err := l.Next.Write([]byte(msg)); err == nil { 135 atomic.StoreInt32(&l.errors, 0) 136 } 137 } 138 } 139 140 return n, nil 141 } 142 143 // Emit emits the message. 144 func (l *Writer) Emit(_ int, _ Level, _ time.Time, format string, args ...interface{}) { 145 fmt.Fprintf(l, format, args...) 146 } 147 148 // MultiEmitter is an emitter that emits to multiple Emitters. 149 type MultiEmitter []Emitter 150 151 // Emit emits to all emitters. 152 func (m *MultiEmitter) Emit(depth int, level Level, timestamp time.Time, format string, v ...interface{}) { 153 for _, e := range *m { 154 e.Emit(1+depth, level, timestamp, format, v...) 155 } 156 } 157 158 // TestLogger is implemented by testing.T and testing.B. 159 type TestLogger interface { 160 Logf(format string, v ...interface{}) 161 } 162 163 // TestEmitter may be used for wrapping tests. 164 type TestEmitter struct { 165 TestLogger 166 } 167 168 // Emit emits to the TestLogger. 169 func (t *TestEmitter) Emit(_ int, level Level, timestamp time.Time, format string, v ...interface{}) { 170 t.Logf(format, v...) 171 } 172 173 // Logger is a high-level logging interface. It is in fact, not used within the 174 // log package. Rather it is provided for others to provide contextual loggers 175 // that may append some addition information to log statement. BasicLogger 176 // satisfies this interface, and may be passed around as a Logger. 177 type Logger interface { 178 // Debugf logs a debug statement. 179 Debugf(format string, v ...interface{}) 180 181 // Infof logs at an info level. 182 Infof(format string, v ...interface{}) 183 184 // Warningf logs at a warning level. 185 Warningf(format string, v ...interface{}) 186 187 // IsLogging returns true iff this level is being logged. This may be 188 // used to short-circuit expensive operations for debugging calls. 189 IsLogging(level Level) bool 190 } 191 192 // BasicLogger is the default implementation of Logger. 193 type BasicLogger struct { 194 Level 195 Emitter 196 } 197 198 // Debugf implements logger.Debugf. 199 func (l *BasicLogger) Debugf(format string, v ...interface{}) { 200 l.DebugfAtDepth(1, format, v...) 201 } 202 203 // Infof implements logger.Infof. 204 func (l *BasicLogger) Infof(format string, v ...interface{}) { 205 l.InfofAtDepth(1, format, v...) 206 } 207 208 // Warningf implements logger.Warningf. 209 func (l *BasicLogger) Warningf(format string, v ...interface{}) { 210 l.WarningfAtDepth(1, format, v...) 211 } 212 213 // DebugfAtDepth logs at a specific depth. 214 func (l *BasicLogger) DebugfAtDepth(depth int, format string, v ...interface{}) { 215 if l.IsLogging(Debug) { 216 l.Emit(1+depth, Debug, time.Now(), format, v...) 217 } 218 } 219 220 // InfofAtDepth logs at a specific depth. 221 func (l *BasicLogger) InfofAtDepth(depth int, format string, v ...interface{}) { 222 if l.IsLogging(Info) { 223 l.Emit(1+depth, Info, time.Now(), format, v...) 224 } 225 } 226 227 // WarningfAtDepth logs at a specific depth. 228 func (l *BasicLogger) WarningfAtDepth(depth int, format string, v ...interface{}) { 229 if l.IsLogging(Warning) { 230 l.Emit(1+depth, Warning, time.Now(), format, v...) 231 } 232 } 233 234 // IsLogging implements logger.IsLogging. 235 func (l *BasicLogger) IsLogging(level Level) bool { 236 return atomic.LoadUint32((*uint32)(&l.Level)) >= uint32(level) 237 } 238 239 // SetLevel sets the logging level. 240 func (l *BasicLogger) SetLevel(level Level) { 241 atomic.StoreUint32((*uint32)(&l.Level), uint32(level)) 242 } 243 244 // logMu protects Log below. We use atomic operations to read the value, but 245 // updates require logMu to ensure consistency. 246 var logMu sync.Mutex 247 248 // log is the default logger. 249 var log atomic.Value 250 251 // Log retrieves the global logger. 252 func Log() *BasicLogger { 253 return log.Load().(*BasicLogger) 254 } 255 256 // SetTarget sets the log target. 257 // 258 // This is not thread safe and shouldn't be called concurrently with any 259 // logging calls. 260 func SetTarget(target Emitter) { 261 logMu.Lock() 262 defer logMu.Unlock() 263 oldLog := Log() 264 log.Store(&BasicLogger{Level: oldLog.Level, Emitter: target}) 265 } 266 267 // SetLevel sets the log level. 268 func SetLevel(newLevel Level) { 269 Log().SetLevel(newLevel) 270 } 271 272 // Debugf logs to the global logger. 273 func Debugf(format string, v ...interface{}) { 274 Log().DebugfAtDepth(1, format, v...) 275 } 276 277 // Infof logs to the global logger. 278 func Infof(format string, v ...interface{}) { 279 Log().InfofAtDepth(1, format, v...) 280 } 281 282 // Warningf logs to the global logger. 283 func Warningf(format string, v ...interface{}) { 284 Log().WarningfAtDepth(1, format, v...) 285 } 286 287 // DebugfAtDepth logs to the global logger. 288 func DebugfAtDepth(depth int, format string, v ...interface{}) { 289 Log().DebugfAtDepth(1+depth, format, v...) 290 } 291 292 // InfofAtDepth logs to the global logger. 293 func InfofAtDepth(depth int, format string, v ...interface{}) { 294 Log().InfofAtDepth(1+depth, format, v...) 295 } 296 297 // WarningfAtDepth logs to the global logger. 298 func WarningfAtDepth(depth int, format string, v ...interface{}) { 299 Log().WarningfAtDepth(1+depth, format, v...) 300 } 301 302 // defaultStackSize is the default buffer size to allocate for stack traces. 303 const defaultStackSize = 1 << 16 // 64KB 304 305 // maxStackSize is the maximum buffer size to allocate for stack traces. 306 const maxStackSize = 1 << 26 // 64MB 307 308 // Stacks returns goroutine stacks, like panic. 309 func Stacks(all bool) []byte { 310 var trace []byte 311 for s := defaultStackSize; s <= maxStackSize; s *= 4 { 312 trace = make([]byte, s) 313 nbytes := runtime.Stack(trace, all) 314 if nbytes == s { 315 continue 316 } 317 return trace[:nbytes] 318 } 319 trace = append(trace, []byte("\n\n...<too large, truncated>")...) 320 return trace 321 } 322 323 // Traceback logs the given message and dumps a stacktrace of the current 324 // goroutine. 325 // 326 // This will be print a traceback, tb, as Warningf(format+":\n%s", v..., tb). 327 func Traceback(format string, v ...interface{}) { 328 v = append(v, Stacks(false)) 329 Warningf(format+":\n%s", v...) 330 } 331 332 // TracebackAll logs the given message and dumps a stacktrace of all goroutines. 333 // 334 // This will be print a traceback, tb, as Warningf(format+":\n%s", v..., tb). 335 func TracebackAll(format string, v ...interface{}) { 336 v = append(v, Stacks(true)) 337 Warningf(format+":\n%s", v...) 338 } 339 340 // IsLogging returns whether the global logger is logging. 341 func IsLogging(level Level) bool { 342 return Log().IsLogging(level) 343 } 344 345 // CopyStandardLogTo redirects the stdlib log package global output to the global 346 // logger for the specified level. 347 func CopyStandardLogTo(l Level) error { 348 var f func(string, ...interface{}) 349 350 switch l { 351 case Debug: 352 f = Debugf 353 case Info: 354 f = Infof 355 case Warning: 356 f = Warningf 357 default: 358 return fmt.Errorf("unknown log level %v", l) 359 } 360 361 stdlog.SetOutput(linewriter.NewWriter(func(p []byte) { 362 // We must not retain p, but log formatting is not required to 363 // be synchronous (though the in-package implementations are), 364 // so we must make a copy. 365 b := make([]byte, len(p)) 366 copy(b, p) 367 368 f("%s", b) 369 })) 370 371 return nil 372 } 373 374 func init() { 375 // Store the initial value for the log. 376 log.Store(&BasicLogger{Level: Info, Emitter: GoogleEmitter{&Writer{Next: os.Stderr}}}) 377 }