github.com/cockroachdb/pebble@v1.1.1-0.20240513155919-3622ade60459/internal/base/logger.go (about) 1 // Copyright 2023 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package base 6 7 import ( 8 "bytes" 9 "context" 10 "fmt" 11 "log" 12 "os" 13 "runtime" 14 "sync" 15 16 "github.com/cockroachdb/pebble/internal/invariants" 17 ) 18 19 // Logger defines an interface for writing log messages. 20 type Logger interface { 21 Infof(format string, args ...interface{}) 22 Fatalf(format string, args ...interface{}) 23 } 24 type defaultLogger struct{} 25 26 // DefaultLogger logs to the Go stdlib logs. 27 var DefaultLogger defaultLogger 28 29 var _ Logger = DefaultLogger 30 31 // Infof implements the Logger.Infof interface. 32 func (defaultLogger) Infof(format string, args ...interface{}) { 33 _ = log.Output(2, fmt.Sprintf(format, args...)) 34 } 35 36 // Fatalf implements the Logger.Fatalf interface. 37 func (defaultLogger) Fatalf(format string, args ...interface{}) { 38 _ = log.Output(2, fmt.Sprintf(format, args...)) 39 os.Exit(1) 40 } 41 42 // InMemLogger implements Logger using an in-memory buffer (used for testing). 43 // The buffer can be read via String() and cleared via Reset(). 44 type InMemLogger struct { 45 mu struct { 46 sync.Mutex 47 buf bytes.Buffer 48 } 49 } 50 51 var _ Logger = (*InMemLogger)(nil) 52 53 // Reset clears the internal buffer. 54 func (b *InMemLogger) Reset() { 55 b.mu.Lock() 56 defer b.mu.Unlock() 57 b.mu.buf.Reset() 58 } 59 60 // String returns the current internal buffer. 61 func (b *InMemLogger) String() string { 62 b.mu.Lock() 63 defer b.mu.Unlock() 64 return b.mu.buf.String() 65 } 66 67 // Infof is part of the Logger interface. 68 func (b *InMemLogger) Infof(format string, args ...interface{}) { 69 s := fmt.Sprintf(format, args...) 70 b.mu.Lock() 71 defer b.mu.Unlock() 72 b.mu.buf.Write([]byte(s)) 73 if n := len(s); n == 0 || s[n-1] != '\n' { 74 b.mu.buf.Write([]byte("\n")) 75 } 76 } 77 78 // Fatalf is part of the Logger interface. 79 func (b *InMemLogger) Fatalf(format string, args ...interface{}) { 80 b.Infof(format, args...) 81 runtime.Goexit() 82 } 83 84 // LoggerAndTracer defines an interface for logging and tracing. 85 type LoggerAndTracer interface { 86 Logger 87 // Eventf formats and emits a tracing log, if tracing is enabled in the 88 // current context. 89 Eventf(ctx context.Context, format string, args ...interface{}) 90 // IsTracingEnabled returns true if tracing is enabled. It can be used as an 91 // optimization to avoid calling Eventf (which will be a noop when tracing 92 // is not enabled) to avoid the overhead of boxing the args. 93 IsTracingEnabled(ctx context.Context) bool 94 } 95 96 // LoggerWithNoopTracer wraps a logger and does no tracing. 97 type LoggerWithNoopTracer struct { 98 Logger 99 } 100 101 var _ LoggerAndTracer = &LoggerWithNoopTracer{} 102 103 // Eventf implements LoggerAndTracer. 104 func (*LoggerWithNoopTracer) Eventf(ctx context.Context, format string, args ...interface{}) { 105 if invariants.Enabled && ctx == nil { 106 panic("Eventf context is nil") 107 } 108 } 109 110 // IsTracingEnabled implements LoggerAndTracer. 111 func (*LoggerWithNoopTracer) IsTracingEnabled(ctx context.Context) bool { 112 if invariants.Enabled && ctx == nil { 113 panic("IsTracingEnabled ctx is nil") 114 } 115 return false 116 } 117 118 // NoopLoggerAndTracer does no logging and tracing. Remember that struct{} is 119 // special cased in Go and does not incur an allocation when it backs the 120 // interface LoggerAndTracer. 121 type NoopLoggerAndTracer struct{} 122 123 var _ LoggerAndTracer = NoopLoggerAndTracer{} 124 125 // Infof implements LoggerAndTracer. 126 func (l NoopLoggerAndTracer) Infof(format string, args ...interface{}) {} 127 128 // Fatalf implements LoggerAndTracer. 129 func (l NoopLoggerAndTracer) Fatalf(format string, args ...interface{}) {} 130 131 // Eventf implements LoggerAndTracer. 132 func (l NoopLoggerAndTracer) Eventf(ctx context.Context, format string, args ...interface{}) { 133 if invariants.Enabled && ctx == nil { 134 panic("Eventf context is nil") 135 } 136 } 137 138 // IsTracingEnabled implements LoggerAndTracer. 139 func (l NoopLoggerAndTracer) IsTracingEnabled(ctx context.Context) bool { 140 if invariants.Enabled && ctx == nil { 141 panic("IsTracingEnabled ctx is nil") 142 } 143 return false 144 }