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
}
可以发现:
- 函数使用互斥锁来保证多个 goroutine 写日志的安全,且在调用 runtime.Caller() 之前,先释放了互斥锁,等获取到信息后再加锁来保证安全。
- 使用 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