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

go包之logrus显示日志文件与行号

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

前言:

logrus是go中比较好的一个log模块.github上的很多开源项目都在使用这个模块, 我在写这个博文时, github上的logrus的stars数已经有8214了.最近在用这个模块时,发现不能打印日志所在文件和行数.在开发过程中, 感觉这就不是很友好了. 

项目地址: logrus github 地址

 

不记录文件名和行号处理办法

logrus支持自定义的hook, 我这里就是使用hook的方式来记录

一个Entry为一条日志记录, 我们的Hook需要做的就是在每一个条的日志记录里面添加调用时的文件名和行号. 核心就是实现自己的Fire方法, 以下是参考实现:

1. 我们新建一个hook的文件. 写入如下代码

package hooks

import (
    "fmt"
    "runtime"
    "strings"
    "github.com/sirupsen/logrus"
)
// ContextHook for log the call context
type contextHook struct {
    Field  string
    Skip   int
    levels []logrus.Level
}
// NewContextHook use to make an hook
// 根据上面的推断, 我们递归深度可以设置到5即可.
func NewContextHook(levels ...logrus.Level) logrus.Hook {
    hook := contextHook{
        Field:  "line",
        Skip:   5,
        levels: levels,
    }
    if len(hook.levels) == 0 {
        hook.levels = logrus.AllLevels
    }
    return &hook
}

// Levels implement levels
func (hook contextHook) Levels() []logrus.Level {
    return logrus.AllLevels
}

// Fire implement fire
func (hook contextHook) Fire(entry *logrus.Entry) error {
    entry.Data[hook.Field] = findCaller(hook.Skip)
    return nil
}
// 对caller进行递归查询, 直到找到非logrus包产生的第一个调用.
// 因为filename我获取到了上层目录名, 因此所有logrus包的调用的文件名都是 logrus/...
// 因此通过排除logrus开头的文件名, 就可以排除所有logrus包的自己的函数调用
func findCaller(skip int) string {
    file := ""
    line := 0
    for i := 0; i < 10; i++ {
        file, line = getCaller(skip + i)
        if !strings.HasPrefix(file, "logrus") {
            break
        }
    }
    return fmt.Sprintf("%s:%d", file, line)
}
// 这里其实可以获取函数名称的: fnName := runtime.FuncForPC(pc).Name()
// 但是我觉得有 文件名和行号就够定位问题, 因此忽略了caller返回的第一个值:pc
// 在标准库log里面我们可以选择记录文件的全路径或者文件名, 但是在使用过程成并发最合适的,
// 因为文件的全路径往往很长, 而文件名在多个包中往往有重复, 因此这里选择多取一层, 取到文件所在的上层目录那层.
func getCaller(skip int) (string, int) {
    _, file, line, ok := runtime.Caller(skip)
    //fmt.Println(file)
    //fmt.Println(line)
    if !ok {
        return "", 0
    }
    n := 0
    for i := len(file) - 1; i > 0; i-- {
        if file[i] == '/' {
            n++
            if n >= 2 {
                file = file[i+1:]
                break
            }
        }
    }
    return file, line
}

 

2. 添加hook到logrus  -- ( logrus定义为了全局使用 )

package main

import (
    log "github.com/sirupsen/logrus"
    zzxHook "study/ginStudy/hook"
)

func main() {
    var Logger = log.New()
    Logger.Hooks.Add(zzxHook.NewContextHook())
    Logger.WithFields(log.Fields{
        "animal": "walrus",
    }).Info("A walrus appears")
}

效果:

 

 

 

2. 添加hook到logrus  -- ( logrus普通使用方式 )

package main

import (
    log "github.com/sirupsen/logrus"
    zzxHook "study/ginStudy/hook"
)

func main() {
    log.AddHook(zzxHook.NewContextHook())
    log.WithFields(log.Fields{
        "animal": "walrus",
    }).Info("A walrus appears")
    
}

效果:

 


鲜花

握手

雷人

路过

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

请发表评论

全部评论

专题导读
上一篇:
bilibili源代码泄露,go-common发布时间:2022-07-10
下一篇:
后端开发工程师的开发环境配置(Vscode+C/Go/Python等)发布时间: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