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  }