18.日志

news/2025/9/21 0:54:13/文章来源:https://www.cnblogs.com/surpassme/p/19103097

18.日志

18.1 自带log包

    在日常项目,在出现问题之后需要排查,一种比较主要的排查方式是通过日志。所以在代码的关键地方,需要打印相应的日志。在Go语言中log包提供了简单的日志功能,其输出格式如下所示:

打印 格式化打印 换行打印 备注
log.Print() log.Printf() log.Println() 类似于fmt.Print*
log.Fatal() log.Fatalf() log.Fatalln() 类似于fmt.Print* + os.Exit(1)
log.Panic() log.Panicf() log.Panicln() 类似于fmt.Print*+ panic()

    一般在打印日志时,我们会定义一个Logger进行日志的打印,默认的日志定义如下所示:

type Logger struct {outMu sync.Mutexout   io.Writer // destination for outputprefix    atomic.Pointer[string] // prefix on each line to identify the logger (but see Lmsgprefix)flag      atomic.Int32           // propertiesisDiscard atomic.Bool
}const (Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23Ltime                         // the time in the local time zone: 01:23:23Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.Llongfile                     // full file name and line number: /a/b/c/d.go:23Lshortfile                    // final file name element and line number: d.go:23. overrides LlongfileLUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zoneLmsgprefix                    // move the "prefix" from the beginning of the line to before the messageLstdFlags     = Ldate | Ltime // initial values for the standard logger
)var std = New(os.Stderr, "", LstdFlags)// Default returns the standard logger used by the package-level output functions.
func Default() *Logger { return std }

    上面都是使用std.Output打印日志。而std本质上是使用标准错误输出、无前缀、LstdFlags标准标记的Logger

18.1.1 使用Std打印日志

    示例代码如下所示:

package mainimport ("log""os"
)func main() {// 使用默认配置打印日志log.Print("使用log.Print打印日志\n")log.Printf("使用log.Printf打印日志,%v", "Surpass")log.Println("使用log.Println打印日志")// 使用自定义LoggerlInfo := log.New(os.Stdout, "[INFO]", log.LstdFlags|log.Lmsgprefix)lInfo.Println("使用自定义Logger打印日志,日志级别 info")lError := log.New(os.Stderr, "[ERROR]", log.LstdFlags|log.Lmsgprefix|log.Lshortfile)lError.Fatalln("使用自定义Logger打印日志,日志级别 error")
}

    代码运行结果如下所示:

2024/12/30 23:48:43 使用log.Print打印日志
2024/12/30 23:48:43 使用log.Printf打印日志,Surpass
2024/12/30 23:48:43 使用log.Println打印日志
2024/12/30 23:48:43 [INFO]使用自定义Logger打印日志,日志级别 info
2024/12/30 23:48:43 main.go:18: [ERROR]使用自定义Logger打印日志,日志级别 error
exit status 1

18.1.2 日志写入文件

    示例代码如下所示:

package mainimport ("log""os""path/filepath"
)func main() {curpath, _ := os.Getwd()flag := os.O_CREATE | os.O_APPEND | os.O_WRONLYfilename := filepath.Join(curpath, "surpass.log")f, err := os.OpenFile(filename, flag, 0)if err != nil {log.Panicf("打开文件%v出错:%v\n", filename, err)}defer f.Close()lInfo := log.New(f, "[INFO]", log.Lshortfile|log.LstdFlags)lInfo.Println("这是一个写入文件的日志,级别-INFO")lError := log.New(f, "[WARNING]", log.Lshortfile|log.LstdFlags)lError.Fatalln("这是一个写入文件的日志,级别-WARNING")lPanic := log.New(f, "[ERROR]", log.Lshortfile|log.LstdFlags)lPanic.Panicln("这是一个写入文件的日志,级别-ERROR")
}

    代码运行结果如下所示:

[INFO]2024/12/31 00:09:37 main.go:20: 这是一个写入文件的日志,级别-INFO
[WARNING]2024/12/31 00:09:37 main.go:23: 这是一个写入文件的日志,级别-WARNING

18.2 zerolog

    Go自带的log库太简单,在实际开发过程中,使用并不方便。因此出现很多第三方比较优秀的开源日志库,如下所示:

  • logrus: 有日志级别、Hook机制、日志格式输出
  • zap是Uber开源的高性能的日志库
  • zerolog更注重开发体验、也是一款高性能的日志库,有日志级别,链式API,JSON格式化的日志记录

Github地址:https://github.com/rs/zerolog

18.2.1 安装

    执行以下命令即可

go get -u github.com/rs/zerolog/log

18.2.2 默认Logger

    示例代码如下所示:

package mainimport ("github.com/rs/zerolog/log"
)func main() {log.Print("Hello,Surpass")
}

    代码运行结果如下所示:

