github.com/mailgun/holster/v4@v4.20.0/consul/log.go (about)

     1  package consul
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"log"
     7  	"os"
     8  
     9  	"github.com/hashicorp/go-hclog"
    10  	"github.com/sirupsen/logrus"
    11  )
    12  
    13  // HCLogAdapter implements the hclog interface, and wraps it
    14  // around a Logrus entry
    15  type HCLogAdapter struct {
    16  	log  logrus.FieldLogger
    17  	name string
    18  	args []interface{} // key/value pairs if this logger was created via With()
    19  }
    20  
    21  func NewHCLogAdapter(logger logrus.FieldLogger, name string) *HCLogAdapter {
    22  	return &HCLogAdapter{
    23  		log:  logger,
    24  		name: name,
    25  	}
    26  }
    27  
    28  // HCLog has one more level than we do. As such, we will never
    29  // set trace level.
    30  func (*HCLogAdapter) Trace(_ string, _ ...interface{}) {
    31  }
    32  
    33  func (a *HCLogAdapter) Debug(msg string, args ...interface{}) {
    34  	a.CreateEntry(args).Debug(msg)
    35  }
    36  
    37  func (a *HCLogAdapter) Info(msg string, args ...interface{}) {
    38  	a.CreateEntry(args).Info(msg)
    39  }
    40  
    41  func (a *HCLogAdapter) Warn(msg string, args ...interface{}) {
    42  	a.CreateEntry(args).Warn(msg)
    43  }
    44  
    45  func (a *HCLogAdapter) Error(msg string, args ...interface{}) {
    46  	a.CreateEntry(args).Error(msg)
    47  }
    48  
    49  func (a *HCLogAdapter) Log(level hclog.Level, msg string, args ...interface{}) {
    50  	switch level {
    51  	case hclog.Trace:
    52  		a.Trace(msg, args...)
    53  	case hclog.Debug:
    54  		a.Debug(msg, args...)
    55  	case hclog.Info:
    56  		a.Info(msg, args...)
    57  	case hclog.Warn:
    58  		a.Warn(msg, args...)
    59  	case hclog.Error:
    60  		a.Error(msg, args...)
    61  	}
    62  }
    63  
    64  func (a *HCLogAdapter) IsTrace() bool {
    65  	return false
    66  }
    67  
    68  func (a *HCLogAdapter) IsDebug() bool {
    69  	return a.shouldEmit(logrus.DebugLevel)
    70  }
    71  
    72  func (a *HCLogAdapter) IsInfo() bool {
    73  	return a.shouldEmit(logrus.InfoLevel)
    74  }
    75  
    76  func (a *HCLogAdapter) IsWarn() bool {
    77  	return a.shouldEmit(logrus.WarnLevel)
    78  }
    79  
    80  func (a *HCLogAdapter) IsError() bool {
    81  	return a.shouldEmit(logrus.ErrorLevel)
    82  }
    83  
    84  func (a *HCLogAdapter) SetLevel(hclog.Level) {
    85  	// interface definition says it is ok for this to be a noop if
    86  	// implementations don't need/want to support dynamic level changing, which
    87  	// we don't currently.
    88  }
    89  
    90  func (a *HCLogAdapter) GetLevel() hclog.Level {
    91  	return hclog.Level(a.log.WithFields(logrus.Fields{}).Level)
    92  }
    93  
    94  func (a *HCLogAdapter) With(args ...interface{}) hclog.Logger {
    95  	e := a.CreateEntry(args)
    96  	return &HCLogAdapter{
    97  		log:  e,
    98  		args: concatFields(a.args, args),
    99  	}
   100  }
   101  
   102  // concatFields combines two sets of key/value pairs.
   103  // It allocates a new slice to avoid using append() and
   104  // accidentally overriding the original slice a, e.g.
   105  // when logger.With() is called multiple times to create
   106  // sub-scoped loggers.
   107  func concatFields(a, b []interface{}) []interface{} {
   108  	c := make([]interface{}, len(a)+len(b))
   109  	copy(c, a)
   110  	copy(c[len(a):], b)
   111  	return c
   112  }
   113  
   114  // ImpliedArgs returns With key/value pairs
   115  func (a *HCLogAdapter) ImpliedArgs() []interface{} {
   116  	return a.args
   117  }
   118  
   119  func (a *HCLogAdapter) Name() string {
   120  	return a.name
   121  }
   122  
   123  func (a *HCLogAdapter) Named(name string) hclog.Logger {
   124  	var newName bytes.Buffer
   125  	if a.name != "" {
   126  		newName.WriteString(a.name)
   127  		newName.WriteString(".")
   128  	}
   129  	newName.WriteString(name)
   130  
   131  	return a.ResetNamed(newName.String())
   132  }
   133  
   134  func (a *HCLogAdapter) ResetNamed(name string) hclog.Logger {
   135  	fields := []interface{}{"subsystem_name", name}
   136  	e := a.CreateEntry(fields)
   137  	return &HCLogAdapter{log: e, name: name}
   138  }
   139  
   140  // StandardLogger is meant to return a stdlib Logger type which wraps around
   141  // hclog. It does this by providing an io.Writer and instantiating a new
   142  // Logger. It then tries to interpret the log level by parsing the message.
   143  //
   144  // Since we are not using `hclog` in a generic way, and I cannot find any
   145  // calls to this method from go-plugin, we will poorly support this method.
   146  // Rather than pull in all of hclog writer parsing logic, pass it a Logrus
   147  // writer, and hardcode the level to INFO.
   148  //
   149  // Apologies to those who find themselves here.
   150  func (a *HCLogAdapter) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger {
   151  	entry := a.log.WithFields(logrus.Fields{})
   152  	return log.New(entry.WriterLevel(logrus.InfoLevel), "", 0)
   153  }
   154  
   155  func (a *HCLogAdapter) StandardWriter(opts *hclog.StandardLoggerOptions) io.Writer {
   156  	var w io.Writer
   157  	logger, ok := a.log.(*logrus.Logger)
   158  	if ok {
   159  		w = logger.Out
   160  	}
   161  	if w == nil {
   162  		w = os.Stderr
   163  	}
   164  	return w
   165  }
   166  
   167  func (a *HCLogAdapter) shouldEmit(level logrus.Level) bool {
   168  	return a.log.WithFields(logrus.Fields{}).Level >= level
   169  }
   170  
   171  func (a *HCLogAdapter) CreateEntry(args []interface{}) *logrus.Entry {
   172  	if len(args)%2 != 0 {
   173  		args = append(args, "<unknown>")
   174  	}
   175  
   176  	fields := make(logrus.Fields)
   177  	for i := 0; i < len(args); i += 2 {
   178  		k, ok := args[i].(string)
   179  		if !ok {
   180  			continue
   181  		}
   182  		v := args[i+1]
   183  		fields[k] = v
   184  	}
   185  
   186  	return a.log.WithFields(fields)
   187  }