github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/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 Errorf(format string, args ...interface{}) 23 Fatalf(format string, args ...interface{}) 24 } 25 type defaultLogger struct{} 26 27 // DefaultLogger logs to the Go stdlib logs. 28 var DefaultLogger defaultLogger 29 30 var _ Logger = DefaultLogger 31 32 // Infof implements the Logger.Infof interface. 33 func (defaultLogger) Infof(format string, args ...interface{}) { 34 _ = log.Output(2, fmt.Sprintf(format, args...)) 35 } 36 37 // Errorf implements the Logger.Errorf interface. 38 func (defaultLogger) Errorf(format string, args ...interface{}) { 39 _ = log.Output(2, fmt.Sprintf(format, args...)) 40 } 41 42 // Fatalf implements the Logger.Fatalf interface. 43 func (defaultLogger) Fatalf(format string, args ...interface{}) { 44 _ = log.Output(2, fmt.Sprintf(format, args...)) 45 os.Exit(1) 46 } 47 48 // InMemLogger implements Logger using an in-memory buffer (used for testing). 49 // The buffer can be read via String() and cleared via Reset(). 50 type InMemLogger struct { 51 mu struct { 52 sync.Mutex 53 buf bytes.Buffer 54 } 55 } 56 57 var _ Logger = (*InMemLogger)(nil) 58 59 // Reset clears the internal buffer. 60 func (b *InMemLogger) Reset() { 61 b.mu.Lock() 62 defer b.mu.Unlock() 63 b.mu.buf.Reset() 64 } 65 66 // String returns the current internal buffer. 67 func (b *InMemLogger) String() string { 68 b.mu.Lock() 69 defer b.mu.Unlock() 70 return b.mu.buf.String() 71 } 72 73 // Infof is part of the Logger interface. 74 func (b *InMemLogger) Infof(format string, args ...interface{}) { 75 s := fmt.Sprintf(format, args...) 76 b.mu.Lock() 77 defer b.mu.Unlock() 78 b.mu.buf.Write([]byte(s)) 79 if n := len(s); n == 0 || s[n-1] != '\n' { 80 b.mu.buf.Write([]byte("\n")) 81 } 82 } 83 84 // Errorf is part of the Logger interface. 85 func (b *InMemLogger) Errorf(format string, args ...interface{}) { 86 b.Infof(format, args...) 87 } 88 89 // Fatalf is part of the Logger interface. 90 func (b *InMemLogger) Fatalf(format string, args ...interface{}) { 91 b.Infof(format, args...) 92 runtime.Goexit() 93 } 94 95 // LoggerAndTracer defines an interface for logging and tracing. 96 type LoggerAndTracer interface { 97 Logger 98 // Eventf formats and emits a tracing log, if tracing is enabled in the 99 // current context. 100 Eventf(ctx context.Context, format string, args ...interface{}) 101 // IsTracingEnabled returns true if tracing is enabled. It can be used as an 102 // optimization to avoid calling Eventf (which will be a noop when tracing 103 // is not enabled) to avoid the overhead of boxing the args. 104 IsTracingEnabled(ctx context.Context) bool 105 } 106 107 // LoggerWithNoopTracer wraps a logger and does no tracing. 108 type LoggerWithNoopTracer struct { 109 Logger 110 } 111 112 var _ LoggerAndTracer = &LoggerWithNoopTracer{} 113 114 // Eventf implements LoggerAndTracer. 115 func (*LoggerWithNoopTracer) Eventf(ctx context.Context, format string, args ...interface{}) { 116 if invariants.Enabled && ctx == nil { 117 panic("Eventf context is nil") 118 } 119 } 120 121 // IsTracingEnabled implements LoggerAndTracer. 122 func (*LoggerWithNoopTracer) IsTracingEnabled(ctx context.Context) bool { 123 if invariants.Enabled && ctx == nil { 124 panic("IsTracingEnabled ctx is nil") 125 } 126 return false 127 } 128 129 // NoopLoggerAndTracer does no logging and tracing. Remember that struct{} is 130 // special cased in Go and does not incur an allocation when it backs the 131 // interface LoggerAndTracer. 132 type NoopLoggerAndTracer struct{} 133 134 var _ LoggerAndTracer = NoopLoggerAndTracer{} 135 136 // Infof implements LoggerAndTracer. 137 func (l NoopLoggerAndTracer) Infof(format string, args ...interface{}) {} 138 139 // Errorf implements LoggerAndTracer. 140 func (l NoopLoggerAndTracer) Errorf(format string, args ...interface{}) {} 141 142 // Fatalf implements LoggerAndTracer. 143 func (l NoopLoggerAndTracer) Fatalf(format string, args ...interface{}) {} 144 145 // Eventf implements LoggerAndTracer. 146 func (l NoopLoggerAndTracer) Eventf(ctx context.Context, format string, args ...interface{}) { 147 if invariants.Enabled && ctx == nil { 148 panic("Eventf context is nil") 149 } 150 } 151 152 // IsTracingEnabled implements LoggerAndTracer. 153 func (l NoopLoggerAndTracer) IsTracingEnabled(ctx context.Context) bool { 154 if invariants.Enabled && ctx == nil { 155 panic("IsTracingEnabled ctx is nil") 156 } 157 return false 158 }