前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文搞懂Go语言标准库,log

一文搞懂Go语言标准库,log

作者头像
微客鸟窝
发布2021-12-27 19:08:28
4550
发布2021-12-27 19:08:28
举报
文章被收录于专栏:Go语言指北

Go 语言的标准库中提供了一个简单的 log 日志包,它不仅提供了很多函数,还定义了一个包含很多方法的类型 Logger。Logger 会打印每条日志信息的日期、时间,默认输出到标准错误。Fatal 系列函数会在写入日志信息后调用 os.Exit(1)。Panic 系列函数会在写入日志信息后 panic。下面详细介绍下标准库log的基本使用。

函数

Golang 的 log 包主要提供了以下几个具备输出功能的函数:

代码语言:javascript
复制
func Fatal(v ...interface{})
func Fatalf(format string, v ...interface{})
func Fatalln(v ...interface{})
func Panic(v ...interface{})
func Panicf(format string, v ...interface{})
func Panicln(v ...interface{})
func Print(v ...interface{})
func Printf(format string, v ...interface{})
func Println(v ...interface{})

示例

代码语言:javascript
复制
//l.Output(2, fmt.Sprintf(format, v...))
 v := "普通"
 log.Printf("一条%s日志。\n", v)
 
 //l.Output(2, fmt.Sprintln(v...))
 log.Println("一条一条普通日志。")
 
 //l.Output(2, fmt.Sprintln(v...))
 //os.Exit(1)
 log.Fatalln("一条触发fatal的日志。")
 
 //s := fmt.Sprintln(v...)
 //l.Output(2, s)
 //panic(s)
 log.Panicln("一条触发panic的日志。")

运行结果

代码语言:javascript
复制
021/12/22 15:01:01 一条普通日志。
2021/12/22 15:01:01 一条普通日志。
2021/12/22 15:01:01 一条触发fatal的日志。

以上这些函数的使用方法和 fmt 包完全相同,具体 fmt 包的介绍上一篇已经介绍过了,>>传送门。通过查看源码可以发现:

  • log.Fatal [ln|f] 实际上是调用的 Printf [ln|f] 之后,又调用了 os.Exit(1) 退出程序。
  • log.Panic [ln|f] 实际上是调用的 Printf [ln|f] 之后,又调用了 panic()函数,抛出一个恐慌。
  • 而 Print[ln|f] 实际上是调用的 Output() 函数。

函数 Output() 的源码:

代码语言:javascript
复制
func (l *Logger) Output(calldepth int, s string) error {
 now := time.Now() // get this early.
 var file string
 var line int
 l.mu.Lock()
 defer l.mu.Unlock()
 if l.flag&(Lshortfile|Llongfile) != 0 {
  // Release lock while getting caller info - it's expensive.
  l.mu.Unlock()
  var ok bool
  _, file, line, ok = runtime.Caller(calldepth)
  if !ok {
   file = "???"
   line = 0
  }
  l.mu.Lock()
 }
 l.buf = l.buf[:0]
 l.formatHeader(&l.buf, now, file, line)
 l.buf = append(l.buf, s...)
 if len(s) == 0 || s[len(s)-1] != '\n' {
  l.buf = append(l.buf, '\n')
 }
 _, err := l.out.Write(l.buf)
 return err
}

可以发现:

  1. 函数使用互斥锁来保证多个 goroutine 写日志的安全,且在调用 runtime.Caller() 之前,先释放了互斥锁,等获取到信息后再加锁来保证安全。
  2. 使用 formatHeader() 函数来格式化日志的信息,然后保存到 buf 中,然后再把日志信息追加到 buf 的末尾,然后再通过判断,查看日志是否为空或末尾不是 \n,如果是就再把 \n 追加到 buf 的末尾,最后将日志信息输出。

配置logger

默认情况下的 logger 只提供了日志的时间信息,log 标准库还提供了一些定制的方法。可以得到更多信息,例如记录该日志的文件名和行号等。

Flags

