1. 前言
日志是开发人员的眼睛和耳朵,可以用来跟踪、调试和分析代码。基于此,标准库提供了log包,可以对日志做一些最基本的配置。根据 特殊需要,开发人员还可以自己定制日志记录器。
2. Log包
package test
import (
"fmt"
"log"
"testing"
)
func init() {
log.SetPrefix("Gopher:")
log.SetFlags(log.Ldate | log.Lmicroseconds | log.Llongfile)
}
func TestLog(t *testing.T) {
// Println 写到标准日志记录器
log.Println("message")
// Fatalln 在调用 Println()之后会接着调用 os.Exit(1)
log.Fatalln("fatal message")
// Panicln 在调用 Println()之后会接着调用 panic()
log.Panicln("panic message")
fmt.Println("hello!") //这句代码是不会执行到的,因为程序已经退出或报panic了
}
输出结果:
=== RUN TestLog
Go-serve:2023/03/27 11:02:34.333911 d:/learnspace/gogo/test/log_test.go:18: message
Go-serve:2023/03/27 11:02:34.355644 d:/learnspace/gogo/test/log_test.go:19: fatal message
FAIL gogo/test 1.056s
log.Fatalln() 和 log.Panicln() 都会使得测试结果 FAIL
log有三个方法Println、Fatalln 和 Panicln 来写日志消息。 这些函数也有可以格式化消息的版本,只需要用 f 替换结尾的 ln。Fatal 系列函数用来写日志 消息,然后使用 os.Exit(1)终止程序。Panic 系列函数用来写日志消息,然后触发一个 panic。 除非程序执行 recover 函数,否则会导致程序打印调用栈后终止。
2.1 设置日志输出格式
func init() {
log.SetPrefix("Gopher:")
log.SetFlags(log.Ldate | log.Lmicroseconds | log.Llongfile)
}
通过init()进行日志输出的格式设定
2.1.1 SetFlags参数
const (
// 将下面的位使用或运算符连接在一起,可以控制要输出的信息。没有
// 办法控制这些信息出现的顺序(下面会给出顺序)或者打印的格式
// (格式在注释里描述)。这些项后面会有一个冒号:
// 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
// 日期: 2009/01/23
Ldate = 1 << iota
// 时间: 01:23:23
Ltime
// 毫秒级时间: 01:23:23.123123。该设置会覆盖 Ltime 标志
Lmicroseconds
// 完整路径的文件名和行号: /a/b/c/d.go:23
Llongfile
// 最终的文件名元素和行号: d.go:23
// 覆盖 Llongfile
Lshortfile
// 标准日志记录器的初始值
LstdFlags = Ldate | Ltime
)
log 包有一个很方便的地方就是,这些日志记录器是多 goroutine 安全的。这意味着在多个 goroutine 可以同时调用来自同一个日志记录器的这些函数,而不会有彼此间的写冲突。
2.1.2 SetOutput 指定输出文件
package log
import (
"log"
"os"
"path/filepath"
"testing"
)
var strWorkDir string
var separator string
func init() {
strWorkDir, _ = os.Getwd() //获取文件所在路径
separator = string(filepath.Separator) //文件地址分隔符
logFileName := "log.txt"
logFilePath := filepath.Join(strWorkDir, logFileName)
var file *os.File
_, err := os.Stat(logFilePath) // 检查文件是否存在
if os.IsNotExist(err) { // 文件不存在则创建
file, err = os.Create(logFilePath)
if err != nil {
panic(err)
}
} else if err != nil {
panic(err)
} else { // 文件存在则打开
file, err = os.OpenFile(logFilePath, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
panic(err)
}
}
log.SetOutput(file)
log.SetPrefix("Gopher:")
log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)
}
func TestLog(t *testing.T) {
// Println 写到标准日志记录器
log.Println("message...")
log.Fatalln("fatal...")
log.Panicln("panicln...")
}
log.txt
Gopher:2023/03/27 17:07:36 d:/learnspace/gogo/test/log/log_test.go:50: message...
Gopher:2023/03/27 17:07:36 d:/learnspace/gogo/test/log/log_test.go:51: fatal...
2.2 定制的日志记录器
要想创建一个定制的日志记录器,需要创建一个 Logger 类型值。可以给每个日志记录器配 置一个单独的目的地,并独立设置其前缀和标志
logger := log.New(os.Stdout, "Gopher:", log.Lshortfile|log.Ldate|log.Ltime)
logger.Println("logger message....")
Gopher:2023/03/27 17:14:34 d:\learnspace\gogo\test\log\log_test.go:53: logger message....
参考书籍《Go语言实战》