当前位置:网站首页>If the program exits abnormally, how to catch the fatal error through the go language?

If the program exits abnormally, how to catch the fatal error through the go language?

2022-06-24 01:25:00 Tsingsee green rhino video

Our team often reviews our existing video platforms, such as EasyNVR、EasyGBS Version update and adaptation test of different systems , stay EasyNVR In the beta version , The program exits abnormally , But the corresponding error cannot be found in the log .

We can solve this problem by Go The function of language capturing errors for troubleshooting and sorting . In general , use defer func(){recover() …} Similar functions capture errors in programs , however recover() The function cannot catch the corresponding exception in the following three cases :

1. A new subprocess is running , If... Occurs in the subprocess panic error , It can't be captured ; 2. If directly in the program os.Exit(0), Corresponding defer Functions do not run , The whole program exits directly ; 3. If a fatal error occurs ,recover() Unable to capture , For example, the following code , Can't be captured .

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'

A fatal exception will appear directly in the program during operation , Cause the whole program to crash and exit .

But in this case , Unable to write to log , Therefore, the corresponding log can be seen only through the console when the program is running . In this case , The code needs to be processed .

stay Windows In the system , The modified code is as follows :

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
}

stay Linux In the system , The modified code is as follows :

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 Calling code in function

elog.RedirectStderr()

Eventually, if fatal Code , Just write it to test-error.log in , That is, the following documents :

原网站

版权声明
本文为[Tsingsee green rhino video]所创,转载请带上原文链接,感谢
https://yzsam.com/2021/11/20211118173422815r.html