log标准库中的 Flags 函数会返回标准 logger 的输出配置,而 SetFlags 函数用来设置标准 logger 的输出配置。

代码语言:javascript
复制
func Flags() int
func SetFlags(flag int)

log 标准库提供了如下的 flag 选项,它们是一系列定义好的常量。

代码语言:javascript
复制
const (
    // 控制输出日志信息的细节,不能控制输出的顺序和格式。
    // 输出的日志在每一项后会有一个冒号分隔:例如2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
    Ldate         = 1 << iota     // 日期:2009/01/23
    Ltime                         // 时间:01:23:23
    Lmicroseconds                 // 微秒级别的时间:01:23:23.123123(用于增强Ltime位)
    Llongfile                     // 文件全路径名+行号: /a/b/c/d.go:23
    Lshortfile                    // 文件名+行号:d.go:23(会覆盖掉Llongfile)
    LUTC                          // 使用UTC时间
    LstdFlags     = Ldate | Ltime // 标准logger的初始值
)

示例

代码语言:javascript
复制
func main() {
    log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)
    log.Println("一条很普通的日志。")
}

//输出
//2021/12/22 15:09:08.290930 /box/main.go:7: 一条很普通的日志。

日志前缀 Prefix

Prefix 函数查看标准 logger 的输出前缀,SetPrefix 函数用来设置输出前缀。

代码语言:javascript
复制
func Prefix() string
func SetPrefix(prefix string)

示例

代码语言:javascript
复制
func main() {
 log.SetPrefix("[info]")
 log.Println("一条普通的日志")
 fmt.Println(log.Prefix())
}

//输出
//[info]2021/12/22 15:15:28 一条普通的日志
//[info]

输出位置 Output

SetOutput 函数用来设置标准 logger 的输出目的地,默认是标准错误输出。

代码语言:javascript
复制
func SetOutput(w io.Writer)

示例

代码语言:javascript
复制
func main() {
 logFile, err := os.OpenFile("./test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
 if err != nil {
  fmt.Println("open log file failed, err:", err)
  return
 }
 log.SetOutput(logFile)
 log.SetFlags(log.Lshortfile | log.Lmicroseconds | log.Ldate)
 log.SetPrefix("[info]")
 log.Println("一条很普通的日志")
}

自定义logger

lo g标准库中还提供了一个创建新 logger 对象的构造函数 New,支持我们创建自己的logger。

代码语言:javascript
复制
func New(out io.Writer, prefix string, flag int) *Logger {
 return &Logger{out: out, prefix: prefix, flag: flag}
}
  • New 创建一个 Logger 对象
  • 参数 out 设置日志信息写入的目的地
  • 参数 prefix 日志前缀,会添加到生成的每一条日志前面
  • 参数 flag 定义日志的属性(时间、文件等等)

示例

代码语言:javascript
复制
func main() {
 logger := log.New(os.Stdout, "<info>", log.Lshortfile|log.Lmicroseconds|log.Ldate)
 logger.Println("自定义的 logger 日志")
}

//输出
//<info>2021/12/22 23:30:16.283401 main.go:10: 自定义的 logger 日志

由于 G o内置的 log 库功能有限,在实际的项目中可以根据自己的需要选择使用第三方的日志库,如logrus、zap等。

图片及部分相关技术知识点来源于网络搜索,侵权删!

参考资料:

https://www.jianshu.com/p/66c75589d6b5

https://www.cnblogs.com/flippedxyy/p/15558771.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微客鸟窝 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 函数
    • 函数 Output() 的源码:
    • 配置logger
      • Flags
        • 日志前缀 Prefix
          • 输出位置 Output
            • 自定义logger
            相关产品与服务
            日志服务
            日志服务(Cloud Log Service,CLS)是腾讯云提供的一站式日志服务平台,提供了从日志采集、日志存储到日志检索,图表分析、监控告警、日志投递等多项服务,协助用户通过日志来解决业务运维、服务监控、日志审计等场景问题。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档