-
Notifications
You must be signed in to change notification settings - Fork 0
/
log.go
149 lines (133 loc) · 4.74 KB
/
log.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
package echox
import (
"bytes"
"io"
"strconv"
"sync"
"time"
)
//-----------------------------------------------------------------------------
// Example for Zap (https://github.com/uber-go/zap)
// func main() {
// e := echox.New()
// logger, _ := zap.NewProduction()
// e.Logger = &ZapLogger{logger: logger}
//}
// type ZapLogger struct {
// logger *zap.Logger
//}
//
// func (l *ZapLogger) Write(p []byte) (n int, err error) {
// // Note: if `logger` middleware is used it will send json bytes here, and it will not look beautiful at all.
// l.logger.Info(string(p), zap.String("subsystem", "echo")) // naively log everything as string message.
// return len(p), nil
//}
//
// func (l *ZapLogger) Error(err error) {
// l.logger.Error(err.Error(), zap.Error(err), zap.String("subsystem", "echo"))
//}
//-----------------------------------------------------------------------------
// Example for Zerolog (https://github.com/rs/zerolog)
// func main() {
// e := echox.New()
// logger := zerolog.New(os.Stdout)
// e.Logger = &ZeroLogger{logger: &logger}
//}
//
// type ZeroLogger struct {
// logger *zerolog.Logger
//}
//
// func (l *ZeroLogger) Write(p []byte) (n int, err error) {
// // Note: if `logger` middleware is used it will send json bytes here, and it will not look beautiful at all.
// l.logger.Info().Str("subsystem", "echo").Msg(string(p)) // naively log everything as string message.
// return len(p), nil
//}
//
// func (l *ZeroLogger) Error(err error) {
// l.logger.Error().Str("subsystem", "echo").Err(err).Msg(err.Error())
//}
//-----------------------------------------------------------------------------
// Example for Logrus (https://github.com/sirupsen/logrus)
// func main() {
// e := echox.New()
// e.Logger = &LogrusLogger{logger: logrus.New()}
//}
//
// type LogrusLogger struct {
// logger *logrus.Logger
//}
//
// func (l *LogrusLogger) Write(p []byte) (n int, err error) {
// // Note: if `logger` middleware is used it will send json bytes here, and it will not look beautiful at all.
// l.logger.WithFields(logrus.Fields{"subsystem": "echo"}).Info(string(p)) // naively log everything as string message.
// return len(p), nil
//}
//
// func (l *LogrusLogger) Error(err error) {
// l.logger.WithFields(logrus.Fields{"subsystem": "echo"}).Error(err)
//}
// Logger defines the logging interface that Echo uses internally in few places.
// For logging in handlers use your own logger instance (dependency injected or package/public variable) from logging framework of your choice.
type Logger interface {
// Write provides writer interface for http.Server `ErrorLog` and for logging startup messages.
// `http.Server.ErrorLog` logs errors from accepting connections, unexpected behavior from handlers,
// and underlying FileSystem errors.
// `logger` middleware will use this method to write its JSON payload.
Write(p []byte) (n int, err error)
// Error logs the error
Error(err error)
}
// jsonLogger is similar logger formatting implementation as `v4` had. It is not particularly fast or efficient. Only
// goal it to exist is to have somewhat backwards compatibility with `v4` for Echo internals logging formatting.
// It is not meant for logging in handlers/middlewares. Use some real logging library for those cases.
type jsonLogger struct {
writer io.Writer
bufferPool sync.Pool
lock sync.Mutex
timeNow func() time.Time
}
func newJSONLogger(writer io.Writer) *jsonLogger {
return &jsonLogger{
writer: writer,
bufferPool: sync.Pool{
New: func() interface{} {
return bytes.NewBuffer(make([]byte, 256))
},
},
timeNow: time.Now,
}
}
func (l *jsonLogger) Write(p []byte) (n int, err error) {
pLen := len(p)
if pLen >= 2 && // naively try to avoid JSON values to be wrapped into message
(p[0] == '{' && p[pLen-2] == '}' && p[pLen-1] == '\n') ||
(p[0] == '{' && p[pLen-1] == '}') {
return l.write(p)
}
// we log with WARN level as we have no idea what that message level should be. From Echo perspective this method is
// called when we pass Echo logger to http.Server.ErrorLog and there are problems inside http.Server - which probably
// deserves at least WARN level.
return l.printf("INFO", string(p))
}
func (l *jsonLogger) Error(err error) {
_, _ = l.printf("ERROR", err.Error())
}
func (l *jsonLogger) printf(level string, message string) (n int, err error) {
buf := l.bufferPool.Get().(*bytes.Buffer)
buf.Reset()
defer l.bufferPool.Put(buf)
buf.WriteString(`{"time":"`)
buf.WriteString(l.timeNow().Format(time.RFC3339Nano))
buf.WriteString(`","level":"`)
buf.WriteString(level)
buf.WriteString(`","prefix":"echo","message":`)
buf.WriteString(strconv.Quote(message))
buf.WriteString("}\n")
return l.write(buf.Bytes())
}
func (l *jsonLogger) write(p []byte) (int, error) {
l.lock.Lock()
defer l.lock.Unlock()
return l.writer.Write(p)
}