log.printf 默认不输出时间戳,因 log 包初始未设置 log.lstdflags(含 log.ldate | log.ltime);需显式调用 log.setflags 启用,且为覆盖非叠加;自定义前缀应使用 log.new 创建独立 logger 实例,避免修改全局 logger。

log.Printf 为什么打不出时间戳?
默认 log.Printf 不带时间戳,是因为 Go 标准库的 log 包初始配置只启用了 log.Lshortfile 或 log.LstdFlags 中的一个——而 log.LstdFlags 才控制日期/时间输出。没设它,就只有纯文本。
- 正确启用时间戳:
log.SetFlags(log.LstdFlags)(含日期+时间+文件行号) - 只要时间不要文件信息:
log.SetFlags(log.Ldate | log.Ltime) - 如果已调用过
log.SetFlags,后续再设会覆盖,不是叠加 - 注意:
log.LstdFlags=log.Ldate | log.Ltime | log.Lshortfile,别误以为它是“默认开启”的
如何给每条日志加统一前缀(比如 [API] 或 [DB])?
标准 log 包不支持运行时动态前缀,但可以用 log.New 创建带前缀的独立 logger 实例,比改全局 log 更安全、更可控。
- 创建带前缀的 logger:
apiLogger := log.New(os.Stdout, "[API] ", log.LstdFlags) - 前缀字符串末尾最好带空格,否则
[API]2024/05/01...会粘连 - 避免直接修改
log.Default()的 prefix——多个包可能依赖默认 logger,改了会影响其他模块 - 不同模块用不同 logger 实例,比如
dbLogger、cacheLogger,互不干扰
为什么自定义 logger 调用 Println 后没输出?
常见原因是 logger 的 writer 设成了 io.Discard 或 nil,或者被重定向到一个已关闭的文件句柄。
- 检查 writer 是否有效:
logger := log.New(os.Stdout, "", 0)是最简可用组合 - 若写文件,确保
os.OpenFile没报错,且 flag 包含os.O_CREATE | os.O_APPEND | os.O_WRONLY - Windows 下路径含中文或空格时,
os.OpenFile("日志.log", ...)可能静默失败,建议先os.Stat验证路径可访问 - goroutine 中使用 logger 时,别在 defer 里 close 文件——可能 logger 还在写,就 panic 了
log 包性能差?要不要换 zap 或 zerolog?
标准 log 包是同步、无缓冲、无异步队列的,高并发写日志(比如每秒上千条)时确实会卡 goroutine。但它足够轻量,适合 CLI 工具、小服务或调试阶段。
- 单机 QPS log 完全够用,不用提前过度优化
- 想保留标准接口又提升性能?可用
golang.org/x/exp/slog(Go 1.21+),它支持 Handler 抽象,可桥接 zap - 替换为 zap 时,注意
zap.NewProduction()默认禁用 caller(即不打文件行号),需显式加zap.AddCaller() - 如果只是想加 JSON 输出,别硬套 zap——用
slog.NewJSONHandler(os.Stdout, nil)更轻量
log.New + 合理 SetFlags 就能撑住;真正卡点往往不在日志本身,而在日志写入目标(比如 NFS 挂载点延迟高,或磁盘满导致 write block)。先确认瓶颈在哪,再决定要不要动 logger。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











