• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

go语言web开发系列之六:gin使用zap记录http服务的访问日志(access log)并按日期分割 ...

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

一,安装用到的库:

1,安装zap日志库:

liuhongdi@ku:/data/liuhongdi/zaplog$ go get -u go.uber.org/zap

2,安装go-file-rotatelogs库

liuhongdi@ku:/data/liuhongdi/zaplog2$ go get -u github.com/lestrrat/go-file-rotatelogs

说明:刘宏缔的go森林是一个专注golang的博客,
          地址:https://blog.csdn.net/weixin_43881017

说明:作者:刘宏缔 邮箱: [email protected]

 

二,演示项目的相关信息:

1,项目地址:

https://github.com/liuhongdi/digv06

2,功能说明:记录http服务的访问日志access log

3,项目结构:如图:

三,go代码说明

1,config/config.yaml

  1.  
    Database:
  2.  
    DBType: mysql
  3.  
    UserName: root
  4.  
    Password: password
  5.  
    Host: 127.0.0.1:3306
  6.  
    DBName: dig
  7.  
    Charset: utf8
  8.  
    ParseTime: True
  9.  
    MaxIdleConns: 10
  10.  
    MaxOpenConns: 30
  11.  
    Server:
  12.  
    RunMode: debug
  13.  
    HttpPort: 8000
  14.  
    ReadTimeout: 60
  15.  
    WriteTimeout: 60
  16.  
    Log:
  17.  
    LogFilePath: /data/gologs/logs
  18.  
    LogInfoFileName: info
  19.  
    LogWarnFileName: warn
  20.  
    LogFileExt: log
  21.  
    AccessLog:
  22.  
    LogFilePath: /data/gologs/logs
  23.  
    LogFileName: access
  24.  
    LogFileExt: log

2,global/setting.go

  1.  
    package global
  2.  
     
  3.  
    import (
  4.  
    "fmt"
  5.  
    "github.com/liuhongdi/digv06/pkg/setting"
  6.  
    "time"
  7.  
    )
  8.  
    //服务器配置
  9.  
    type ServerSettingS struct {
  10.  
    RunMode string
  11.  
    HttpPort string
  12.  
    ReadTimeout time.Duration
  13.  
    WriteTimeout time.Duration
  14.  
    }
  15.  
    //数据库配置
  16.  
    type DatabaseSettingS struct {
  17.  
    DBType string
  18.  
    UserName string
  19.  
    Password string
  20.  
    Host string
  21.  
    DBName string
  22.  
    Charset string
  23.  
    ParseTime bool
  24.  
    MaxIdleConns int
  25.  
    MaxOpenConns int
  26.  
    }
  27.  
    //日志配置
  28.  
    type LogSettingS struct {
  29.  
    LogFilePath string //保存到的目录
  30.  
    LogInfoFileName string //info级日志文件的名字
  31.  
    LogWarnFileName string //warn级日志文件的名字
  32.  
    LogAccessFileName string //Access日志文件的名字
  33.  
    LogFileExt string //文件的扩展名
  34.  
    }
  35.  
    //访问日志配置
  36.  
    type AccessLogSettingS struct {
  37.  
    LogFilePath string //保存到的目录
  38.  
    LogFileName string //Access日志文件的名字
  39.  
    LogFileExt string //文件的扩展名
  40.  
    }
  41.  
    //定义全局变量
  42.  
    var (
  43.  
    ServerSetting *ServerSettingS
  44.  
    DatabaseSetting *DatabaseSettingS
  45.  
    LogSetting *LogSettingS
  46.  
    AccessLogSetting *AccessLogSettingS
  47.  
    )
  48.  
     
  49.  
    //读取配置到全局变量
  50.  
    func SetupSetting() error {
  51.  
    s, err := setting.NewSetting()
  52.  
    if err != nil {
  53.  
    return err
  54.  
    }
  55.  
    err = s.ReadSection("Database", &DatabaseSetting)
  56.  
    if err != nil {
  57.  
    return err
  58.  
    }
  59.  
     
  60.  
    err = s.ReadSection("Server", &ServerSetting)
  61.  
    if err != nil {
  62.  
    return err
  63.  
    }
  64.  
     
  65.  
    err = s.ReadSection("Log", &LogSetting)
  66.  
    if err != nil {
  67.  
    return err
  68.  
    }
  69.  
     
  70.  
    err = s.ReadSection("AccessLog", &AccessLogSetting)
  71.  
    if err != nil {
  72.  
    return err
  73.  
    }
  74.  
     
  75.  
    fmt.Println("setting:")
  76.  
    fmt.Println(ServerSetting)
  77.  
    fmt.Println(DatabaseSetting)
  78.  
    fmt.Println(LogSetting)
  79.  
    fmt.Println(AccessLogSetting)
  80.  
    return nil
  81.  
    }

