logger.go raw

   1  package logging
   2  
   3  import (
   4  	"context"
   5  	"io"
   6  	"log"
   7  )
   8  
   9  // Classification is the type of the log entry's classification name.
  10  type Classification string
  11  
  12  // Set of standard classifications that can be used by clients and middleware
  13  const (
  14  	Warn  Classification = "WARN"
  15  	Debug Classification = "DEBUG"
  16  )
  17  
  18  // Logger is an interface for logging entries at certain classifications.
  19  type Logger interface {
  20  	// Logf is expected to support the standard fmt package "verbs".
  21  	Logf(classification Classification, format string, v ...interface{})
  22  }
  23  
  24  // LoggerFunc is a wrapper around a function to satisfy the Logger interface.
  25  type LoggerFunc func(classification Classification, format string, v ...interface{})
  26  
  27  // Logf delegates the logging request to the wrapped function.
  28  func (f LoggerFunc) Logf(classification Classification, format string, v ...interface{}) {
  29  	f(classification, format, v...)
  30  }
  31  
  32  // ContextLogger is an optional interface a Logger implementation may expose that provides
  33  // the ability to create context aware log entries.
  34  type ContextLogger interface {
  35  	WithContext(context.Context) Logger
  36  }
  37  
  38  // WithContext will pass the provided context to logger if it implements the ContextLogger interface and return the resulting
  39  // logger. Otherwise the logger will be returned as is. As a special case if a nil logger is provided, a Nop logger will
  40  // be returned to the caller.
  41  func WithContext(ctx context.Context, logger Logger) Logger {
  42  	if logger == nil {
  43  		return Nop{}
  44  	}
  45  
  46  	cl, ok := logger.(ContextLogger)
  47  	if !ok {
  48  		return logger
  49  	}
  50  
  51  	return cl.WithContext(ctx)
  52  }
  53  
  54  // Nop is a Logger implementation that simply does not perform any logging.
  55  type Nop struct{}
  56  
  57  // Logf simply returns without performing any action
  58  func (n Nop) Logf(Classification, string, ...interface{}) {
  59  	return
  60  }
  61  
  62  // StandardLogger is a Logger implementation that wraps the standard library logger, and delegates logging to it's
  63  // Printf method.
  64  type StandardLogger struct {
  65  	Logger *log.Logger
  66  }
  67  
  68  // Logf logs the given classification and message to the underlying logger.
  69  func (s StandardLogger) Logf(classification Classification, format string, v ...interface{}) {
  70  	if len(classification) != 0 {
  71  		format = string(classification) + " " + format
  72  	}
  73  
  74  	s.Logger.Printf(format, v...)
  75  }
  76  
  77  // NewStandardLogger returns a new StandardLogger
  78  func NewStandardLogger(writer io.Writer) *StandardLogger {
  79  	return &StandardLogger{
  80  		Logger: log.New(writer, "SDK ", log.LstdFlags),
  81  	}
  82  }
  83