-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathlayout_utils.go
More file actions
139 lines (126 loc) · 3.38 KB
/
Copy pathlayout_utils.go
File metadata and controls
139 lines (126 loc) · 3.38 KB
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
137
138
139
package log4g
import (
"bytes"
"errors"
"fmt"
)
// layout pieces types
const (
lpText = iota
lpLoggerName
lpDate
lpLogLevel
lpMessage
)
// parse states
const (
psText = iota
psPiece
psDateStart
psDate
)
type layoutPiece struct {
value string
pieceType int
}
type LayoutTemplate []layoutPiece
var logLevelNames []string
func init() {
logLevelNames = lm.config.levelNames
}
// ParseLayout parses the layout parameter and returns LayoutTemplate instance
// if it is correct.
// The log message layout is format string with the following placeholders:
// %c - logger name
// %d{date/time format} - date/time. The date/time format should be specified
// in time.Format() form like "Mon, 02 Jan 2006 15:04:05 -0700"
// %p - priority name
// %m - the log message
// %% - '%'
//
// For example, layout string '[%d{01-02 15:04:05.000}] %p %c: %m' will be parsed
// to a layout template, which can be used by ToLogMessage() to form the log
// line. For logger 'a.b.c' will produce message like this:
//
// [09-17 12:34:12.123] INFO a.b.c: Hello logging world!
//
func ParseLayout(layout string) (LayoutTemplate, error) {
layoutTemplate := make(LayoutTemplate, 0, 10)
state := psText
startIdx := 0
for i, rune := range layout {
switch state {
case psText:
if rune == '%' {
layoutTemplate = addPiece(layout[startIdx:i], lpText, layoutTemplate)
state = psPiece
}
case psPiece:
state = psText
startIdx = i + 1
switch rune {
case 'c':
layoutTemplate = addPiece("c", lpLoggerName, layoutTemplate)
case 'd':
state = psDateStart
case 'p':
layoutTemplate = addPiece("p", lpLogLevel, layoutTemplate)
case 'm':
layoutTemplate = addPiece("m", lpMessage, layoutTemplate)
case '%':
startIdx = i
default:
return nil, errors.New("Unknown layout identifier " + string(rune))
}
case psDateStart:
if rune != '{' {
return nil, errors.New("%d should follow by date format in braces like this: %d{...}, but found " + string(rune))
}
startIdx = i + 1
state = psDate
case psDate:
if rune == '}' {
layoutTemplate = addPiece(layout[startIdx:i], lpDate, layoutTemplate)
state = psText
startIdx = i + 1
}
}
}
if state != psText {
return nil, errors.New("Unexpected end of layout, cannot parse it properly")
}
return addPiece(layout[startIdx:len(layout)], lpText, layoutTemplate), nil
}
// ToLogMessage transforms logEvent value to a log text line using provided
// layout template.
//
// For example, for the template '[%d{01-02 15:04:05.000}] %p %c: %m'
// the code line 'abcLogger.info("Hello logging world!")' will produce the log message:
//
// [09-17 12:34:12.123] INFO a.b.c: Hello logging world!
//
// for the logger 'a.b.c'
func ToLogMessage(logEvent *LogEvent, template LayoutTemplate) string {
buf := bytes.NewBuffer(make([]byte, 0, 64))
for _, piece := range template {
switch piece.pieceType {
case lpText:
buf.WriteString(piece.value)
case lpLoggerName:
buf.WriteString(logEvent.LoggerName)
case lpDate:
buf.WriteString(logEvent.Timestamp.Format(piece.value))
case lpLogLevel:
buf.WriteString(logLevelNames[logEvent.Level])
case lpMessage:
buf.WriteString(fmt.Sprint(logEvent.Payload))
}
}
return buf.String()
}
func addPiece(str string, pieceType int, template LayoutTemplate) LayoutTemplate {
if len(str) == 0 {
return template
}
return append(template, layoutPiece{str, pieceType})
}