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

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信息维度。

相关文章:

  • JavaScript数组-数组中新增元素
  • 区块链(13):FISCO BCOS简介及安装
  • 智能指针讲解
  • 深度学习与人工智能资料推荐:DeepSeek整合包全解析
  • 智享AI直播三代系统,马斯克旗下AI人工智能直播工具,媲美DeepSeek!
  • 大摩闭门会:250218 学习总结报告
  • 排序算法:冒泡排序
  • ARM64 Trust Firmware [四]
  • 【鸿蒙开发】第三十八章 ArkTS代码调试
  • Spotify AI 技术(1)使用 TensorFlow 和 TF-Agents
  • 电脑机箱散热风扇声音大的影响因素
  • Linux I2C 命令
  • 最小二乘法原理分析
  • C语言指针学习笔记
  • 深入浅出TypedArray:网络数据处理、WebGPU与加密实战
  • 从入门到跑路(六)k8s配置ingress-nginx
  • 代码随想录算法【Day50】
  • Pycharm中查找与替换
  • 计算机网络-OSI七层参考模型与数据封装,网络安全零基础入门到精通实战教程!
  • ZLMediaKit Windows 编译指南
  • 董军同德国国防部长举行会谈
  • 外交部:国际社会广泛理解和支持中方不同意台参加世卫大会的决定
  • 全国人大常委会今年将初次审议检察公益诉讼法
  • 特朗普访问卡塔尔,两国签署多项合作协议
  • 网约车座椅靠背张贴“差评者得癌症”,如祺出行:未收到投诉无法处理
  • KPL“王朝”诞生背后:AG和联赛一起迈向成熟