Debian下Golang日志异常处理全流程指南
Golang中未被捕获的panic会导致程序崩溃,需通过defer和recover捕获并记录异常信息。以下是标准库与第三方库的实现示例:
log包:通过defer注册恢复函数,将异常信息写入日志。package main
import (
"log"
"os"
)
func main() {
log.SetOutput(os.Stdout) // 输出到标准输出
log.SetFlags(log.LstdFlags | log.Lshortfile) // 添加时间、文件名及行号
defer func() {
if r := recover(); r != nil {
log.Printf("【系统异常】%v", r) // 记录异常信息
}
}()
panic("模拟运行时异常") // 触发异常
}
logrus:通过WithFields添加结构化字段,提升日志可读性。package main
import (
"github.com/sirupsen/logrus"
)
func main() {
logrus.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
logrus.SetReportCaller(true) // 显示调用者信息
defer func() {
if r := recover(); r != nil {
logrus.WithFields(logrus.Fields{
"error": r,
"file": "main.go",
"line": 20,
}).Error("【致命异常】程序崩溃")
}
}()
panic("模拟业务异常")
}
zap:高性能日志库,适合生产环境,通过Error方法记录异常。package main
import (
"go.uber.org/zap"
)
func main() {
logger, _ := zap.NewProduction() // 生产环境配置
defer logger.Sync() // 确保日志刷新到磁盘
defer func() {
if r := recover(); r != nil {
logger.Error("【运行时异常】",
zap.String("error", fmt.Sprintf("%v", r)),
zap.String("stack", string(debug.Stack())), // 记录堆栈信息
)
}
}()
panic("模拟数据库异常")
}
通过日志级别区分异常严重程度,避免无关日志干扰排查:
DEBUG(调试)、INFO(常规信息)、WARN(警告)、ERROR(错误)、FATAL(致命,需终止程序)。logrus为例,通过环境变量或代码动态调整:import (
"github.com/sirupsen/logrus"
"os"
)
func init() {
level := os.Getenv("LOG_LEVEL") // 从环境变量读取级别
switch level {
case "DEBUG":
logrus.SetLevel(logrus.DebugLevel)
case "ERROR":
logrus.SetLevel(logrus.ErrorLevel)
default:
logrus.SetLevel(logrus.InfoLevel)
}
}
使用JSON等结构化格式记录日志,便于日志分析工具(如ELK)解析:
package main
import (
"github.com/sirupsen/logrus"
)
func main() {
logrus.SetFormatter(&logrus.JSONFormatter{}) // 设置JSON格式
logrus.WithFields(logrus.Fields{
"service": "user-service",
"endpoint": "/login",
"error": "invalid password",
"status": 401,
}).Error("【登录失败】密码错误")
}
输出结果:
{"level":"error","msg":"【登录失败】密码错误","service":"user-service","endpoint":"/login","error":"invalid password","status":401,"time":"2025-10-07T14:30:00+08:00"}
使用lfshook库实现日志自动轮换,避免单一日志文件占用过多磁盘空间:
package main
import (
"github.com/sirupsen/logrus"
"github.com/rifflock/lfshook"
"path/filepath"
)
func main() {
log := logrus.New()
// 配置日志轮换路径(按级别分开存储)
pathMap := lfshook.PathMap{
logrus.InfoLevel: filepath.Join("/var/log", "app-info.log"),
logrus.ErrorLevel: filepath.Join("/var/log", "app-error.log"),
}
hook := lfshook.NewHook(pathMap, &logrus.JSONFormatter{})
log.Hooks.Add(hook)
log.Info("【常规日志】程序启动成功")
log.Error("【错误日志】数据库连接失败")
}
ERROR级别日志数量),结合Alertmanager设置阈值告警(如1分钟内超过5次ERROR则发送邮件/短信通知)。go mod tidy清理无用依赖,确保依赖库版本兼容,避免因库bug导致的异常。通过以上步骤,可全面覆盖Debian下Golang日志异常的处理流程,从捕获异常、记录日志到分析排查,提升系统稳定性与可维护性。