3,global/accessLog.go

  1.  
    package global
  2.  
     
  3.  
    import (
  4.  
    "fmt"
  5.  
    "github.com/liuhongdi/digv06/pkg/setting"
  6.  
    "time"
  7.  
    )
  8.  
    //服务器配置
  9.  
    type ServerSettingS struct {
  10.  
    RunMode string
  11.  
    HttpPort string
  12.  
    ReadTimeout time.Duration
  13.  
    WriteTimeout time.Duration
  14.  
    }
  15.  
    //数据库配置
  16.  
    type DatabaseSettingS struct {
  17.  
    DBType string
  18.  
    UserName string
  19.  
    Password string
  20.  
    Host string
  21.  
    DBName string
  22.  
    Charset string
  23.  
    ParseTime bool
  24.  
    MaxIdleConns int
  25.  
    MaxOpenConns int
  26.  
    }
  27.  
    //日志配置
  28.  
    type LogSettingS struct {
  29.  
    LogFilePath string //保存到的目录
  30.  
    LogInfoFileName string //info级日志文件的名字
  31.  
    LogWarnFileName string //warn级日志文件的名字
  32.  
    LogAccessFileName string //Access日志文件的名字
  33.  
    LogFileExt string //文件的扩展名
  34.  
    }
  35.  
    //访问日志配置
  36.  
    type AccessLogSettingS struct {
  37.  
    LogFilePath string //保存到的目录
  38.  
    LogFileName string //Access日志文件的名字
  39.  
    LogFileExt string //文件的扩展名
  40.  
    }
  41.  
    //定义全局变量
  42.  
    var (
  43.  
    ServerSetting *ServerSettingS
  44.  
    DatabaseSetting *DatabaseSettingS
  45.  
    LogSetting *LogSettingS
  46.  
    AccessLogSetting *AccessLogSettingS
  47.  
    )
  48.  
     
  49.  
    //读取配置到全局变量
  50.  
    func SetupSetting() error {
  51.  
    s, err := setting.NewSetting()
  52.  
    if err != nil {
  53.  
    return err
  54.  
    }
  55.  
    err = s.ReadSection("Database", &DatabaseSetting)
  56.  
    if err != nil {
  57.  
    return err
  58.  
    }
  59.  
     
  60.  
    err = s.ReadSection("Server", &ServerSetting)
  61.  
    if err != nil {
  62.  
    return err
  63.  
    }
  64.  
     
  65.  
    err = s.ReadSection("Log", &LogSetting)
  66.  
    if err != nil {
  67.  
    return err
  68.  
    }
  69.  
     
  70.  
    err = s.ReadSection("AccessLog", &AccessLogSetting)
  71.  
    if err != nil {
  72.  
    return err
  73.  
    }
  74.  
     
  75.  
    fmt.Println("setting:")
  76.  
    fmt.Println(ServerSetting)
  77.  
    fmt.Println(DatabaseSetting)
  78.  
    fmt.Println(LogSetting)
  79.  
    fmt.Println(AccessLogSetting)
  80.  
    return nil
  81.  
    }