{"level":"debug","time":"2024-12-31T23:18:14+08:00","message":"Hello,Surpass"}

默认输出格式为JSON,级别且为Debug模式

18.2.3 消息级别

    zerolog对应的日志级别从高到低如下所示:

  • panic (zerolog.PanicLevel, 5)
  • fatal (zerolog.FatalLevel, 4)
  • error (zerolog.ErrorLevel, 3)
  • warn (zerolog.WarnLevel, 2)
  • info (zerolog.InfoLevel, 1)
  • debug (zerolog.DebugLevel, 0)
  • trace (zerolog.TraceLevel, -1)

    查看源码定义如下所示:

const (// DebugLevel defines debug log level.DebugLevel Level = iota// InfoLevel defines info log level.InfoLevel// WarnLevel defines warn log level.WarnLevel// ErrorLevel defines error log level.ErrorLevel// FatalLevel defines fatal log level.FatalLevel// PanicLevel defines panic log level.PanicLevel// NoLevel defines an absent log level.NoLevel// Disabled disables the logger.Disabled// TraceLevel defines trace log level.TraceLevel Level = -1// Values less than TraceLevel are handled as numbers.
)

    在zerolog中,日志级别可以全局设置,也可以局部设置,即为每一个Logger或消息设置不同的消息级别。其中全局级别的使用形式如下所示:

  • 设置级别:zerolog.SetGlobalLevel(zerolog.InfoLevel)
  • 获取级别:zerolog.GlobalLevel()

    示例代码如下所示:

package mainimport ("fmt""github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {// 获取全局的消息级别fmt.Printf("获取全局消息级别:%+v\n", zerolog.GlobalLevel())fmt.Printf("默认Logger的消息级别为:%+v\n", log.Logger.GetLevel())// 创建一个Logger,并获取相应的消息级别l := log.Level(zerolog.WarnLevel)fmt.Printf("新建Logger的级别为:%+v", l.GetLevel())// 使用默认Logger 自定义每一个消息的级别log.Info().Msg("默认Logger消息级别-INFO")log.Error().Msg("默认Logger消息级别-ERROR")log.Warn().Msg("默认Logger消息级别-WARNING")log.Debug().Msg("默认Logger消息级别-DEBUG")log.Trace().Msg("默认Logger消息级别-TRACE")// 使用自定义Logger 自定义每一个消息的级别l.Debug().Msg("自定义Logger消息级别-DEBUG")  //不输出l.Info().Msg("自定义Logger消息级别-INFO")    // 不输出l.Error().Msg("自定义Logger消息级别-ERROR")  //输出l.Warn().Msg("自定义Logger消息级别-WARNING") //输出
}

    代码运行结果如下所示:

获取全局消息级别:trace
默认Logger的消息级别为:trace
新建Logger的级别为:warn
{"level":"info","time":"2024-12-31T23:41:34+08:00","message":"默认Logger消息级别-INFO"}
{"level":"error","time":"2024-12-31T23:41:34+08:00","message":"默认Logger消息级别-ERROR"}
{"level":"warn","time":"2024-12-31T23:41:34+08:00","message":"默认Logger消息级别-WARNING"}
{"level":"debug","time":"2024-12-31T23:41:34+08:00","message":"默认Logger消息级别-DEBUG"}
{"level":"trace","time":"2024-12-31T23:41:34+08:00","message":"默认Logger消息级别-TRACE"}{"level":"error","time":"2024-12-31T23:41:34+08:00","message":"自定义Logger消息级别-ERROR"}
{"level":"warn","time":"2024-12-31T23:41:34+08:00","message":"自定义Logger消息级别-WARNING"}

    从代码运行结果可以总结如下所示:

  • 使用默认Logger,可以输出所有日志消息
  • 使用自定义Logger,只能输出部分日志消息,是因为在zerolog中存在消息级别Logger级别两个概念

    在上述代码中自定义的Logger中,其Logger级别被设置为WarnLevel,其级别为2,当输出的消息级别低于其Logger级别时,则不被输出。因此想要消息成功输出,则需要满足以下条件

消息级别 >= max(全局组别,当前Logger级别)

其中 zerolog.SetGlobalLevel() 为全局级别,会影响所有Logger

