前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >程序异常退出,如何通过Go语言捕获fatal错误?

程序异常退出,如何通过Go语言捕获fatal错误?

原创
作者头像
TSINGSEE青犀视频
修改于 2021-11-18 09:31:22
修改于 2021-11-18 09:31:22
3.6K00
代码可运行
举报
文章被收录于专栏:TSINGSEE青犀视频TSINGSEE青犀视频
运行总次数:0
代码可运行

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

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 系统中,修改的代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 系统中,修改的代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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函数中调用代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
elog.RedirectStderr()

最终如果出现 fatal 代码,就写入到 test-error.log 中,也就是以下文件:

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Go语言的文件处理:详细指南
该代码示例展示了如何逐行读取名为example.txt的文件,并将每一行打印到控制台。
数字扫地僧
2024/06/25
1690
Go语言写文件几种方式性能对比
方式2比方式1略快,但是重复次数多了后会报错,应该是defer被压栈太多导致系统撑不了太多打开的文件
李海彬
2018/07/26
1.2K0
Golang语言情怀--第101期 区块链技术-以太坊公链NFT图片去中心化存储-第2节:go语言实现IPFS存储demo
实际连接:https://ipfs.io/ipfs/+hash数据;访问上传到节点数据,上传后建议过几分钟后再去获取,确保已经同步到访问的节点数据。
李海彬
2022/12/14
4440
Golang语言情怀--第101期 区块链技术-以太坊公链NFT图片去中心化存储-第2节:go语言实现IPFS存储demo
Golang中文件目录操作的实现
       Golang中,文件是指计算机中存储数据的实体,文件可以是文本文件、二进制文件、配置文件等。在Go语言中,通过操作文件,我们可以读取文件的内容,写入数据到文件,以及获取文件的属性等。
