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 }