...
1 package log
2
3 import (
4 "bytes"
5 "io"
6 "log"
7 "regexp"
8 "strings"
9 )
10
11
12
13
14
15
16
17 type StdlibWriter struct{}
18
19
20 func (w StdlibWriter) Write(p []byte) (int, error) {
21 log.Print(strings.TrimSpace(string(p)))
22 return len(p), nil
23 }
24
25
26
27
28 type StdlibAdapter struct {
29 Logger
30 timestampKey string
31 fileKey string
32 messageKey string
33 prefix string
34 joinPrefixToMsg bool
35 }
36
37
38 type StdlibAdapterOption func(*StdlibAdapter)
39
40
41 func TimestampKey(key string) StdlibAdapterOption {
42 return func(a *StdlibAdapter) { a.timestampKey = key }
43 }
44
45
46 func FileKey(key string) StdlibAdapterOption {
47 return func(a *StdlibAdapter) { a.fileKey = key }
48 }
49
50
51 func MessageKey(key string) StdlibAdapterOption {
52 return func(a *StdlibAdapter) { a.messageKey = key }
53 }
54
55
56
57
58
59
60
61 func Prefix(prefix string, joinPrefixToMsg bool) StdlibAdapterOption {
62 return func(a *StdlibAdapter) { a.prefix = prefix; a.joinPrefixToMsg = joinPrefixToMsg }
63 }
64
65
66
67 func NewStdlibAdapter(logger Logger, options ...StdlibAdapterOption) io.Writer {
68 a := StdlibAdapter{
69 Logger: logger,
70 timestampKey: "ts",
71 fileKey: "caller",
72 messageKey: "msg",
73 }
74 for _, option := range options {
75 option(&a)
76 }
77 return a
78 }
79
80 func (a StdlibAdapter) Write(p []byte) (int, error) {
81 p = a.handlePrefix(p)
82
83 result := subexps(p)
84 keyvals := []interface{}{}
85 var timestamp string
86 if date, ok := result["date"]; ok && date != "" {
87 timestamp = date
88 }
89 if time, ok := result["time"]; ok && time != "" {
90 if timestamp != "" {
91 timestamp += " "
92 }
93 timestamp += time
94 }
95 if timestamp != "" {
96 keyvals = append(keyvals, a.timestampKey, timestamp)
97 }
98 if file, ok := result["file"]; ok && file != "" {
99 keyvals = append(keyvals, a.fileKey, file)
100 }
101 if msg, ok := result["msg"]; ok {
102 msg = a.handleMessagePrefix(msg)
103 keyvals = append(keyvals, a.messageKey, msg)
104 }
105 if err := a.Logger.Log(keyvals...); err != nil {
106 return 0, err
107 }
108 return len(p), nil
109 }
110
111 func (a StdlibAdapter) handlePrefix(p []byte) []byte {
112 if a.prefix != "" {
113 p = bytes.TrimPrefix(p, []byte(a.prefix))
114 }
115 return p
116 }
117
118 func (a StdlibAdapter) handleMessagePrefix(msg string) string {
119 if a.prefix == "" {
120 return msg
121 }
122
123 msg = strings.TrimPrefix(msg, a.prefix)
124 if a.joinPrefixToMsg {
125 msg = a.prefix + msg
126 }
127 return msg
128 }
129
130 const (
131 logRegexpDate = `(?P<date>[0-9]{4}/[0-9]{2}/[0-9]{2})?[ ]?`
132 logRegexpTime = `(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?)?[ ]?`
133 logRegexpFile = `(?P<file>.+?:[0-9]+)?`
134 logRegexpMsg = `(: )?(?P<msg>(?s:.*))`
135 )
136
137 var (
138 logRegexp = regexp.MustCompile(logRegexpDate + logRegexpTime + logRegexpFile + logRegexpMsg)
139 )
140
141 func subexps(line []byte) map[string]string {
142 m := logRegexp.FindSubmatch(line)
143 if len(m) < len(logRegexp.SubexpNames()) {
144 return map[string]string{}
145 }
146 result := map[string]string{}
147 for i, name := range logRegexp.SubexpNames() {
148 result[name] = strings.TrimRight(string(m[i]), "\n")
149 }
150 return result
151 }
152
View as plain text