周小末天天开心
2023/10/16
3610
Golang中文件目录操作的实现
Golang文件操作-上篇
1、读文件 2、写文件 3、文件指针 4、ioutil文件操作 4.1 readall读取文件所有内容 4.2 readfile直接读文件 4.3 writefile直接写文件 5、bufio带缓冲IO 5.1 scanner 逐行读取 5.2 带缓冲IO reader 5.2.1 read 读 5.2.2 readline 读 5.2.3 readstring、readslice 读 5.3 带缓冲IO writer 1、读文件 读文件的过程 文件位置 打开文件 读取文件内容(逐个字符读、按
仙人技术
2021/09/23
6480
Golang文件操作-上篇
Golang 语言中的 defer 怎么使用?
在 Golang 语言中,我们可以在函数(自定义和部分内置)或方法中使用 defer 关键字注册延迟调用(一个或多个),多个延迟调用的执行顺序是先进后出(FILO)。并且不会受到函数执行结束退出,显式调用 return 和主动(或被动)触发 panic 的影响,注册成功的所有延迟调用都会被执行,除非 defer 注册在 return 之后或者函数(或方法)调用 os.Exit(1)。
frank.
2021/06/22
4880
golang 大文件分割
golang 大文件分割 package main import ( "fmt" "io/ioutil" "math" "os" "strconv" ) const chunkSize int64 = 4 << 20 func main() { fileInfo, err := os.Stat("test.zip") if err != nil { fmt.Println(err) } num := int(math.Ceil
大师级码师
2021/11/02
1.8K0
聊聊golang的zap的WriteSyncer
序 本文主要研究一下golang的zap的WriteSyncer WriteSyncer zap@v1.16.0/zapcore/write_syncer.go type WriteSyncer interface { io.Writer Sync() error } WriteSyncer内嵌了io.Writer接口,定义了Sync方法 Writer /usr/local/go/src/io/io.go type Writer interface { Write(p []byte
code4it
2020/12/11
6680
GO语言文件的创建与打开实例分析
文件操作是个很重要的话题,使用也非常频繁,熟悉如何操作文件是必不可少的。Golang 对文件的支持是在 os package 里,具体操作都封装在 type File struct {} 结构体中。 一、func Open(name string) (file *File, err error) 再简单不过了,给一个路径给它,返回文件描述符,如果出现错误就会返回一个 *PathError。 这是一个只读打开模式,实际上就是 os.OpenFile() 的快捷操作,它的原型如下: func Open(nam
李海彬
2018/03/22
8360
EasyDSS 编译 Arm 版本出现 “undefined: syscall.Dup2”解决方式
由于很多用户的系统和程序都不同,因此TSINGSEE青犀视频研发团队往往需要根据用户的实际需求来对产品进行定制或者修改。有的客户需要 Arm 版本的 EasyDSS平台使用,因此我们也会在aarch64环境下编译EasyDSS。在编译过程中,出现报错 “undefined: syscall.Dup2”。
TSINGSEE青犀视频
2021/09/24
1.3K0
Go服务迁到K8s后老抽风重启? 记一次完整的线上问题解决过程
之前把Go服务都迁到Kubernetes上后有些服务的某个 Pod总是时不时的重启一下,通过查业务日志根本查不到原因,我分析了一下肯定是哪里代码不严谨造成引用空指针导致Go发送运行时panic才会挂掉的,但是容器重启后之前输出到stderr的panic是会被清空的,所以才有了这篇文章里后面的分析和方案解决。
KevinYan
2020/09/18
1.7K0
2.Go语言之文件操作学习记录.md
描述: 我们可以采用os包中的Open()函数打开一个文件,返回一个*File和一个err。然后对得到的文件实例调用Close()函数就能够关闭文件。
全栈工程师修炼指南
2022/09/29
4710
Go每日一库之93:mmap
mmap 另一个非常重要的特性是:减少内存的拷贝次数。在 linux 系统中,文件的读写操作通常通过 read 和 write 这两个系统调用来实现,这个过程会产生频繁的内存拷贝。比如 read 函数就涉及了 2 次内存拷贝:
luckpunk
2023/09/30
7030
Go语言核心36讲(Go语言实战与应用二十三)--学习笔记
我们在上一篇文章中。从“os.File类型都实现了哪些io包中的接口”这一问题出发,介绍了一系列的相关内容。今天我们继续围绕这一知识点进行扩展。
郑子铭
2021/12/09
6640
Go语言核心36讲(Go语言实战与应用二十三)--学习笔记
一篇文章带你搞定Go语言基础之文件操作
文件操作就简单了,像打开word了,excel了,都是文件操作,当然,我们肯定是不能直接操作word的
Go进阶者
2021/01/22
3210
Go:log库的全面指南与使用技巧
在Go语言的标准库中,log包提供了简单而强大的日志功能。日志记录是软件开发中不可或缺的一部分,它不仅帮助开发人员调试和排查问题,还在系统运行中提供了宝贵的运行时信息。本文将详细讲解Go语言log库的各种功能及其使用技巧,帮助开发者更好地掌握和应用这一重要工具。
运维开发王义杰
2024/05/29
1K0
Go:log库的全面指南与使用技巧
Go语言入门(九) 文件操作
文件操作 文件的基本操作 读文件 func readFile(){ filename := "./aaa.log" file, err := os.Open(filename) if err != nil { fmt.Printf("open %s is error,error %v\n",filename,err) return } //关闭文件句柄 defer func() { file.Close() }() //
alexhuiwang
2020/09/24
3790
Go基础--终端操作和文件操作
终端操作 操作终端相关的文件句柄常量 os.Stdin:标准输入 os.Stdout:标准输出 os.Stderr:标准错误输出 关于终端操作的代码例子: package main import "fmt" var ( firstName,lastName,s string i int f float32 input = "56.12/5212/Go" format = "%f/%d/%s" ) func main() { fmt.Println("pl
coders
2018/03/30
7290
聊聊golang的zap的WriteSyncer
序 本文主要研究一下golang的zap的WriteSyncer golang-15-728.jpg WriteSyncer zap@v1.16.0/zapcore/write_syncer.go type WriteSyncer interface { io.Writer Sync() error } WriteSyncer内嵌了io.Writer接口,定义了Sync方法 Writer /usr/local/go/src/io/io.go type Writer interfac
code4it
2020/12/09
9750
聊聊golang的zap的WriteSyncer
go语言文件操作汇总
bufio.Writer.WriteString 带缓冲的写,最后要将缓冲中的数据写入下层的io.Writer接口(Flush方法)
程序员小饭
2020/09/07
4070
相关推荐
Go语言的文件处理:详细指南
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文