package mainimport ("fmt""github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {// 设置全局消息级别zerolog.SetGlobalLevel(zerolog.ErrorLevel)// 获取全局的消息级别fmt.Printf("获取全局消息级别:%+v\n", zerolog.GlobalLevel())fmt.Printf("默认Logger的消息级别为:%+v\n", log.Logger.GetLevel())// 创建一个Logger,并获取相应的消息级别l := log.Level(zerolog.WarnLevel)fmt.Printf("新建Logger的级别为:%+v", l.GetLevel())// 使用默认Logger 自定义每一个消息的级别log.Info().Msg("默认Logger消息级别-INFO")log.Error().Msg("默认Logger消息级别-ERROR")log.Warn().Msg("默认Logger消息级别-WARNING")log.Debug().Msg("默认Logger消息级别-DEBUG")log.Trace().Msg("默认Logger消息级别-TRACE")// 使用自定义Logger 自定义每一个消息的级别l.Debug().Msg("自定义Logger消息级别-DEBUG")  //不输出l.Info().Msg("自定义Logger消息级别-INFO")    // 不输出l.Error().Msg("自定义Logger消息级别-ERROR")  //输出l.Warn().Msg("自定义Logger消息级别-WARNING") //输出// 禁用日志输出zerolog.SetGlobalLevel(zerolog.Disabled)fmt.Printf("获取全局消息级别:%+v\n", zerolog.GlobalLevel())log.Info().Msg("默认Logger消息级别-PANIC")l.Error().Msg("自定义Logger消息级别-PANIC")
}

    代码运行结果如下所示:

获取全局消息级别:error
默认Logger的消息级别为:trace
新建Logger的级别为:warn{"level":"error","time":"2025-01-01T00:06:15+08:00","message":"默认Logger消息级别-ERROR"}
{"level":"error","time":"2025-01-01T00:06:15+08:00","message":"自定义Logger消息级别-ERROR"}
获取全局消息级别:disabled

18.2.4 上下文

    zerolog 的默认输出格式为JSON,但也可以自定义一些键值对字段,并在上下文中进行输出,示例代码如下所示:

package mainimport ("fmt""time""github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {// 设置全局消息级别zerolog.SetGlobalLevel(zerolog.InfoLevel)// 获取全局的消息级别fmt.Printf("获取全局消息级别:%+v\n", zerolog.GlobalLevel())fmt.Printf("默认Logger的消息级别为:%+v\n", log.Logger.GetLevel())log.Warn().Bool("SUCCESS", false).Str("原因", "未满足相应的条件").Msg("没有满足相应条件")log.Info().Str("Username", "Surpass").Time("登录时间", time.Now()).Msg("用户登录成功")
}

    代码运行结果如下所示:

获取全局消息级别:info
默认Logger的消息级别为:trace
{"level":"warn","SUCCESS":false,"原因":"未满足相应的条件","time":"2025-01-01T00:19:38+08:00","message":"没有满足相应条件"}
{"level":"info","Username":"Surpass","登录时间":"2025-01-01T00:19:38+08:00","time":"2025-01-01T00:19:38+08:00","message":"用户登录成功"}

18.2.5 错误日志

    在zerolog中输出错误日志的示例代码如下所示:

package mainimport ("errors""fmt""time""github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {// 设置全局消息级别zerolog.SetGlobalLevel(zerolog.InfoLevel)// 获取全局的消息级别fmt.Printf("获取全局消息级别:%+v\n", zerolog.GlobalLevel())fmt.Printf("默认Logger的消息级别为:%+v\n", log.Logger.GetLevel())// 设置时间格式zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMslog.Info().Str("Username", "Surpass").Time("登录时间", time.Now()).Msg("用户登录成功")// 自定义错误日志err := errors.New("Surpass自定义错误日志")log.Error(). // 错误级别消息Err(err). // 错误消息内容,即err字段Send()log.Fatal().Err(err).Send()
}

    代码运行结果如下所示:

获取全局消息级别:info
默认Logger的消息级别为:trace
{"level":"info","Username":"Surpass","登录时间":1735662443578,"time":1735662443578,"message":"用户登录成功"}
{"level":"error","error":"Surpass自定义错误日志","time":1735662443578}
{"level":"fatal","error":"Surpass自定义错误日志","time":1735662443578}
exit status 1

18.2.6 自定义Logger

    示例代码如下所示:

package mainimport ("errors""fmt""os""github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {// 自定义Logger方式一:loggerA := zerolog.New(os.Stdout).With().Timestamp().Caller().Logger().Level(zerolog.DebugLevel)zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMsfmt.Println("自定义LoggerA的级别为:", loggerA.GetLevel())err := errors.New("Surpass自定义错误")loggerA.Error().Err(err).Send()fmt.Println("")// 自定义Logger方式二:loggerB := log.With().Str("Product", "Surpass").Caller().Logger().Level(zerolog.InfoLevel)fmt.Println("自定义LoggerB的级别为:", loggerB.GetLevel())loggerB.Info().Msg("自定义的Logger")
}

    代码运行结果如下所示:

