-
Notifications
You must be signed in to change notification settings - Fork 1
/
formatters.go
233 lines (207 loc) · 6.04 KB
/
formatters.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package xlog
import (
"bufio"
"fmt"
"io"
"log"
"runtime"
"strings"
"time"
)
// Formatter defines an interface for formatting logs
type Formatter interface {
// Format log entry string to the stream
Format(pkg string, level LogLevel, depth int, entries ...interface{})
// Flush the logs
Flush()
}
// NewStringFormatter returns string-based formatter
func NewStringFormatter(w io.Writer) Formatter {
return &StringFormatter{
w: bufio.NewWriter(w),
}
}
// StringFormatter defines string-based formatter
type StringFormatter struct {
w *bufio.Writer
}
// Format log entry string to the stream
func (s *StringFormatter) Format(pkg string, l LogLevel, i int, entries ...interface{}) {
now := time.Now().UTC()
s.w.WriteString(now.Format(time.RFC3339))
s.w.WriteByte(' ')
writeEntries(s.w, pkg, l, i, entries...)
s.Flush()
}
func writeEntries(w *bufio.Writer, pkg string, _ LogLevel, _ int, entries ...interface{}) {
if pkg != "" {
w.WriteString(pkg + ": ")
}
str := fmt.Sprint(entries...)
endsInNL := strings.HasSuffix(str, "\n")
w.WriteString(str)
if !endsInNL {
w.WriteString("\n")
}
}
// Flush the logs
func (s *StringFormatter) Flush() {
s.w.Flush()
}
// NewPrettyFormatter returns an instance of PrettyFormatter
func NewPrettyFormatter(w io.Writer, debug bool) Formatter {
return &PrettyFormatter{
w: bufio.NewWriter(w),
debug: debug,
}
}
// PrettyFormatter provides default logs format
type PrettyFormatter struct {
w *bufio.Writer
debug bool
}
// Format log entry string to the stream
func (c *PrettyFormatter) Format(pkg string, l LogLevel, depth int, entries ...interface{}) {
now := time.Now()
ts := now.Format("2006-01-02 15:04:05")
c.w.WriteString(ts)
ms := now.Nanosecond() / 1000
c.w.WriteString(fmt.Sprintf(".%06d", ms))
if c.debug {
_, file, line, ok := runtime.Caller(depth) // It's always the same number of frames to the user's call.
if !ok {
file = "???"
line = 1
} else {
slash := strings.LastIndex(file, "/")
if slash >= 0 {
file = file[slash+1:]
}
}
if line < 0 {
line = 0 // not a real line number
}
c.w.WriteString(fmt.Sprintf(" [%s:%d]", file, line))
}
c.w.WriteString(fmt.Sprint(" ", l.Char(), " | "))
writeEntries(c.w, pkg, l, depth, entries...)
c.Flush()
}
// Flush the logs
func (c *PrettyFormatter) Flush() {
c.w.Flush()
}
// NewColorFormatter returns an instance of ColorFormatter
func NewColorFormatter(w io.Writer, color bool) Formatter {
return &ColorFormatter{
w: bufio.NewWriter(w),
color: color,
}
}
// ColorFormatter provides colorful logs format
type ColorFormatter struct {
w *bufio.Writer
color bool
}
// color pallete map
var (
ColorOff = []byte("\033[0m")
colorRed = []byte("\033[0;31m")
colorGreen = []byte("\033[0;32m")
colorOrange = []byte("\033[0;33m")
colorBlue = []byte("\033[0;34m")
colorPurple = []byte("\033[0;35m")
colorCyan = []byte("\033[0;36m")
colorGray = []byte("\033[0;37m") // TRACE
colorLightRed = []byte("\033[0;91m") // ERROR
colorLightGreen = []byte("\033[0;92m") // NOTICE
colorLightOrange = []byte("\033[0;93m") // WARN
colorLightBlue = []byte("\033[0;94m") // DEBUG
colorLightCyan = []byte("\033[0;96m") // INFO
)
// LevelColors provides colors map
var LevelColors = map[LogLevel][]byte{
CRITICAL: colorLightRed,
ERROR: colorLightRed,
WARNING: colorLightOrange,
NOTICE: colorLightGreen,
INFO: colorLightCyan,
DEBUG: colorGray,
TRACE: colorGray,
}
// Format log entry string to the stream
func (c *ColorFormatter) Format(pkg string, l LogLevel, depth int, entries ...interface{}) {
now := time.Now()
ts := now.Format("2006-01-02 15:04:05")
c.w.WriteString(ts)
ms := now.Nanosecond() / 1000
c.w.WriteString(fmt.Sprintf(".%06d", ms))
if c.color {
c.w.Write(LevelColors[l])
}
c.w.WriteString(fmt.Sprint(" ", l.Char(), " | "))
writeEntries(c.w, pkg, l, depth, entries...)
if c.color {
c.w.Write(ColorOff)
}
c.Flush()
}
// Flush the logs
func (c *ColorFormatter) Flush() {
c.w.Flush()
}
// LogFormatter emulates the form of the traditional built-in logger.
type LogFormatter struct {
logger *log.Logger
prefix string
}
// NewLogFormatter is a helper to produce a new LogFormatter struct. It uses the
// golang log package to actually do the logging work so that logs look similar.
func NewLogFormatter(w io.Writer, prefix string, flag int) Formatter {
return &LogFormatter{
logger: log.New(w, "", flag), // don't use prefix here
prefix: prefix, // save it instead
}
}
// Format builds a log message for the LogFormatter. The LogLevel is ignored.
func (lf *LogFormatter) Format(pkg string, _ LogLevel, _ int, entries ...interface{}) {
str := fmt.Sprint(entries...)
prefix := lf.prefix
if pkg != "" {
prefix = fmt.Sprintf("%s%s: ", prefix, pkg)
}
lf.logger.Output(5, fmt.Sprintf("%s%v", prefix, str)) // call depth is 5
}
// Flush is included so that the interface is complete, but is a no-op.
func (lf *LogFormatter) Flush() {
// noop
}
// NilFormatter is a no-op log formatter that does nothing.
type NilFormatter struct {
}
// NewNilFormatter is a helper to produce a new LogFormatter struct. It logs no
// messages so that you can cause part of your logging to be silent.
func NewNilFormatter() Formatter {
return &NilFormatter{}
}
// Format does nothing.
func (*NilFormatter) Format(_ string, _ LogLevel, _ int, _ ...interface{}) {
// noop
}
// Flush is included so that the interface is complete, but is a no-op.
func (*NilFormatter) Flush() {
// noop
}