当前位置: 首页 > article >正文

golang panic信息捕获

背景

我们的日志接入阿里云sls平台,但是,日志是以json的格式存储在阿里云sls平台上,程序中产生的error,info等日志都可以实现以json的格式打印。但是,golang程序中产生的panic信息本身不是以json的格式输出,这就导致panic信息在阿里云sls平台上不方便检索。

基于上述痛点,我们期望捕获程序的panic信息,并且以json的格式打印,如此,我们就可以方便的实现在阿里云sls平台上检索的目的。

解决方案

核心的思路

通过deferrecover()机制捕获panic信息,结合Go的JSON序列化能力,将堆栈信息、错误内容等关键数据封装为结构化JSON格式。

实现步骤

定义日志的结构体

日志结构体定义:

type PanicLog struct {
	Timestamp string `json:"@timestamp"`
	Level     string `json:"level"`
	Message   string `json:"message"`
	Stack     string `json:"stack"`
	Service   string `json:"service"`
}

 封装打印日志的方法

func logPanicAsJSON(panicObj interface{}) {
	stack := string(debug.Stack()) // 获取完整堆栈

	logEntry := PanicLog{
		Timestamp: time.Now().Format(time.RFC3339),
		Level:     "PANIC",
		Message:   fmt.Sprintf("%v", panicObj),
		Stack:     stack,
		Service:   "your-service-name",
	}

	jsonData, _ := json.Marshal(logEntry)
	// 输出到SLS(根据实际日志库选择方式)
	log.Println(string(jsonData) )
}

封装方法捕获panic

defer func() {
			if r := recover(); r != nil {
				logPanicAsJSON(r) // 记录 panic 信息
				c.AbortWithStatus(http.StatusInternalServerError)
			}
}()

测试案例

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"runtime/debug"
	"time"
)

type PanicLog struct {
	Timestamp string `json:"@timestamp"`
	Level     string `json:"level"`
	Message   string `json:"message"`
	Stack     string `json:"stack"`
	Service   string `json:"service"`
}

func main() {
	defer func() {
		if r := recover(); r != nil {
			// 捕获panic信息并转换为JSON
			logPanicAsJSON(r)
			os.Exit(1)
		}
	}()
	// 业务代码...
	testPanic()
	time.Sleep(1 * time.Second)
}

func testPanic() {
	// nil指针引发panic
	var a *int
	*a = 1
}

func logPanicAsJSON(panicObj interface{}) {
	stack := string(debug.Stack()) // 获取完整堆栈

	logEntry := PanicLog{
		Timestamp: time.Now().Format(time.RFC3339),
		Level:     "PANIC",
		Message:   fmt.Sprintf("%v", panicObj),
		Stack:     stack,
		Service:   "your-service-name",
	}

	jsonData, _ := json.Marshal(logEntry)
	// 输出到SLS(根据实际日志库选择方式)
	log.Println(string(jsonData))
}

注意事项

在Go语言里,recover() 函数只能捕获当前goroutine内产生的 panic

所以,在下面的这个案例中recover不能捕获到panic信息。如果需要捕获到,需要在每个协程中都执行recover的逻辑。

func main() {
	defer func() {
		if r := recover(); r != nil {
			// 捕获panic信息并转换为JSON
			logPanicAsJSON(r)
			os.Exit(1)
		}
	}()
	// 业务代码...
	go func() {
		testPanic()
	}()
	time.Sleep(1 * time.Second)
}

扩展优化

日志结构体中增加traceId信息维度。


http://www.kler.cn/a/554430.html

相关文章:

  • jmeter接口测试(一)
  • 微服务入门-笔记
  • 汽车长期不保养的危害
  • NVIDIA和AMD显卡型号解读
  • 读书笔记:要点提炼《基于大模型的RAG应用开发与优化——构建企业级LLM应用》(严灿平)
  • 芯谷D668:便携式录音机与耳机式盒式录音机的理想音频解决方案
  • <2.20>Leetcode哈希、双指针
  • Kafka Connect 数据格式转换器
  • 微信小程序:多菜单栏设计效果
  • 基于Spring Boot的图书管理系统设计与实现(LW+源码+讲解)
  • 2025年archlinux tigervnc分辨率设置不生效的问题
  • Maven 构建报告与文档生成
  • 界面控件Telerik UI for Blazor 2024 Q4新版亮点 - 轻松实现日程自定义
  • Unity3D 使用 ILRuntime 时的性能问题详解
  • 排查生产sql查询缓慢
  • Rust 与 WebAssembly 结合的优势
  • Pycharm安装教程超详细图文教程,超详细Pycharm安装保姆级教程
  • 用AI学历史1——中国通史
  • cenos 安装 /usr/local/nginx/sbin/nginx这个路径的nginx
  • MySQL版本选择与安装