github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/go-kit/kit/log/stdlib.go (about)

     1  package log
     2  
     3  import (
     4  	"io"
     5  	"log"
     6  	"regexp"
     7  	"strings"
     8  )
     9  
    10  // StdlibWriter implements io.Writer by invoking the stdlib log.Print. It's
    11  // designed to be passed to a Go kit logger as the writer, for cases where
    12  // it's necessary to redirect all Go kit log output to the stdlib logger.
    13  //
    14  // If you have any choice in the matter, you shouldn't use this. Prefer to
    15  // redirect the stdlib log to the Go kit logger via NewStdlibAdapter.
    16  type StdlibWriter struct{}
    17  
    18  // Write implements io.Writer.
    19  func (w StdlibWriter) Write(p []byte) (int, error) {
    20  	log.Print(strings.TrimSpace(string(p)))
    21  	return len(p), nil
    22  }
    23  
    24  // StdlibAdapter wraps a Logger and allows it to be passed to the stdlib
    25  // logger's SetOutput. It will extract date/timestamps, filenames, and
    26  // messages, and place them under relevant keys.
    27  type StdlibAdapter struct {
    28  	Logger
    29  	timestampKey string
    30  	fileKey      string
    31  	messageKey   string
    32  }
    33  
    34  // StdlibAdapterOption sets a parameter for the StdlibAdapter.
    35  type StdlibAdapterOption func(*StdlibAdapter)
    36  
    37  // TimestampKey sets the key for the timestamp field. By default, it's "ts".
    38  func TimestampKey(key string) StdlibAdapterOption {
    39  	return func(a *StdlibAdapter) { a.timestampKey = key }
    40  }
    41  
    42  // FileKey sets the key for the file and line field. By default, it's "caller".
    43  func FileKey(key string) StdlibAdapterOption {
    44  	return func(a *StdlibAdapter) { a.fileKey = key }
    45  }
    46  
    47  // MessageKey sets the key for the actual log message. By default, it's "msg".
    48  func MessageKey(key string) StdlibAdapterOption {
    49  	return func(a *StdlibAdapter) { a.messageKey = key }
    50  }
    51  
    52  // NewStdlibAdapter returns a new StdlibAdapter wrapper around the passed
    53  // logger. It's designed to be passed to log.SetOutput.
    54  func NewStdlibAdapter(logger Logger, options ...StdlibAdapterOption) io.Writer {
    55  	a := StdlibAdapter{
    56  		Logger:       logger,
    57  		timestampKey: "ts",
    58  		fileKey:      "caller",
    59  		messageKey:   "msg",
    60  	}
    61  	for _, option := range options {
    62  		option(&a)
    63  	}
    64  	return a
    65  }
    66  
    67  func (a StdlibAdapter) Write(p []byte) (int, error) {
    68  	result := subexps(p)
    69  	keyvals := []interface{}{}
    70  	var timestamp string
    71  	if date, ok := result["date"]; ok && date != "" {
    72  		timestamp = date
    73  	}
    74  	if time, ok := result["time"]; ok && time != "" {
    75  		if timestamp != "" {
    76  			timestamp += " "
    77  		}
    78  		timestamp += time
    79  	}
    80  	if timestamp != "" {
    81  		keyvals = append(keyvals, a.timestampKey, timestamp)
    82  	}
    83  	if file, ok := result["file"]; ok && file != "" {
    84  		keyvals = append(keyvals, a.fileKey, file)
    85  	}
    86  	if msg, ok := result["msg"]; ok {
    87  		keyvals = append(keyvals, a.messageKey, msg)
    88  	}
    89  	if err := a.Logger.Log(keyvals...); err != nil {
    90  		return 0, err
    91  	}
    92  	return len(p), nil
    93  }
    94  
    95  const (
    96  	logRegexpDate = `(?P<date>[0-9]{4}/[0-9]{2}/[0-9]{2})?[ ]?`
    97  	logRegexpTime = `(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?)?[ ]?`
    98  	logRegexpFile = `(?P<file>.+?:[0-9]+)?`
    99  	logRegexpMsg  = `(: )?(?P<msg>.*)`
   100  )
   101  
   102  var (
   103  	logRegexp = regexp.MustCompile(logRegexpDate + logRegexpTime + logRegexpFile + logRegexpMsg)
   104  )
   105  
   106  func subexps(line []byte) map[string]string {
   107  	m := logRegexp.FindSubmatch(line)
   108  	if len(m) < len(logRegexp.SubexpNames()) {
   109  		return map[string]string{}
   110  	}
   111  	result := map[string]string{}
   112  	for i, name := range logRegexp.SubexpNames() {
   113  		result[name] = string(m[i])
   114  	}
   115  	return result
   116  }