上篇文章,我们已经给项目加上了路由,并且走通了接口,这篇文章我们再给项目加上一项必不可少的内容 —— 日志.
目前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


