-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.go
234 lines (218 loc) · 6.85 KB
/
config.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
234
package zlog
import (
"fmt"
"github.com/luxun9527/zlog/report"
"github.com/mitchellh/mapstructure"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
"log"
"net/http"
"os"
"reflect"
"sync"
"time"
)
const (
// _defaultBufferSize specifies the default size used by Buffer.
_defaultBufferSize = 256 * 1024 // 256 kB
// _defaultFlushInterval specifies the default flush interval for
// Buffer.
_defaultFlushInterval = 30 * time.Second
)
const (
_file = "file"
_console = "console"
)
var (
_once sync.Once
)
type Config struct {
Name string `json:",optional" mapstructure:"name"`
//日志级别 debug info warn panic
Level zap.AtomicLevel `json:"Level" mapstructure:"level"`
//在panic级别的时候 是否显示堆栈
Stacktrace bool `json:",default=true" mapstructure:"stacktrace"`
//添加调用者信息
AddCaller bool `json:",default=true" mapstructure:"addCaller"`
//调用链,往上多少级 ,在一些中间件,对日志有包装,可以通过这个选项指定。
CallerShip int `json:",default=3" mapstructure:"callerShip"`
//输出到哪里标准输出console,还是文件file
Mode string `json:",default=console" mapstructure:"mode"`
//文件名称加路径
FileName string `json:",optional" mapstructure:"filename"`
//error级别的日志输入到不同的地方,默认console 输出到标准错误输出,file可以指定文件
ErrorFileName string `json:",optional" mapstructure:"errorFileName"`
// 单个日志文件大小 单位MB 默认100MB
MaxSize int `json:",optional" mapstructure:"maxSize"`
//日志保留天数
MaxAge int `json:",optional" mapstructure:"maxAge"`
//日志最大保留的个数
MaxBackup int `json:",optional" mapstructure:"maxBackUp"`
//异步日志 日志将先输入到内存到,定时批量落盘。如果设置这个值,要保证在程序退出的时候调用Sync(),在开发阶段不用设置为true。
Async bool `json:",optional" mapstructure:"async"`
//是否输出json格式
Json bool `json:",optional" mapstructure:"json"`
//是否日志压缩
Compress bool `json:",optional" mapstructure:"compress"`
// file 模式是否输出到控制台
Console bool `json:"console" mapstructure:"console"`
// 非json格式,是否加上颜色。
Color bool `json:",default=true" mapstructure:"color"`
Port int32 `json:",default=true" mapstructure:"port"`
//report配置
ReportConfig *report.ReportConfig `json:",optional" mapstructure:"reportConfig"`
options []zap.Option
}
func (lc *Config) UpdateLevel(level zapcore.Level) {
lc.Level.SetLevel(level)
}
func (lc *Config) Build() *zap.Logger {
if lc.Mode != _file && lc.Mode != _console {
log.Panicln("mode must be console or file")
}
if lc.Mode == _file && lc.FileName == "" {
log.Panicln("file mode, but file name is empty")
}
var (
ws zapcore.WriteSyncer
errorWs zapcore.WriteSyncer
encoder zapcore.Encoder
)
encoderConfig := zapcore.EncoderConfig{
//当存储的格式为JSON的时候这些作为可以key
MessageKey: "msg",
LevelKey: "level",
TimeKey: "time",
NameKey: "logger",
CallerKey: "caller",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
//以上字段输出的格式
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: CustomTimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.FullCallerEncoder,
}
if lc.Mode == _console {
ws = zapcore.Lock(os.Stdout)
} else {
normalConfig := &lumberjack.Logger{
Filename: lc.FileName,
MaxSize: lc.MaxSize,
MaxAge: lc.MaxAge,
MaxBackups: lc.MaxBackup,
LocalTime: true,
Compress: lc.Compress,
}
if lc.ErrorFileName != "" {
errorConfig := &lumberjack.Logger{
Filename: lc.ErrorFileName,
MaxSize: lc.MaxSize,
MaxAge: lc.MaxAge,
MaxBackups: lc.MaxBackup,
LocalTime: true,
Compress: lc.Compress,
}
errorWs = zapcore.Lock(zapcore.AddSync(errorConfig))
}
ws = zapcore.Lock(zapcore.AddSync(normalConfig))
}
//是否加上颜色。
if lc.Color && !lc.Json {
encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
}
encoder = zapcore.NewConsoleEncoder(encoderConfig)
if lc.Json {
encoder = zapcore.NewJSONEncoder(encoderConfig)
}
if lc.Async {
ws = &zapcore.BufferedWriteSyncer{
WS: ws,
Size: _defaultBufferSize,
FlushInterval: _defaultFlushInterval,
}
if errorWs != nil {
errorWs = &zapcore.BufferedWriteSyncer{
WS: errorWs,
Size: _defaultBufferSize,
FlushInterval: _defaultFlushInterval,
}
}
}
var c = []zapcore.Core{zapcore.NewCore(encoder, ws, lc.Level)}
if errorWs != nil {
highCore := zapcore.NewCore(encoder, errorWs, zapcore.ErrorLevel)
c = append(c, highCore)
}
//文件模式同时输出到控制台
if lc.Mode == _file && lc.Console {
consoleWs := zapcore.NewCore(encoder, zapcore.Lock(os.Stdout), zapcore.ErrorLevel)
c = append(c, consoleWs)
}
if lc.ReportConfig != nil {
//上报的格式一律json
if !lc.Json {
encoderConfig.EncodeLevel = zapcore.LowercaseLevelEncoder
encoder = zapcore.NewJSONEncoder(encoderConfig)
}
emptyLevel := zap.AtomicLevel{}
if lc.ReportConfig.Level == emptyLevel {
lc.ReportConfig.Level = zap.NewAtomicLevelAt(zap.WarnLevel)
}
//指定级别的日志上报。
reportCore := zapcore.NewCore(encoder, report.NewReportWriterBuffer(lc.ReportConfig), lc.ReportConfig.Level)
c = append(c, reportCore)
}
core := zapcore.NewTee(c...)
logger := zap.New(core)
//是否新增调用者信息
if lc.AddCaller {
lc.options = append(lc.options, zap.AddCaller())
if lc.CallerShip != 0 {
lc.options = append(lc.options, zap.AddCallerSkip(lc.CallerShip))
}
}
//当错误时是否添加堆栈信息
if lc.Stacktrace {
lc.options = append(lc.options, zap.AddStacktrace(zap.PanicLevel))
}
if lc.Name != "" {
logger = logger.With(zap.String("project", lc.Name))
}
logger = logger.WithOptions(lc.options...)
if lc.Port > 0 {
lc.InitLogServer(lc.Port)
logger.Sugar().Infof("log server init success,port:%d", lc.Port)
}
return logger
}
func (lc *Config) InitLogServer(port int32) {
go func(p int32) {
_once.Do(func() {
if err := http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", p), lc.Level); err != nil {
zap.S().Error("init log server start failed", zap.Error(err))
}
})
}(port)
}
func CustomTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02-15:04:05"))
}
// StringToLogLevelHookFunc viper的string转zapcore.Level
func StringToLogLevelHookFunc() mapstructure.DecodeHookFunc {
return func(
f reflect.Type,
t reflect.Type,
data interface{}) (interface{}, error) {
if f.Kind() != reflect.String {
return data, nil
}
atomicLevel, err := zap.ParseAtomicLevel(data.(string))
if err != nil {
return data, nil
}
// Convert it by parsing
return atomicLevel, nil
}
}