当前位置:网站首页>golang : Zap日志整合
golang : Zap日志整合
2022-07-30 05:51:00 【行人已】
1、目录结构
项目名称
--------------main.go
--------------setting.json
--------------common
------------------------common/log
------------------------common/log/log_def.go
------------------------common/log/log_instance.go
2、获取Zap资源库
go get -u go.uber.org/zap
go get -u github.com/natefinch/lumberjack
import "go.uber.org/zap"
3、log_def.go 实现(主要是实现日志需要的属性)
import (
"os"
"path/filepath"
"sync"
"time"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
type Options struct {
LogFileDir string //文件保存地方
AppName string //日志文件前缀
ErrorFileName string
WarnFileName string
InfoFileName string
DebugFileName string
Level zapcore.Level //日志等级
MaxSize int //日志文件小大(M)
MaxBackups int // 最多存在多少个切片文件
MaxAge int //保存的最大天数
Development bool //是否是开发模式
zap.Config
}
type ModOptions func(options *Options)
var (
l *Logger
sp = string(filepath.Separator)
errWS, warnWS, infoWS, debugWS zapcore.WriteSyncer // IO输出
debugConsoleWS = zapcore.Lock(os.Stdout) // 控制台标准输出
errorConsoleWS = zapcore.Lock(os.Stderr)
)
type Logger struct {
*zap.Logger
sync.RWMutex
Opts *Options `json:"opts"`
zapConfig zap.Config
initialized bool
}
func NewLogger(mod ...ModOptions) *zap.Logger {
l = &Logger{}
l.Lock()
defer l.Unlock()
if l.initialized {
l.Info("[NewLogger] logger initEd")
return nil
}
l.Opts = &Options{
LogFileDir: "",
AppName: "app",
ErrorFileName: "error.log",
WarnFileName: "warn.log",
InfoFileName: "info.log",
DebugFileName: "debug.log",
Level: zapcore.DebugLevel,
MaxSize: 100,
MaxBackups: 60,
MaxAge: 30,
Development: true,
}
if l.Opts.LogFileDir == "" {
l.Opts.LogFileDir, _ = filepath.Abs(filepath.Dir(filepath.Join(".")))
l.Opts.LogFileDir += sp + "logs" + sp
}
if l.Opts.Development {
l.zapConfig = zap.NewDevelopmentConfig()
l.zapConfig.EncoderConfig.EncodeTime = timeEncoder
} else {
l.zapConfig = zap.NewProductionConfig()
// l.zapConfig.EncoderConfig.EncodeTime = timeUnixNano
l.zapConfig.EncoderConfig.EncodeTime = timeEncoder
}
if l.Opts.OutputPaths == nil || len(l.Opts.OutputPaths) == 0 {
l.zapConfig.OutputPaths = []string{"stdout"}
}
if l.Opts.ErrorOutputPaths == nil || len(l.Opts.ErrorOutputPaths) == 0 {
l.zapConfig.OutputPaths = []string{"stderr"}
}
for _, fn := range mod {
fn(l.Opts)
}
l.zapConfig.Level.SetLevel(l.Opts.Level)
l.init()
l.initialized = true
return l.Logger
}
func (l *Logger) init() {
l.setSyncs()
var err error
l.Logger, err = l.zapConfig.Build(l.cores())
if err != nil {
panic(err)
}
defer l.Logger.Sync()
}
func (l *Logger) setSyncs() {
//切割日志
f := func(fN string) zapcore.WriteSyncer {
return zapcore.AddSync(&lumberjack.Logger{
Filename: l.Opts.LogFileDir + sp + l.Opts.AppName + "-" + fN,
MaxSize: l.Opts.MaxSize,
MaxBackups: l.Opts.MaxBackups,
MaxAge: l.Opts.MaxAge,
Compress: true,
LocalTime: true,
})
}
errWS = f(l.Opts.ErrorFileName)
warnWS = f(l.Opts.WarnFileName)
infoWS = f(l.Opts.InfoFileName)
debugWS = f(l.Opts.DebugFileName)
return
}
func SetMaxSize(MaxSize int) ModOptions {
return func(option *Options) {
option.MaxSize = MaxSize
}
}
func SetMaxBackups(MaxBackups int) ModOptions {
return func(option *Options) {
option.MaxBackups = MaxBackups
}
}
func SetMaxAge(MaxAge int) ModOptions {
return func(option *Options) {
option.MaxAge = MaxAge
}
}
func SetLogFileDir(LogFileDir string) ModOptions {
return func(option *Options) {
option.LogFileDir = LogFileDir
}
}
func SetAppName(AppName string) ModOptions {
return func(option *Options) {
option.AppName = AppName
}
}
func SetLevel(Level zapcore.Level) ModOptions {
return func(option *Options) {
option.Level = Level
}
}
func SetErrorFileName(ErrorFileName string) ModOptions {
return func(option *Options) {
option.ErrorFileName = ErrorFileName
}
}
func SetWarnFileName(WarnFileName string) ModOptions {
return func(option *Options) {
option.WarnFileName = WarnFileName
}
}
func SetInfoFileName(InfoFileName string) ModOptions {
return func(option *Options) {
option.InfoFileName = InfoFileName
}
}
func SetDebugFileName(DebugFileName string) ModOptions {
return func(option *Options) {
option.DebugFileName = DebugFileName
}
}
func SetDevelopment(Development bool) ModOptions {
return func(option *Options) {
option.Development = Development
}
}
func (l *Logger) cores() zap.Option {
//将JSON Encoder更改为普通的Log Encoder : NewConsoleEncoder
// fileEncoder := zapcore.NewJSONEncoder(l.zapConfig.EncoderConfig)
fileEncoder := zapcore.NewConsoleEncoder(l.zapConfig.EncoderConfig)
encoderConfig := zap.NewDevelopmentEncoderConfig()
encoderConfig.EncodeTime = timeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
errPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl == zapcore.ErrorLevel && zapcore.ErrorLevel-l.zapConfig.Level.Level() > -1
})
warnPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl == zapcore.WarnLevel && zapcore.WarnLevel-l.zapConfig.Level.Level() > -1
})
infoPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl == zapcore.InfoLevel && zapcore.InfoLevel-l.zapConfig.Level.Level() > -1
})
debugPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl == zapcore.DebugLevel && zapcore.DebugLevel-l.zapConfig.Level.Level() > -1
})
cores := []zapcore.Core{
zapcore.NewCore(fileEncoder, errWS, errPriority),
zapcore.NewCore(fileEncoder, warnWS, warnPriority),
zapcore.NewCore(fileEncoder, infoWS, infoPriority),
zapcore.NewCore(fileEncoder, debugWS, debugPriority),
}
if l.Opts.Development {
cores = append(cores, []zapcore.Core{
zapcore.NewCore(consoleEncoder, errorConsoleWS, errPriority),
zapcore.NewCore(consoleEncoder, debugConsoleWS, warnPriority),
zapcore.NewCore(consoleEncoder, debugConsoleWS, infoPriority),
zapcore.NewCore(consoleEncoder, debugConsoleWS, debugPriority),
}...)
}
return zap.WrapCore(func(c zapcore.Core) zapcore.Core {
return zapcore.NewTee(cores...)
})
}
func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02 15:04:05"))
}
func timeUnixNano(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendInt64(t.UnixNano() / 1e6)
}
3.1、setSyncs函数解释:
Zap本身不支持切割归档日志文件为了添加日志切割归档功能,我们使用第三方库Lumberjack来实现的
f := func(fN string) zapcore.WriteSyncer {
return zapcore.AddSync(&lumberjack.Logger{
Filename: l.Opts.LogFileDir + sp + l.Opts.AppName + "-" + fN, //日志文件的位置
MaxSize: l.Opts.MaxSize, //在进行切割之前,日志文件的最大大小(以MB为单位)
MaxBackups: l.Opts.MaxBackups, //保留旧文件的最大个数
MaxAge: l.Opts.MaxAge, //保留旧文件的最大天数
Compress: true, //是否压缩/归档旧文件
LocalTime: true, //LocalTime 确定用于格式化时间戳的时间
})
}
4、log_instance.go 实现(实现读取setting中日志配置,初始化zap)
viper 是读取配置文件的库,非常好用,不知道可以去看看
NewLogger 是初始化zap配置
import (
"fmt"
"github.com/spf13/viper"
"go.uber.org/zap"
)
var logger *zap.Logger
// log instance init
func InitLog() {
level := viper.GetString(`log.level`)
logLevel := zap.DebugLevel
if "debug" == level {
logLevel = zap.DebugLevel
}
if "info" == level {
logLevel = zap.InfoLevel
}
if "error" == level {
logLevel = zap.ErrorLevel
}
if "warn" == level {
logLevel = zap.WarnLevel
}
fmt.Println("日志级别", logLevel)
logger = NewLogger(
SetAppName(viper.GetString("log.appName")),
SetDevelopment(viper.GetBool("log.development")),
SetDebugFileName(viper.GetString("log.debugFileName")),
SetErrorFileName(viper.GetString("log.errorFileName")),
SetInfoFileName(viper.GetString("log.infoFileName")),
SetMaxAge(viper.GetInt("log.maxAge")),
SetMaxBackups(viper.GetInt("log.maxBackups")),
SetMaxSize(viper.GetInt("log.maxSize")),
SetLevel(zap.DebugLevel),
)
}
func GetLogger() *zap.Logger {
return logger
}
5、main.go 实现
func main() {
VipInit()
//初始化日志
log.InitLog()
}
func VipInit() {
// viper.SetConfigName("config1") // 读取yaml配置文件
viper.SetConfigName("setting") // 读取json配置文件
//viper.AddConfigPath("/etc/appname/") //设置配置文件的搜索目录
//viper.AddConfigPath("$HOME/.appname") // 设置配置文件的搜索目录
viper.AddConfigPath(".") // 设置配置文件和可执行二进制文件在用一个目录
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Config file not found; ignore error if desired
fmt.Println("no such config file")
} else {
// Config file was found but another error was produced
fmt.Println("read config error")
}
// 读取配置文件失败致命错误
fmt.Errorf(err.Error())
}
}
6、setting.json 实现
字段意思可在:Options 中查看
{
"log": {
"level" : "info",
"appName": "test",
"development": false,
"debugFileName": "debug.log",
"errorFileName": "warn.log",
"infoFileName": "info.log",
"maxAge": "7",
"maxBackups": "30",
"maxSize": "100"
}
}
7、最终效果

所有代码已放到: https://gitee.com/hjx_RuGuoYunZhiDao/strom-huang-go/tree/master/go_zap
边栏推荐
猜你喜欢
随机推荐
大飞机C919都用了哪些新材料?
Selenium01
舒尔补(schur completement)
iptables命令
Software Testing Terminology - Scenario Testing
New material under the plastic restriction order - polylactic acid (PLA)
Electron日常学习笔记
人工肌肉智能材料新突破
不会吧,Log4j 漏洞还没有完全修复?
如何理解普吕克坐标(几何理解)
【MySQL】MySQL中如何实现分页操作
Oracle查看表空间使用率及爆满解决方案
UDP和TCP使用同一个端口,可行吗?
Station B collapsed, what would you do if you were the developer in charge that night?
2020 数学建模之旅
The calculation proof of the intersection of the space line and the plane and its source code
空间平面相交的直线的计算及其源码
Equation Derivation Proof of Vector Triple Product
(GGG)JWT
CTO说不建议我使用SELECT * ,这是为什么?









