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

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

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

函数

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

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{})
复制代码

示例

//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的日志。")
复制代码

运行结果

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

以上这些函数的使用方法和 fmt 包完全相同。通过查看源码可以发现:

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

函数 Output() 的源码:

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 的输出配置。

func Flags() int
func SetFlags(flag int)
复制代码

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

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的初始值
)
复制代码

示例

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 函数用来设置输出前缀。

func Prefix() string
func SetPrefix(prefix string)
复制代码

示例

func main() {
  log.SetPrefix("[info]")
  log.Println("一条普通的日志")
  fmt.Println(log.Prefix())
}
//输出
//[info]2021/12/22 15:15:28 一条普通的日志
//[info]
复制代码

输出位置 Output

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

func SetOutput(w io.Writer)
复制代码

示例

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

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

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

示例

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 日志
复制代码

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

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
3天前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
16 4
|
3天前
|
缓存 监控 前端开发
在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统
本文深入探讨了在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统。
27 1
|
6天前
|
Go
go语言中的continue 语句
go语言中的continue 语句
17 3
|
7天前
|
安全 Go 调度
探索Go语言的并发模型:goroutine与channel
在这个快节奏的技术世界中,Go语言以其简洁的并发模型脱颖而出。本文将带你深入了解Go语言的goroutine和channel,这两个核心特性如何协同工作,以实现高效、简洁的并发编程。
|
8天前
|
Go
go语言中的 跳转语句
【11月更文挑战第4天】
17 4
|
8天前
|
JSON 安全 Go
Go语言中使用JWT鉴权、Token刷新完整示例,拿去直接用!
本文介绍了如何在 Go 语言中使用 Gin 框架实现 JWT 用户认证和安全保护。JWT(JSON Web Token)是一种轻量、高效的认证与授权解决方案,特别适合微服务架构。文章详细讲解了 JWT 的基本概念、结构以及如何在 Gin 中生成、解析和刷新 JWT。通过示例代码,展示了如何在实际项目中应用 JWT,确保用户身份验证和数据安全。完整代码可在 GitHub 仓库中查看。
40 1
|
1天前
|
存储 Go PHP
Go语言中的加解密利器:go-crypto库全解析
在软件开发中,数据安全和隐私保护至关重要。`go-crypto` 是一个专为 Golang 设计的加密解密工具库,支持 AES 和 RSA 等加密算法,帮助开发者轻松实现数据的加密和解密,保障数据传输和存储的安全性。本文将详细介绍 `go-crypto` 的安装、特性及应用实例。
11 0
|
16天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
137 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
1月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
234 3
|
1月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1638 14
下一篇
无影云桌面