4,middelware/accesslog.go

  1.  
    package middleware
  2.  
     
  3.  
    import (
  4.  
    "bytes"
  5.  
    "github.com/liuhongdi/digv06/global"
  6.  
    "github.com/liuhongdi/digv06/pkg/util"
  7.  
    "time"
  8.  
    "github.com/gin-gonic/gin"
  9.  
    )
  10.  
     
  11.  
    type AccessLogWriter struct {
  12.  
    gin.ResponseWriter
  13.  
    body *bytes.Buffer
  14.  
    }
  15.  
     
  16.  
    func (w AccessLogWriter) Write(p []byte) (int, error) {
  17.  
    if n, err := w.body.Write(p); err != nil {
  18.  
    return n, err
  19.  
    }
  20.  
    return w.ResponseWriter.Write(p)
  21.  
    }
  22.  
     
  23.  
    func AccessLog() gin.HandlerFunc {
  24.  
    return func(c *gin.Context) {
  25.  
    bodyWriter := &AccessLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
  26.  
    c.Writer = bodyWriter
  27.  
     
  28.  
    beginTime := time.Now().UnixNano()
  29.  
    c.Next()
  30.  
    endTime := time.Now().UnixNano()
  31.  
    duration:=endTime-beginTime
  32.  
     
  33.  
    s := "%s %s \"%s %s\" "+
  34.  
    "%s %d %d %dµs "+
  35.  
    "\"%s\""
  36.  
     
  37.  
    layout := "2006-01-02 15:04:05"
  38.  
    timeNow := time.Now().Format(layout)
  39.  
     
  40.  
    global.AccessLogger.Infof(s,
  41.  
    util.GetRealIp(c),
  42.  
    timeNow,
  43.  
    c.Request.Method,
  44.  
    c.Request.RequestURI,
  45.  
    c.Request.Proto,
  46.  
    bodyWriter.Status(),
  47.  
    bodyWriter.body.Len(),
  48.  
    duration/1000,
  49.  
    c.Request.Header.Get("User-Agent"),
  50.  
     
  51.  
    );
  52.  
    }
  53.  
    }