自定义LoggerA的级别为: debug
{"level":"error","error":"Surpass自定义错误","time":1735664944449,"caller":"C:/Users/Surpass/Documents/GolangProjets/src/18/1808-zerolog-customer/main.go:18"}自定义LoggerB的级别为: info
{"level":"info","Product":"Surpass","time":1735664944449,"caller":"C:/Users/Surpass/Documents/GolangProjets/src/18/1808-zerolog-customer/main.go:25","message":"自定义的Logger"}

18.2.7 日志写入文件

    示例代码如下所示:

package mainimport ("os""path/filepath""github.com/rs/zerolog""github.com/rs/zerolog/log"
)func main() {zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMscurPath, _ := os.Getwd()filename := filepath.Join(curPath, "zerolog.surpass.log")f, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0)if err != nil {log.Panic().Err(err).Send()}defer f.Close()// 多分支写multi := zerolog.MultiLevelWriter(f, os.Stdout)logger := zerolog.New(multi).With().Timestamp().Logger()logger.Info().Msg("日志同时写入文件和控制台")
}

本文同步在微信订阅号上发布,如各位小伙伴们喜欢我的文章,也可以关注我的微信订阅号:woaitest,或扫描下面的二维码添加关注:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/908638.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

testuserjiagou

https://aws.amazon.com/cn/blogs/architecture/disaster-recovery-dr-architecture-on-aws-part-i-strategies-for-recovery-in-the-cloud/

IDEA 自动编译和热部署

测试环境 IDEA2023 一 自动编译菜单 File >> Settings >> Build,Execution,Deployment >> Compiler 勾选上 Build project automatically 二 热加载 1. 设置自动编译后,添加依赖<dependency&g…

testusers3

我们需要为AWS S3创建一个策略,以便允许ALB(Application Load Balancer)将访问日志上传到指定的S3存储桶。 策略需要满足以下条件: 允许ALB服务将日志写入S3存储桶。 只允许对特定存储桶和特定前缀(如果需要)的写…

RabbitMQ核心模型简介,Hello World的生产与消费

本章学习目标理解AMQP模型中的核心概念:Connection, Channel, Producer, Consumer, Queue。创建一个.NET项目并添加RabbitMQ客户端库。使用C#编写代码发送一条消息("Hello World")。使用C#编写代码接收并…

关于oj在创建文件夹失败的原因

由于他是在/home,java所在的身份www,没有权限创建文件夹和文件,其次是没有Docker 权限被拒绝

Linux 基础命令 02

一、查看文件内容及内容处理命令 1.1 vi/vim vi命令 是UNIX操作系统和类UNIX操作系统中最通⽤的全屏幕纯⽂本编辑器。Linux中的vi编辑器叫vim,它是vi的增强版(vi Improved),与vi编辑器完全兼容,⽽且实现了很多增强…

RabbitMQ核心模型简介,Hello World的发送与消费

本文目标理解AMQP模型中的核心概念:Connection, Channel, Producer, Consumer, Queue。创建一个.NET项目并添加RabbitMQ客户端库。使用C#编写代码发送一条消息("Hello World")。使用C#编写代码接收并处理…

Proxy 库解析(三)

ptrs template <class F> struct converter {explicit converter(F f) noexcept : f_(std::move(f)) {}converter(const converter&) = delete;template <class T>operator T() && noexcept(s…

软工个人项目 - Helen

论文查重系统设计与实现 GitHub作业链接: https://github.com/Playerhh/playerhh/tree/main/3223004773这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/这个作业要求在哪里…

记录 | 心理行动机制模型

你說: 在学校操场跑步,然后拉了十个单杠,想着要不再做个俯卧撑吧,但想着累了,不做了,但又想了想,还不如去想,就算做一个也是做,那还不如做试试,于是一个变成两个,两个变成五个,五个变成十个,十个在上25个…

ENSP模拟搭建典型中小型企业网架构

小型公司网络 网络拓扑图规划 vlan 销售 vlan 10 市场 vlan 20 产品 vlan 30 服务器 vlan 40 DMZ vlan 50 老板位 vlan 88 配置vlan SW3 [SW3]vlan 10 //创建vlan [SW3-vlan10]description xiaoshou //描述[SW3-vl…

【Java】ArrayList讲解

基础操作 创建实例

【Java】HashMap讲解

基础操作 创建实例

图解15:DNS工作原理

最近工作经常处理域名解析,SSL证书配置

图解16:数据和信息流的9大架构模式

本人ETL最近比较少用,之前使用都是处理数据平台入湖、数据同步、数仓

图解12:软件开发8大模型

本人基本都是使用增量和迭代

2025年9月15灯塔arl安装部署教程_2025-09-20

灯塔是什么 灯塔 ARL 是网络安全领域受青睐的自动化互联网资产侦察与安全风险评估工具,既能通过 DNS 解析、证书透明度日志、搜索引擎语法梳理域名资产,结合域名反向映射 IP、扫描 IP 段及 ASN 归属分析明确网络基础…