lumberjack
实现日志归档功能项目根目录下,新建log
目录,新建log.go
和constant.go
,配置如下:
package log
import (
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
)
// 设置日志级别、输出格式和日志文件的路径
func SetLogs(logLevel zapcore.Level, logFormat, fileName string) {
encoderConfig := zapcore.EncoderConfig{
TimeKey: TIME_KEY,
LevelKey: LEVLE_KEY,
NameKey: NAME_KEY,
CallerKey: CALLER_KEY,
MessageKey: MESSAGE_KEY,
StacktraceKey: STACKTRACE_KEY,
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder, // 大写编码器
EncodeTime: zapcore.ISO8601TimeEncoder, // ISO8601 UTC 时间格式
EncodeDuration: zapcore.SecondsDurationEncoder, //
EncodeCaller: zapcore.ShortCallerEncoder, // 短路径编码器(相对路径+行号)
EncodeName: zapcore.FullNameEncoder,
}
// 设置日志输出格式
var encoder zapcore.Encoder
switch logFormat {
case LOGFORMAT_JSON:
encoder = zapcore.NewJSONEncoder(encoderConfig)
default:
encoder = zapcore.NewConsoleEncoder(encoderConfig)
}
// 添加日志切割归档功能
hook := lumberjack.Logger{
Filename: fileName, // 日志文件路径
MaxSize: MAX_SIZE, // 每个日志文件保存的最大尺寸 单位:M
MaxBackups: MAX_BACKUPS, // 日志文件最多保存多少个备份
MaxAge: MAX_AGE, // 文件最多保存多少天
Compress: true, // 是否压缩
}
core := zapcore.NewCore(
encoder, // 编码器配置
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stderr), zapcore.AddSync(&hook)), // 打印到控制台和文件
zap.NewAtomicLevelAt(logLevel), // 日志级别
)
// 开启文件及行号
caller := zap.AddCaller()
// 开启开发模式,堆栈跟踪
development := zap.Development()
// 构造日志
logger := zap.New(core, caller, development)
// 将自定义的logger替换为全局的logger
zap.ReplaceGlobals(logger)
}
constant.go
中是一些自定义的常量,可根据自己实际情况适当修改。
package log
const (
// logFormat
LOGFORMAT_JSON = "json"
LOGFORMAT_CONSOLE = "console"
// EncoderConfig
TIME_KEY = "time"
LEVLE_KEY = "level"
NAME_KEY = "logger"
CALLER_KEY = "caller"
MESSAGE_KEY = "msg"
STACKTRACE_KEY = "stacktrace"
// 日志归档配置项
// 每个日志文件保存的最大尺寸 单位:M
MAX_SIZE = 1
// 文件最多保存多少天
MAX_BACKUPS = 5
// 日志文件最多保存多少个备份
MAX_AGE = 7
)
Gin
路由初始化及引入zap
日志框架项目根目录下,新建router
目录并进入该目录,新建router.go
,配置如下:
package router
import (
"fmt"
"github.com/gin-contrib/zap"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"time"
)
func InitRoutes() *gin.Engine {
engine := gin.New()
// 使用zap日志库
engine.Use(ginzap.Ginzap(zap.L(), time.RFC3339, true))
engine.Use(ginzap.RecoveryWithZap(zap.L(), true))
g := engine.Group("/api/v1")
{
// Example ping request.
g.GET("/hello", func(c *gin.Context) {
c.String(200, "hello world !!! "+fmt.Sprint(time.Now().Format("2006-01-2 15:04:05")))
})
// Example when panic happen.
g.GET("/panic", func(c *gin.Context) {
panic("An unexpected error happen!")
})
}
return engine
}
main.go
中调用SetLogs
和InitRoutes
,使自定义的日志配置和路由生效package main
import (
"gin-example/log"
"gin-example/router"
"go.uber.org/zap"
)
func init() {
// 初始化日志库
log.SetLogs(zap.DebugLevel, log.LOGFORMAT_CONSOLE, "./log/gin-example.log")
}
func main() {
r := router.InitRoutes()
if err := r.Run(":8888"); err != nil {
zap.L().Fatal("HTTP Server启动失败", zap.Error(err))
}
}
go mod
拉取相关依赖并启动服务$ go mod init gin-example
$ go mod tidy
$ go run main.go
# 打开新的终端访问相应的url
$ curl localhost:8888/api/v1/hello
hello world !!! 2020-05-6 22:56:11
# main.go 打印的日志信息
$ go run main.go
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /api/v1/hello --> gin-example/router.InitRoutes.func1 (3 handlers)
[GIN-debug] GET /api/v1/panic --> gin-example/router.InitRoutes.func2 (3 handlers)
[GIN-debug] Listening and serving HTTP on :8888
2020-05-06T22:56:11.799+0800 INFO [email protected]/zap.go:46 /api/v1/hello {"status": 200, "method": "GET", "path": "/api/v1/hello", "query": "", "ip": "127.0.0.1", "user-agent": "curl/7.58.0", "time": "2020-05-06T14:56:11Z", "latency": 0.000035822}