5,pkg/zaplog/zaplog.go

  1.  
    package zaplog
  2.  
     
  3.  
    import (
  4.  
    rotatelogs "github.com/lestrrat/go-file-rotatelogs"
  5.  
    "go.uber.org/zap"
  6.  
    "go.uber.org/zap/zapcore"
  7.  
    "io"
  8.  
    "time"
  9.  
    )
  10.  
     
  11.  
    //get logger
  12.  
    func GetInitLogger(filepath,infofilename,warnfilename,fileext string) (*zap.SugaredLogger,error) {
  13.  
    encoder := getEncoder()
  14.  
    //两个判断日志等级的interface
  15.  
    //warnlevel以下属于info
  16.  
    infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
  17.  
    return lvl < zapcore.WarnLevel
  18.  
    })
  19.  
    //warnlevel及以上属于warn
  20.  
    warnLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
  21.  
    return lvl >= zapcore.WarnLevel
  22.  
    })
  23.  
     
  24.  
    infoWriter,err := getLogWriter(filepath+"/"+infofilename,fileext)
  25.  
    if (err != nil) {
  26.  
    return nil,err
  27.  
    }
  28.  
    warnWriter,err2 := getLogWriter(filepath+"/"+warnfilename,fileext)
  29.  
    if (err2 != nil) {
  30.  
    return nil,err2
  31.  
    }
  32.  
     
  33.  
    //创建具体的Logger
  34.  
    core := zapcore.NewTee(
  35.  
    zapcore.NewCore(encoder, infoWriter, infoLevel),
  36.  
    zapcore.NewCore(encoder, warnWriter, warnLevel),
  37.  
    )
  38.  
    loggerres := zap.New(core, zap.AddCaller())
  39.  
     
  40.  
    return loggerres.Sugar(),nil
  41.  
    }
  42.  
     
  43.  
    //get logger
  44.  
    func GetInitAccessLogger(filepath,filename,fileext string) (*zap.SugaredLogger,error) {
  45.  
     
  46.  
    warnWriter,err2 := getLogWriter(filepath+"/"+filename,fileext)
  47.  
    if (err2 != nil) {
  48.  
    return nil,err2
  49.  
    }
  50.  
     
  51.  
    var cfg zap.Config
  52.  
    cfg =zap.Config{
  53.  
    Level: zap.NewAtomicLevelAt(zap.DebugLevel),
  54.  
    Development: true,
  55.  
    Encoding: "console",
  56.  
    EncoderConfig: zapcore.EncoderConfig{
  57.  
    MessageKey: "msg",
  58.  
    },
  59.  
    OutputPaths: []string{"stdout", "./log.txt"},
  60.  
    ErrorOutputPaths: []string{"stderr"},
  61.  
    }
  62.  
     
  63.  
    l, err := cfg.Build(SetOutput(warnWriter, cfg))
  64.  
    if err != nil {
  65.  
    panic(err)
  66.  
    }
  67.  
     
  68.  
    return l.Sugar(),nil
  69.  
    }
  70.  
     
  71.  
     
  72.  
    func SetOutput(ws zapcore.WriteSyncer, conf zap.Config) zap.Option {
  73.  
    var enc zapcore.Encoder
  74.  
    switch conf.Encoding {
  75.  
    case "json":
  76.  
    enc = zapcore.NewJSONEncoder(conf.EncoderConfig)
  77.  
    case "console":
  78.  
    enc = zapcore.NewConsoleEncoder(conf.EncoderConfig)
  79.  
    default:
  80.  
    panic("unknown encoding")
  81.  
    }
  82.  
    return zap.WrapCore(func(core zapcore.Core) zapcore.Core {
  83.  
    return zapcore.NewCore(enc, ws, conf.Level)
  84.  
    })
  85.  
    }
  86.  
     
  87.  
     
  88.  
    //Encoder
  89.  
    func getEncoder() zapcore.Encoder {
  90.  
    encoderConfig := zap.NewProductionEncoderConfig()
  91.  
    encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
  92.  
    encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
  93.  
    return zapcore.NewConsoleEncoder(encoderConfig)
  94.  
    }
  95.  
     
  96.  
    //LogWriter
  97.  
    func getLogWriter(filePath,fileext string) (zapcore.WriteSyncer,error) {
  98.  
    warnIoWriter,err := getWriter(filePath,fileext)
  99.  
    if (err != nil) {
  100.  
    return nil,err
  101.  
    }
  102.  
    return zapcore.AddSync(warnIoWriter),nil
  103.  
    }
  104.  
     
  105.  
    //日志文件切割,按天
  106.  
    func getWriter(filename,fileext string) (io.Writer,error) {
  107.  
    // 保存30天内的日志,每24小时(整点)分割一次日志
  108.  
    hook, err := rotatelogs.New(
  109.  
    filename+"_%Y%m%d."+fileext,
  110.  
    rotatelogs.WithLinkName(filename),
  111.  
    rotatelogs.WithMaxAge(time.Hour*24*30),
  112.  
    rotatelogs.WithRotationTime(time.Hour*24),
  113.  
    )
  114.  
    /*
  115.  
    //供测试用,保存30天内的日志,每1分钟(整点)分割一次日志
  116.  
    hook, err := rotatelogs.New(
  117.  
    filename+"_%Y%m%d%H%M.log",
  118.  
    rotatelogs.WithLinkName(filename),
  119.  
    rotatelogs.WithMaxAge(time.Hour*24*30),
  120.  
    rotatelogs.WithRotationTime(time.Minute*1),
  121.  
    )
  122.  
    */
  123.  
    if err != nil {
  124.  
    //panic(err)
  125.  
    return nil,err
  126.  
    }
  127.  
    return hook,nil
  128.  
    }

6,router/router.go

  1.  
    package router
  2.  
     
  3.  
    import (
  4.  
    "github.com/gin-gonic/gin"
  5.  
    "github.com/liuhongdi/digv06/controller"
  6.  
    "github.com/liuhongdi/digv06/global"
  7.  
    "github.com/liuhongdi/digv06/middleware"
  8.  
    "github.com/liuhongdi/digv06/pkg/result"
  9.  
    "runtime/debug"
  10.  
    )
  11.  
     
  12.  
    func Router() *gin.Engine {
  13.  
    router := gin.Default()
  14.  
    //处理异常
  15.  
    router.NoRoute(HandleNotFound)

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
区块链学习之Hyperledger Fabric开发环境搭建(Go+Docker+Fabric)发布时间:2022-07-10
下一篇:
Go语言AST尝试发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap