
本文介绍两种主流方法:一是通过 log.setoutput() 统一接管 go 标准日志输出;二是借助系统命令(如 logger 或重定向)捕获所有运行时输出(含编译错误、panic、标准错误流),适用于本地开发与服务器部署场景。
在 Go 应用开发中,仅重定向 HTTP 框架(如 Martini)的日志远不足以覆盖全部运行时信息。真正的“全量日志”需包含三类内容:
- ✅ 应用内 log.Printf / log.Fatalln 等标准日志
- ✅ 运行时 panic 堆栈(默认打印到 stderr)
- ❌ 编译期错误(如 go run 时包下载失败)——这类属于构建过程输出,无法被 Go 程序内捕获,必须由 shell 层面重定向
方法一:统一接管 Go 标准日志(推荐用于应用内日志)
使用 log.SetOutput() 可全局替换默认日志输出目标,无需修改每个 log.Xxx() 调用:
package main
import (
"log"
"os"
)
func init() {
// 打开日志文件(追加模式)
f, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
log.Fatal("无法打开日志文件:", err)
}
// 将所有 log.* 输出重定向至此文件
log.SetOutput(f)
}
func main() {
log.Println("服务已启动")
// 即使在其他包或中间件中调用 log.Println,也会写入 app.log
}⚠️ 注意:此方式不捕获 panic 堆栈(panic 默认走 os.Stderr),也不捕获 fmt.Print*、第三方库未使用 log 包的输出。
方法二:Shell 层面全量重定向(覆盖 panic、stderr、构建错误)
在 Unix/macOS 系统中,直接通过 shell 重定向 stderr 和 stdout 到文件或 syslog:
# 方式 A:直接写入文件(最简单,推荐服务器部署) go run MainPackageFile.go > app.log 2>&1 # 方式 B:通过 logger 写入系统日志(支持日志轮转、优先级标记) go run MainPackageFile.go 2>&1 | logger -t "my-go-app" -p local0.info # 方式 C:指定自定义日志文件(需配合 logger -f) # 先创建命名管道(可选),或使用 systemd-journald 等更健壮方案
Windows 用户可使用:
go run MainPackageFile.go 2>&1 > app.log
最佳实践建议
- 开发阶段:用 go run ... > log.txt 2>&1 快速验证全量输出
- 生产部署:结合 systemd(Linux)或 supervisord,配置 StandardOutput=journal + StandardError=journal,再用 journalctl -u myapp.service -f 实时追踪
- 增强可靠性:对关键 panic,可注册 recover + log 显式记录,但切勿替代 shell 重定向——因为未捕获的 panic 仍会输出到 stderr
总之,log.SetOutput() 解决「应用日志归一化」,而 shell 重定向解决「运行时全流捕获」。二者互补,缺一不可。










