上篇文章,我们已经给项目加上了路由,并且走通了接口,这篇文章我们再给项目加上一项必不可少的内容 —— 日志.
目前go的日志记录,用的最多的还是 logrus, 我们这次就将logrus以一个中间件的方式,引入我们的项目。
第一步 引入logrus
logrus项目的git地址: https://github.com/sirupsen/logrus ,
go get -u github.com/sirupsen/logrus
第二步 增加日志配置读取逻辑
在根目录创建配置文件夹,并创建配置文件config.yaml,以及配置解析文件conf.go
mkdir conf
./conf/config.yaml :
log: # 日志配置 # 日志路径 dir: "./log"
./conf/conf.go :
package conf import ( "gopkg.in/yaml.v3" "io/ioutil" ) var BaseConf Config type LogConf struct { Dir string `yaml:"dir"` } type Config struct { Log LogConf `yaml:"log"` } func InitConf() { confPath := "./conf/config.yaml" if yamlFile, err := ioutil.ReadFile(confPath); err != nil { panic("read conf error: " + err.Error()) } else if err = yaml.Unmarshal(yamlFile, &BaseConf); err != nil { panic("conf file unmarshal error: " + err.Error()) } }
注意: ioutil.ReadFile(),可以是相对路径,也可以是绝对路径,但相对路径的话,./ 指的是根目录,跟当前文件所在目录无关
第四步 初始化配置
在main函数中,初始化配置 ./main.go :
package main import ( "fusheng-admin/conf" "fusheng-admin/router" "github.com/gin-gonic/gin" ) func main() { // 1.创建路由 r := gin.Default() // 初始化配置 conf.InitConf() // 2.绑定路由规则,执行的函数 // gin.Context,封装了request和response router.Http(r) // 3.监听端口,默认在8080 // Run("里面不指定端口号默认为8088") r.Run(":8088") }
第四步 封装logrus
创建log封装文件 ./library/log/log.go
mkdir library/log
library/log/log.go
package log import ( "fmt" "github.com/sirupsen/logrus" "os" "path" "fusheng-admin/conf" ) func init() { // 设置日志格式为json格式 logrus.SetFormatter(&logrus.JSONFormatter{ TimestampFormat: "2006-01-02 15:04:05", }) logrus.SetReportCaller(true) } func Debug(fields logrus.Fields, args ...interface{}) { setOutPutFile(logrus.DebugLevel) logrus.WithFields(fields).Debug(args) } func Info(fields logrus.Fields, args ...interface{}) { setOutPutFile(logrus.InfoLevel) logrus.WithFields(fields).Info(args) } func Warn(fields logrus.Fields, args ...interface{}) { setOutPutFile(logrus.WarnLevel) logrus.WithFields(fields).Warn(args) } func Fatal(fields logrus.Fields, args ...interface{}) { setOutPutFile(logrus.FatalLevel) logrus.WithFields(fields).Fatal(args) } func Error(fields logrus.Fields, args ...interface{}) { setOutPutFile(logrus.ErrorLevel) logrus.WithFields(fields).Error(args) } func Panic(fields logrus.Fields, args ...interface{}) { setOutPutFile(logrus.PanicLevel) logrus.WithFields(fields).Panic(args) } func Trace(fields logrus.Fields, args ...interface{}) { setOutPutFile(logrus.TraceLevel) logrus.WithFields(fields).Trace(args) } func setOutPutFile(level logrus.Level) { if _, err := os.Stat(conf.BaseConf.Log.Dir); os.IsNotExist(err) { err = os.MkdirAll(conf.BaseConf.Log.Dir, 0777) if err != nil { panic(fmt.Errorf("create log dir '%s' error: %s", conf.BaseConf.Log.Dir, err)) } } name := "" switch level { case logrus.DebugLevel: name = "debug" case logrus.InfoLevel: name = "info" case logrus.WarnLevel: name = "warn" case logrus.FatalLevel: name = "fatal" case logrus.ErrorLevel: name = "error" case logrus.PanicLevel: name = "panic" case logrus.TraceLevel: name = "trace" default: panic(fmt.Errorf("invaild log level error %d", logrus.ErrorLevel)) } fileName := path.Join(conf.BaseConf.Log.Dir, name + ".log") var err error os.Stderr, err = os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) if err != nil { fmt.Println("open log file err", err) } logrus.SetOutput(os.Stderr) logrus.SetLevel(level) return }
第五步 创建log中间件
通过创建log中间件,是框架能够自动的记录请求前后的一些信息,便于日志追查。
创建中间件文件, ./library/middleware/logger.go
mkdir library/middleware
library/middleware/logger.go
package middleware import ( "bytes" "github.com/gin-gonic/gin" "io/ioutil" "time" "word-dect-go/library/log" ) func LoggerToFile() gin.HandlerFunc { return func(ctx *gin.Context) { // 开始时间 start := time.Now() // 请求报文 var requestBody []byte if ctx.Request.Body != nil { var err error requestBody, err = ctx.GetRawData() if err != nil { log.Warn(map[string]interface{}{"err": err.Error()}, "get http request body error") } ctx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(requestBody)) } // 处理请求 ctx.Next() // 结束时间 end := time.Now() log.Info(map[string]interface{}{ "statusCode": ctx.Writer.Status(), "cost": float64(end.Sub(start).Nanoseconds()/1e4) / 100.0, "clientIp": ctx.ClientIP(), "method": ctx.Request.Method, "uri": ctx.Request.RequestURI, }) } }
第六步 引入中间件
r.Use(middleware.LoggerToFile())
./main.go :
package main import ( "fusheng-admin/conf" "fusheng-admin/library/middleware" "fusheng-admin/router" "github.com/gin-gonic/gin" ) func main() { // 1.创建路由 r := gin.Default() r.Use(middleware.LoggerToFile()) // 初始化配置 conf.InitConf() // 2.绑定路由规则,执行的函数 // gin.Context,封装了request和response router.Http(r) // 3.监听端口,默认在8080 // Run("里面不指定端口号默认为8088") r.Run(":8088") }
第七步 常规调用
./service/user.go : (我们增加个接口参数name, 并将其打印到日志)
// 请求参数结构体 type UserRequestParams struct { Name string `json:"name"` Ctx *gin.Context } func UserAdd(param *UserRequestParams, responseBody *library.ResponseBody) { log.Info(map[string]interface{}{"name": param.Name}) return }
第七步 接口调用,查看日志
curl -H "Content-Type: application/json;" -X POST "http://127.0.0.1:8088/api/v1/useradd" -d '{"name":"user1"}'
可以看到,根目录下自动创建了 ./log 目录,且生成了日志文件info.log :
{"file":"/Users/ethanxu/Ethan/Work/other/fusheng-admin/library/log/log.go:26","func":"fusheng-admin/library/log.Info","level":"info","msg":"[]","name":"user1","time":"2021-06-28 20:46:09"} {"clientIp":"127.0.0.1","cost":1.3,"file":"/Users/ethanxu/Ethan/Work/other/fusheng-admin/library/log/log.go:26","func":"fusheng-admin/library/log.Info","level":"info","method":"POST","msg":"[]","statusCode":200,"time":"2021-06-28 20:46:09","uri":"/api/v1/useradd"}
至此,我们的项目就可以方便的使用日志啦!
ps: 日志相关我们并不需要上传至git,所以可以添加.gitignore文件,这样git就会忽略掉日志文件了。该文件可以自行定义,不需要上传至git的文件/文件夹都可以在这里进行配置。(.gitignore文件本身记得上传至git哦~) (bin 为之前创建的编译后程序存放目录,.idea为所用IDE自动生成的目录)
.gitignore :
bin log .idea