Chinaunix首页 | 论坛 | 博客
  • 博客访问: 54413
  • 博文数量: 22
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 232
  • 用 户 组: 普通用户
  • 注册时间: 2020-11-30 14:45
个人简介

专注流媒体、视频物联网、云计算、大数据开发

文章分类

全部博文(22)

文章存档

2021年(18)

2020年(4)

我的朋友

分类: Java

2021-11-18 17:06:32

我们团队经常会对我们现有视频平台比如 EasyNVR、EasyGBS 等进行版本更新以及不同系统的适配测试,在 EasyNVR 测试版本中,出现程序异常退出的情况,但是日志中查找不到对应的错误。

这个问题我们可以通过对 Go 语言捕获错误的功能进行排查和整理。一般情况下,采用defer func(){recover() …} 类似的函数捕获程序中的错误,但是 recover() 函数在以下三种情况下是捕获不到对应的异常:

1.新运行了一个子协程,如果子协程中出现 panic 错误,是无法捕获的;
2.如果在程序中直接 os.Exit(0),对应的 defer 函数也不会运行,整个程序直接退出;
3.如果发生致命错误,recover() 无法捕获,例如以下的代码,并不能被捕获到。

defer func() { err := recover() if err != nil { fmt.Print("err=", err) } }() a := "hello world" sh := (*reflect.StringHeader)(unsafe.Pointer(&a)) bh := reflect.SliceHeader{ Data: sh.Data, Len: sh.Len, Cap: sh.Len, } b := *(*[]byte)(unsafe.Pointer(&bh)) b[0] = 'H'

运行过程中程序会直接出现一个致命异常,导致整个程序崩溃退出。

但是该种情况下,无法写入到日志,因此在程序运行中只有通过控制台才能看到对应的日志。针对此种情况,需要对代码进行处理。

在 Windows 系统中,修改的代码如下:

package elog import ( "os" "syscall" ) var ( kernel32 = syscall.MustLoadDLL("kernel32.dll") procSetStdHandle = kernel32.MustFindProc("SetStdHandle") ) func setStdHandle(stdhandle int32, handle syscall.Handle) error { r0, _, e1 := syscall.Syscall(procSetStdHandle.Addr(), 2, uintptr(stdhandle), uintptr(handle), 0) if r0 == 0 { if e1 != 0 { return error(e1) } return syscall.EINVAL } return nil } // RedirectStderr to the file passed in func RedirectStderr() (err error) { logFile, err := os.OpenFile("./test-error.log", os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_APPEND, 0644) if err != nil { return } err = setStdHandle(syscall.STD_ERROR_HANDLE, syscall.Handle(logFile.Fd())) if err != nil { return } // SetStdHandle does not affect prior references to stderr os.Stderr = logFile return }

在 Linux 系统中,修改的代码如下:

package elog import ( "os" "syscall" ) // RedirectStderr to the file passed in func RedirectStderr() (err error) { logFile, err := os.OpenFile("./test-error.log", os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_APPEND, 0644) if err != nil { return } err = syscall.Dup3(int(logFile.Fd()), int(os.Stderr.Fd()),0) if err != nil { return } return }

main函数中调用代码

elog.RedirectStderr()

最终如果出现 fatal 代码,就写入到 test-error.log 中。


阅读(776) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~