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 : 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 1 : func (defaultLogger) Infof(format string, args ...interface{}) { 34 1 : _ = log.Output(2, fmt.Sprintf(format, args...)) 35 1 : } 36 : 37 : // Errorf implements the Logger.Errorf interface. 38 1 : func (defaultLogger) Errorf(format string, args ...interface{}) { 39 1 : _ = log.Output(2, fmt.Sprintf(format, args...)) 40 1 : } 41 : 42 : // Fatalf implements the Logger.Fatalf interface. 43 0 : func (defaultLogger) Fatalf(format string, args ...interface{}) { 44 0 : _ = log.Output(2, fmt.Sprintf(format, args...)) 45 0 : os.Exit(1) 46 0 : } 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 1 : func (b *InMemLogger) Reset() { 61 1 : b.mu.Lock() 62 1 : defer b.mu.Unlock() 63 1 : b.mu.buf.Reset() 64 1 : } 65 : 66 : // String returns the current internal buffer. 67 1 : func (b *InMemLogger) String() string { 68 1 : b.mu.Lock() 69 1 : defer b.mu.Unlock() 70 1 : return b.mu.buf.String() 71 1 : } 72 : 73 : // Infof is part of the Logger interface. 74 1 : func (b *InMemLogger) Infof(format string, args ...interface{}) { 75 1 : s := fmt.Sprintf(format, args...) 76 1 : b.mu.Lock() 77 1 : defer b.mu.Unlock() 78 1 : b.mu.buf.Write([]byte(s)) 79 1 : if n := len(s); n == 0 || s[n-1] != '\n' { 80 1 : b.mu.buf.Write([]byte("\n")) 81 1 : } 82 : } 83 : 84 : // Errorf is part of the Logger interface. 85 0 : func (b *InMemLogger) Errorf(format string, args ...interface{}) { 86 0 : b.Infof(format, args...) 87 0 : } 88 : 89 : // Fatalf is part of the Logger interface. 90 0 : func (b *InMemLogger) Fatalf(format string, args ...interface{}) { 91 0 : b.Infof(format, args...) 92 0 : runtime.Goexit() 93 0 : } 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 0 : func (*LoggerWithNoopTracer) Eventf(ctx context.Context, format string, args ...interface{}) { 116 0 : if invariants.Enabled && ctx == nil { 117 0 : panic("Eventf context is nil") 118 : } 119 : } 120 : 121 : // IsTracingEnabled implements LoggerAndTracer. 122 1 : func (*LoggerWithNoopTracer) IsTracingEnabled(ctx context.Context) bool { 123 1 : if invariants.Enabled && ctx == nil { 124 0 : panic("IsTracingEnabled ctx is nil") 125 : } 126 1 : 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 0 : func (l NoopLoggerAndTracer) Infof(format string, args ...interface{}) {} 138 : 139 : // Errorf implements LoggerAndTracer. 140 0 : func (l NoopLoggerAndTracer) Errorf(format string, args ...interface{}) {} 141 : 142 : // Fatalf implements LoggerAndTracer. 143 0 : func (l NoopLoggerAndTracer) Fatalf(format string, args ...interface{}) {} 144 : 145 : // Eventf implements LoggerAndTracer. 146 0 : func (l NoopLoggerAndTracer) Eventf(ctx context.Context, format string, args ...interface{}) { 147 0 : if invariants.Enabled && ctx == nil { 148 0 : panic("Eventf context is nil") 149 : } 150 : } 151 : 152 : // IsTracingEnabled implements LoggerAndTracer. 153 1 : func (l NoopLoggerAndTracer) IsTracingEnabled(ctx context.Context) bool { 154 1 : if invariants.Enabled && ctx == nil { 155 0 : panic("IsTracingEnabled ctx is nil") 156 : } 157 1 : return false 158 : }