日志中输出文件名,行号及函数名是个比较有用的功能,那么在logrus中如何作到呢?

1. 在自带Formatter中输出

logrus有两个片自的Formatter,分别是:TextFormatter和JSONFormatter。(如果不了解TextFormatter和JSONFormatter,可以 点这里 )要在这两个Formatter中输出文件名,行号和函数名,只需要设置

logrus.SetReportCaller(true)

1.1 在TextFormatter中输出

func Demo(){
	logrus.Info("i'm demo")
func main(){
	logrus.SetReportCaller(true)
	logrus.SetFormatter(&logrus.TextFormatter{
		//以下设置只是为了使输出更美观
		DisableColors:true,
		TimestampFormat:"2006-01-02 15:03:04",
	Demo()
time="2021-05-11 14:02:45" level=info msg="i'm demo" func=main.Demo file="/home/ballqiu/go/log/demo.go:30"
  • func为函数名
  • file格式为文件名:行号
  • JsonFormatter中的使用类似

1.2 定制文件名和函数名的输出

上例中的文件名因为包含了路径信息,因此特别长。如果我们只要想文件名,不想输出路径,以便使得日志更简短,怎么做呢?可以设置Formatter中的CallerPrettyfier,它的函数原型是:

func(*runtime.Frame) (function string, file string)

返回值中的function是函数名, file是文件名。

func Demo(){
	logrus.Info("i'm demo")
func main(){
	logrus.SetReportCaller(true)
	logrus.SetFormatter(&logrus.JSONFormatter{
		TimestampFormat:"2006-01-02 15:03:04",
		CallerPrettyfier: func(frame *runtime.Frame) (function string, file string) {
		    //处理文件名
			fileName := path.Base(frame.File)
			return frame.Function, fileName
	Demo()
{"file":"demo.go","func":"main.Demo","level":"info","msg":"i'm demo","time":"2021-05-11 14:02:57"}
  • 参数frame中包含了文件名,函数名,行号,等一系列信息。
  • path.Base(frame.File)去掉了文件名中的路径部分。
  • TextFormatter中的使用与JSONFormatter完全一致

2.在自定义Formatter中输出

如果你还不了解如何自定义Formatter,可以参看logrus自定义日志输出格式

  1. 设置logrus.SetReportCaller(true)
  2. 通过entry.Caller拿到相应的信息进行输出
type MyFormatter struct {}
func (m *MyFormatter) Format(entry *logrus.Entry) ([]byte, error){
	var b *bytes.Buffer
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	timestamp := entry.Time.Format("2006-01-02 15:04:05")
	var newLog string
    //HasCaller()为true才会有调用信息
	if entry.HasCaller() {
		fName := filepath.Base(entry.Caller.File)
		newLog = fmt.Sprintf("[%s] [%s] [%s:%d %s] %s\n",
			timestamp, entry.Level, fName, entry.Caller.Line, entry.Caller.Function, entry.Message)
	} else{
		newLog = fmt.Sprintf("[%s] [%s] %s\n", timestamp, entry.Level, entry.Message)
	b.WriteString(newLog)
	return b.Bytes(), nil
func Demo(){
	logrus.Info("i'm demo")
func main(){
	logrus.SetReportCaller(true)
	logrus.SetFormatter(&MyFormatter{})
	Demo()
[2021-05-11 15:08:46] [info] [demo.go:38 main.Demo] i'm demo
  • entry.Caller.File:文件名
  • entry.Caller.Line: 行号
  • entry.Caller.Function:函数名
  • entry.Caller中还有调用栈相关信息,有需要可以在日志中加入
  • entry.HasCaller() 的判断是必须的,否则如果外部没有设置logrus.SetReportCaller(true),entry.Caller.*的调用会引发Panic
logrus默认不支持显示文件名行号,不太友好,但是在v1.2.0版本已经修复。可以通过setReportCaller设置即可显示文件名行号 补充知识:logrus输出设置 O_RDONLY:只读模式(read-only) O_WRONLY:只写模式(write-only) O_RDWR:读写模式(read-write) O_APPEND:追加模式(append) O_CREATE:文件不存在就创建(create a new file if none exists.) O_EXCL:与 O_CREATE 一起用,构成一个新建文件的功能,它要求文件必须不存在(used with O_C
%(levelname)s 文本形式的日志级别 %(pathname)s 调用日志输出函数的模块的完整路径,可能没有 %(filename)s 调用日志输出函数的模块的文件名 %(module)s 调用日志输出函数的模块 %(funcName)s 调用日志输出函数... 在后台程序运行出问题时,需要查看详尽的日志,C语言提供记录日志触发点文件名行号函数的方法,关键是利用C99新增的预处理标识符__VA_ARGS__;先介绍几个编译器内置的宏定义,这些宏定义不仅可以帮助我们完成跨平台的源码编写,灵活使用也可以巧妙地帮我们输出非常有用的调试信息。 二、ANSI C标准宏 __LINE__ // 在源代码插入当前源代码行号 golang 的runtime库,提供Caller函数,可以返回运行时正在执行的文件名行号函数定义: func Caller(skip int) (pc uintptr, file string, line int, ok bool) {} 函数用法: _, file, line, ok := runtime.Caller(0) func main() { funcName,file,line,ok :=. 下面示例代码的一些import我没做校验,我只是从我的一个测试代码里抠出来的,出现一些错误自己简单处理下就可以用。 logrus简介 logrus是一个可插拔的、结构化的日志框架。 logrus拥有六种日志级别:debug、info、warn、error、fatal和panic 可扩展的Hook机制: 允许使用者通过hook的方式将日志分发到任意地方,如本地文件系统、标准输出logs... func InitLogger() { level := GetLogLevel(viper.GetString("LOG_LEVEL")) log.SetLevel(level) formatter := &log.TextFormatter{ ForceColors: true,//设置颜色 FullTimestamp: . printf("当前文件名:%s\n", __FILE__); printf("当前函数:%s\n", __FUNCTION__); printf("当前行号:%d\n", __LINE__); return 0; 输出结果如下: 当前文件名:test.c 当前函数:main 当前行号:5 这些内置变量可以帮助我们在程序输出调试信息,或者记录日志信息,方便程序的调试和维护。