手把手,带你从零封装Gin框架(三):日志初始化

项目源码

地址: github.com/jassue/jass…

前言

本篇来讲一下怎么将日志服务集成到项目中,它也是框架中必不可少的,平时代码调试,线上 Bug 分析都离不开它。这里将使用 zap 作为日志库,一般来说,日志都是需要写入到文件保存的,这也是 zap 唯一缺少的部分,所以我将结合 lumberjack 来使用,实现日志切割归档的功能

安装

1
2
3
shell复制代码go get -u go.uber.org/zap

go get -u gopkg.in/natefinch/lumberjack.v2

定义日志配置项

新建 config/log.go 文件,定义 zaplumberjack 初始化需要使用的配置项,大家可以根据自己的喜好去定制

1
2
3
4
5
6
7
8
9
10
11
12
13
go复制代码package config

type Log struct {
Level string `mapstructure:"level" json:"level" yaml:"level"`
RootDir string `mapstructure:"root_dir" json:"root_dir" yaml:"root_dir"`
Filename string `mapstructure:"filename" json:"filename" yaml:"filename"`
Format string `mapstructure:"format" json:"format" yaml:"format"`
ShowLine bool `mapstructure:"show_line" json:"show_line" yaml:"show_line"`
MaxBackups int `mapstructure:"max_backups" json:"max_backups" yaml:"max_backups"`
MaxSize int `mapstructure:"max_size" json:"max_size" yaml:"max_size"` // MB
MaxAge int `mapstructure:"max_age" json:"max_age" yaml:"max_age"` // day
Compress bool `mapstructure:"compress" json:"compress" yaml:"compress"`
}

config/config.go 添加 Log 成员属性

1
2
3
4
5
6
go复制代码package config

type Configuration struct {
App App `mapstructure:"app" json:"app" yaml:"app"`
Log Log `mapstructure:"log" json:"log" yaml:"log"`
}

config.yaml 增加对应配置项

1
2
3
4
5
6
7
8
9
10
yaml复制代码log:
level: info # 日志等级
root_dir: ./storage/logs # 日志根目录
filename: app.log # 日志文件名称
format: # 写入格式 可选json
show_line: true # 是否显示调用行
max_backups: 3 # 旧文件的最大个数
max_size: 500 # 日志文件最大大小(MB)
max_age: 28 # 旧文件的最大保留天数
compress: true # 是否压缩

定义 utils 工具函数

新建 utils/directory.go 文件,编写 PathExists 函数,用于判断路径是否存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
go复制代码package utils

import "os"

func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}

初始化 zap

zap 的具体使用说明可查看官方文档

新建 bootstrap/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
go复制代码package bootstrap

import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
"jassue-gin/global"
"jassue-gin/utils"
"os"
"time"
)

var (
level zapcore.Level // zap 日志等级
options []zap.Option // zap 配置项
)

func InitializeLog() *zap.Logger {
// 创建根目录
createRootDir()

// 设置日志等级
setLogLevel()

if global.App.Config.Log.ShowLine {
options = append(options, zap.AddCaller())
}

// 初始化 zap
return zap.New(getZapCore(), options...)
}

func createRootDir() {
if ok, _ := utils.PathExists(global.App.Config.Log.RootDir); !ok {
_ = os.Mkdir(global.App.Config.Log.RootDir, os.ModePerm)
}
}

func setLogLevel() {
switch global.App.Config.Log.Level {
case "debug":
level = zap.DebugLevel
options = append(options, zap.AddStacktrace(level))
case "info":
level = zap.InfoLevel
case "warn":
level = zap.WarnLevel
case "error":
level = zap.ErrorLevel
options = append(options, zap.AddStacktrace(level))
case "dpanic":
level = zap.DPanicLevel
case "panic":
level = zap.PanicLevel
case "fatal":
level = zap.FatalLevel
default:
level = zap.InfoLevel
}
}

// 扩展 Zap
func getZapCore() zapcore.Core {
var encoder zapcore.Encoder

// 调整编码器默认配置
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = func(time time.Time, encoder zapcore.PrimitiveArrayEncoder) {
encoder.AppendString(time.Format("[" + "2006-01-02 15:04:05.000" + "]"))
}
encoderConfig.EncodeLevel = func(l zapcore.Level, encoder zapcore.PrimitiveArrayEncoder) {
encoder.AppendString(global.App.Config.App.Env + "." + l.String())
}

// 设置编码器
if global.App.Config.Log.Format == "json" {
encoder = zapcore.NewJSONEncoder(encoderConfig)
} else {
encoder = zapcore.NewConsoleEncoder(encoderConfig)
}

return zapcore.NewCore(encoder, getLogWriter(), level)
}

// 使用 lumberjack 作为日志写入器
func getLogWriter() zapcore.WriteSyncer {
file := &lumberjack.Logger{
Filename: global.App.Config.Log.RootDir + "/" + global.App.Config.Log.Filename,
MaxSize: global.App.Config.Log.MaxSize,
MaxBackups: global.App.Config.Log.MaxBackups,
MaxAge: global.App.Config.Log.MaxAge,
Compress: global.App.Config.Log.Compress,
}

return zapcore.AddSync(file)
}

定义全局变量 Log

global/app.go 中,添加 Log 成员属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
go复制代码package global

import (
"github.com/spf13/viper"
"go.uber.org/zap"
"jassue-gin/config"
)

type Application struct {
ConfigViper *viper.Viper
Config config.Configuration
Log *zap.Logger
}

var App = new(Application)

测试

main.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
go复制代码package main

import (
"github.com/gin-gonic/gin"
"jassue-gin/bootstrap"
"jassue-gin/global"
"net/http"
)

func main() {
// 初始化配置
bootstrap.InitializeConfig()

// 初始化日志
global.App.Log = bootstrap.InitializeLog()
global.App.Log.Info("log init success!")

r := gin.Default()

// 测试路由
r.GET("/ping", func(c *gin.Context) {
c.String(http.StatusOK, "pong")
})

// 启动服务器
r.Run(":" + global.App.Config.App.Port)
}

启动 main.go ,生成 storage/logs/app.log 文件,表示日志初始化成功,文件内容显示如下:

1
bash复制代码[2021-10-12 19:17:46.997]	local.info	jassue-gin/main.go:16	log init success!

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%