日志log
作者: ryan 发布于: 2025/11/28 更新于: 2025/11/28 字数: 0 字 阅读: 0 分钟
Go 标准库的 log 包以极简、稳定、并发安全著称,整个包只有约 600 行代码,却足以应对绝大多数日常日志需求。
使用示例
go
log.Println("普通日志")
log.Fatalln("致命错误") // 打印后调用 os.Exit(1)
log.Panicln("触发 panic") // 打印后调用 panic()输出:
go
2025/11/26 10:30:45 普通日志
2025/11/26 10:30:45 致命错误
exit status 1
注意:Fatal 系列会退出进程,Panic 系列可被 recover 捕获。
核心数据结构
go
type Logger struct {
mu sync.Mutex // 全局互斥锁,确保并发安全
prefix string // 每行日志前缀
flag int // 格式控制标志位
out io.Writer // 输出目标,默认 os.Stderr
buf []byte // 临时缓冲区,减少内存分配
}整个包的功能全部围绕这一个结构体展开,极致简洁。
全局默认 Logger
Logger 是所有包级函数的真正实现
go
// log/log.go 源码(简化)
var std = New(os.Stderr, "", LstdFlags)
// 所有包级函数都是 std 的薄包装
func Println(v ...any) { std.Output(2, fmt.Sprintln(v...)) }
func Printf(format string, v ...any) { std.Output(2, fmt.Sprintf(format, v...)) }
func Fatal(v ...any) { std.Output(2, fmt.Sprintln(v...)); os.Exit(1) }
func Panic(v ...any) { std.Output(2, fmt.Sprintln(v...)); panic(...) }因此以下三者完全等价
go
log.Println("hello") // 最常见
log.Default().Println("hello") // 显式获取默认 logger(Go 1.17+)
std.Println("hello") // 直接使用包级变量(内部就是 *Logger)
工厂函数 New
go
func New(out io.Writer, prefix string, flag int) *Logger {
return &Logger{out: out, prefix: prefix, flag: flag}
}把参数塞进结构体,返回指针。
日志格式标志位
go
const (
Ldate = 1 << iota // 2025/11/26
Ltime // 10:30:45
Lmicroseconds // 微秒精度 10:30:45.123123
Llongfile // 完整路径 /path/to/main.go:23
Lshortfile // 短路径 main.go:23
LUTC // 使用 UTC 时间
)
const LstdFlags = Ldate | Ltime // 默认值
常用组合示例:
go
log.New(os.Stderr, "[INFO] ", Ldate|Ltime|Lmicroseconds|Lshortfile)
// 输出:[INFO] 2025/11/26 10:30:45.123456 main.go:23 hello
方法接收者与调用方式
所有核心方法都是指针接收者 func (l *Logger) Println(...)
std 本身就是*Logger类型(指针)因此直接可以写为 std.Println(...)
错误示范(能编译但多余)
go
(&std).Println("hi") // 多此一举
(*std).Println("hi") // 同上
自定义 Logger
go
// 通常放在包级变量
var logger = log.New(
os.Stdout,
"[MYAPP] ",
log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile,
)
func main() {
logger.Println("服务器启动")
logger.Printf("用户 %s 从 %s 登录", user, ip)
logger.Fatal("配置加载失败")
}
模块化日志示例:
go
// db/logger.go
var DB = log.New(os.Stderr, "[DB] ", log.LstdFlags|log.Lshortfile)
// http/logger.go
var HTTP = log.New(os.Stderr, "[HTTP] ", log.LstdFlags|log.Lshortfile)
全局只有一个
*Logger实例 , 所有函数都是它的快捷方式
