Line data Source code
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 0 : func (defaultLogger) Infof(format string, args ...interface{}) { 33 0 : _ = log.Output(2, fmt.Sprintf(format, args...)) 34 0 : } 35 : 36 : // Fatalf implements the Logger.Fatalf interface. 37 0 : func (defaultLogger) Fatalf(format string, args ...interface{}) { 38 0 : _ = log.Output(2, fmt.Sprintf(format, args...)) 39 0 : os.Exit(1) 40 0 : } 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 0 : func (b *InMemLogger) Reset() { 55 0 : b.mu.Lock() 56 0 : defer b.mu.Unlock() 57 0 : b.mu.buf.Reset() 58 0 : } 59 : 60 : // String returns the current internal buffer. 61 0 : func (b *InMemLogger) String() string { 62 0 : b.mu.Lock() 63 0 : defer b.mu.Unlock() 64 0 : return b.mu.buf.String() 65 0 : } 66 : 67 : // Infof is part of the Logger interface. 68 0 : func (b *InMemLogger) Infof(format string, args ...interface{}) { 69 0 : s := fmt.Sprintf(format, args...) 70 0 : b.mu.Lock() 71 0 : defer b.mu.Unlock() 72 0 : b.mu.buf.Write([]byte(s)) 73 0 : if n := len(s); n == 0 || s[n-1] != '\n' { 74 0 : b.mu.buf.Write([]byte("\n")) 75 0 : } 76 : } 77 : 78 : // Fatalf is part of the Logger interface. 79 0 : func (b *InMemLogger) Fatalf(format string, args ...interface{}) { 80 0 : b.Infof(format, args...) 81 0 : runtime.Goexit() 82 0 : } 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 0 : func (*LoggerWithNoopTracer) Eventf(ctx context.Context, format string, args ...interface{}) { 105 0 : if invariants.Enabled && ctx == nil { 106 0 : panic("Eventf context is nil") 107 : } 108 : } 109 : 110 : // IsTracingEnabled implements LoggerAndTracer. 111 1 : func (*LoggerWithNoopTracer) IsTracingEnabled(ctx context.Context) bool { 112 1 : if invariants.Enabled && ctx == nil { 113 0 : panic("IsTracingEnabled ctx is nil") 114 : } 115 1 : 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 0 : func (l NoopLoggerAndTracer) Infof(format string, args ...interface{}) {} 127 : 128 : // Fatalf implements LoggerAndTracer. 129 0 : func (l NoopLoggerAndTracer) Fatalf(format string, args ...interface{}) {} 130 : 131 : // Eventf implements LoggerAndTracer. 132 0 : func (l NoopLoggerAndTracer) Eventf(ctx context.Context, format string, args ...interface{}) { 133 0 : if invariants.Enabled && ctx == nil { 134 0 : panic("Eventf context is nil") 135 : } 136 : } 137 : 138 : // IsTracingEnabled implements LoggerAndTracer. 139 0 : func (l NoopLoggerAndTracer) IsTracingEnabled(ctx context.Context) bool { 140 0 : if invariants.Enabled && ctx == nil { 141 0 : panic("IsTracingEnabled ctx is nil") 142 : } 143 0 : return false 144 : }