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  }