-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstandard.go
136 lines (122 loc) · 3.75 KB
/
standard.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package logging
import (
"bufio"
"bytes"
"io"
"path"
"regexp"
"strconv"
"time"
)
// A StringWriter writes preformatted strings. StringWriters are intended to be used by StringOutputter.
type StringWriter interface {
Write(str string)
}
// StringOutputter implements Outputter by combining a Formatter and a StringWriter.
type StringOutputter struct {
Formatter Formatter
Writer StringWriter
}
// Output formats the message with the StringOutputter's Formatter, and then writes the result to the StringWriter.
func (s StringOutputter) Output(msg *Message) {
s.Writer.Write(s.Formatter.Format(msg))
}
// IOWriter implements StringWriter by writing lines to an io.Writer.
type IOWriter struct {
Writer io.Writer
}
// Implements StringWriter.
func (w IOWriter) Write(str string) {
io.WriteString(w.Writer, str+"\n")
if bufout, ok := w.Writer.(*bufio.Writer); ok {
bufout.Flush()
}
}
// ThresholdOutputter wraps an Outputter and only forwards messages that meet a certain threshold level.
type ThresholdOutputter struct {
Threshold Level
Outputter Outputter
}
func (t ThresholdOutputter) Output(msg *Message) {
if t.Threshold > msg.Level {
return
}
t.Outputter.Output(msg)
}
// BasicFormatter uses simple string templates to format messages.
type BasicFormatter struct {
// Map of variable name to date format strings, as accepted by the Format method of time.Time objects. By default
// contains the keys "date" (just the date), "time" (just the time), and "datetime" (date and time).
DateVars map[string]string
template []templatePart
}
var templateRegex = regexp.MustCompile(`^(\$[a-zA-Z]+|\$\$|[^\$]+)`)
// Returns a new BasicFormatter that uses the given template. The template may contain variables in the form $name,
// as well as arbitrary text. Variables will be substituted for their values in the result of Format. The default
// variables are:
// level The level of the message, as returned by Level.String.
// msg The string associated with the message.
// file The name of the file where the logging statement originated.
// line The line number where the logging statement originated.
// logger The name of the logger which was used to log the message.
// Variables from DateVars ($date, $time and $datetime, by default) are also included.
//
// For example: If the template is "[$level] $time - $msg\n", then the call logger.Warn("oh no!") could produce
// an output of: "[WARN] 15:04:05 - oh no!\n".
func NewBasicFormatter(template string) *BasicFormatter {
parts := []templatePart{}
remain := template
for len(remain) > 0 {
match := templateRegex.FindString(remain)
if match == "" {
panic("invalid template: " + template)
}
switch {
case match == "$$":
parts = append(parts, templatePart{"$", false})
case match[0] == '$':
parts = append(parts, templatePart{match[1:], true})
default:
parts = append(parts, templatePart{match, false})
}
remain = remain[len(match):]
}
return &BasicFormatter{
template: parts,
DateVars: map[string]string{
"date": "02/01/2006",
"time": "15:04:05",
"datetime": time.ANSIC,
},
}
}
// Implements Formatter.
func (b *BasicFormatter) Format(msg *Message) string {
vars := b.getVars(msg)
var result bytes.Buffer
for _, part := range b.template {
if part.Var {
result.WriteString(vars[part.Str])
} else {
result.WriteString(part.Str)
}
}
return result.String()
}
func (b *BasicFormatter) getVars(msg *Message) map[string]string {
vars := map[string]string{
"level": msg.Level.String(),
"msg": msg.Msg,
"file": path.Base(msg.File),
"line": strconv.Itoa(msg.Line),
"logger": msg.Logger.Name,
}
for key, layout := range b.DateVars {
vars[key] = msg.Time.Format(layout)
}
return vars
}
type templatePart struct {
Str string
Var bool
}