golang 打印error的堆栈信息操作

众所周知,目前的golang error只关注Error()信息,而不关注它的堆栈路径,对错误的定位大多数通过

log.SetFlags(log.Llongfile| log.LstdFlags)
log.Println(e)

一旦代码分层,为了定位错误,可能出现每一个层次的同一个error,都得log好几次,比如:

func DB()error{
	return errors.New("time out")
}
func Dao()error{
    if er:= DB();er!=nil{
    	 log.Println(er)
    	 return error
    }
    return nil
}
func Service()error{
    if er:= Dao();er!=nil{
    	 log.Println(er)
    	 return error
    }
    return nil
}
func Control()error{
    if er:= Service();er!=nil{
    	 log.Println(er)
    	 return error
    }
    return nil
}

如何一次性抛出错误,把该错误的堆栈全部都拿住呢

以模拟一次请求-分发-服务-数据库操作为例:

package main
import (
	"errors"
	"fmt"
	"github.com/fwhezfwhez/errorx"
)
func main() {
	if e := Control(); e != nil {
		e.(errorx.Error).PrintStackTrace()
		// log.Println(e.(errorx.Error).StackTrace())
	} else {
		Reply()
	}
}
// assume an engine to connect mysql
func DB() error {
	return errors.New("connect to mysql time out")
}
// handle database operation
func Dao() error {
	if er := DB(); er != nil {
		return errorx.New(er)
	}
	return nil
}
// handle logic service
func Service() error {
	if er := Dao(); er != nil {
		return errorx.Wrap(er)
	}
	return nil
}
// handle request distribute from main
func Control() error {
	if er := Service(); er != nil {
		return errorx.ReGen(er, errors.New("inner service error,please call admin for help"))
	}
	return nil
}
// reply a the request
func Reply(){
	fmt.Println("handle success")
}

执行结果:

StackTrace | CausedBy

G:/go_workspace/GOPATH/src/errorX/example/main.go: 26 | connect to mysql time out

G:/go_workspace/GOPATH/src/errorX/example/main.go: 34 | connect to mysql time out

G:/go_workspace/GOPATH/src/errorX/example/main.go: 42 | inner service error,please call admin for help

补充:golang 异常退出堆栈捕获

利用golang自带包 runtime/debug 异常时打印

DebugInfo.go

package main
import (
    "fmt"
    "os"
    "runtime/debug"
    "time"
)
func TryE() {
    errs := recover()
    if errs == nil {
        return
    }
    exeName := os.Args[0] //获取程序名称
    now := time.Now()  //获取当前时间
    pid := os.Getpid() //获取进程ID
    time_str := now.Format("20060102150405")                          //设定时间格式
    fname := fmt.Sprintf("%s-%d-%s-dump.log", exeName, pid, time_str) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
    fmt.Println("dump to file ", fname)
    f, err := os.Create(fname)
    if err != nil {
        return
    }
    defer f.Close()
    f.WriteString(fmt.Sprintf("%v\r\n", errs)) //输出panic信息
    f.WriteString("========\r\n")
    f.WriteString(string(debug.Stack())) //输出堆栈信息
}

测试异常捕获 main.go

package main
import (
    "fmt"
    "time"
)
func main() {
    defer TryE()
    fmt.Println(time.Now())
    panic(-2)
    fmt.Println("panic restore now, continue.")
}

查看堆栈可以定位main 里第11行抛出异常-2.

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • 基于golang如何实现error工具包详解

    前言 对于一门编程语言的开发者,类库包管理是一项考核编程语言成熟度的重要指标之一,Golang 也不例外.笔者在日常使用Golang语言开发系统程序时发现,在 Golang 的世界里,存在着大量的技术实现讨论和各种自制的解决方案. 最近在开发Go项目,发现Go语言本身存在的error并没有像触发panic时显示详细的调试信息.对于复杂的系统而言,这会让我们开发者需要一定的时间才能定位到错误.所以我们基本Go本身的error封装了一个可以快速定位错误工具包.下面让我们来看看这个工具包是怎么实现的.

  • Golang中interface{}转为数组的操作

    interface{} 转为普通类型 我们都知道在golang中interface{}可以代表任何类型,对于像int64.bool.string等这些简单类型,interface{}类型转为这些简单类型时,直接使用 p, ok := t.(bool) p, ok := t.(int64) 如果ok==true的话,就已经类型转换成功. 假设有这样一个场景,我们有一个函数有返回值,但是返回值的类型不定,所以我们的返回值类型只能以接口来代替了. 返回接口类型之后,我们就要对其类型进行判断然后进行类型

  • golang DNS服务器的简单实现操作

    简单的DNS服务器 提供一个简单的可以查询域名和反向查询的DNS服务器. dig命令主要用来从 DNS 域名服务器查询主机地址信息. 查找www.baidu.com的ip (A记录): 命令:dig @127.0.0.1 www.baidu.com 根据ip查找对应域名 (PTR记录): 命令:dig @127.0.0.1 -x 220.181.38.150 源码 : package mainimport ( "fmt" "net" "golang.org

  • golang coroutine 的等待与死锁用法

    直接上代码: 1. 第一种情况 如果没有select{}, main 主线程不会等待coroutine运行,导致coroutine得不到机会运行. You are requesting eventual scheduling (using the two go statements) of two goroutines and then you exit main without giving the scheduler a chance to do anything. 有了select, 程序

  • Golang捕获panic堆栈信息的讲解

    golang当中panic的时候如果启动的goroutine比较多,刷的信息满屏都是,在终端工具上因为刷的信息太多,找不到前边的信息,因此很有必要程序自己捕获panic,并且将错误信息输出到文件当中,以便定位排查问题. Golang捕获panic堆栈信息 func PanicTrace(kb int) []byte { s := []byte("/src/runtime/panic.go") e := []byte("\ngoroutine ") line := [

  • golang slice元素去重操作

    合并两个整型切片,返回没有重复元素的切片,有两种去重策略 1. 通过双重循环来过滤重复元素(时间换空间) // 通过两重循环过滤重复元素 func RemoveRepByLoop(slc []int) []int { result := []int{} // 存放结果 for i := range slc{ flag := true for j := range result{ if slc[i] == result[j] { flag = false // 存在重复元素,标识为false br

  • golang中json和struct的使用说明

    1.返回json响应结果 在struct的字段后面加入json:"key"可以进行json格式输出,其中key为json的键名 type SuccessResponse struct { Code int `json:"code"` Msg string `json:"msg"` Data interface{} `json:"data"` } func SuccessRsp(ctx *gin.Context, data in

  • golang 打印error的堆栈信息操作

    众所周知,目前的golang error只关注Error()信息,而不关注它的堆栈路径,对错误的定位大多数通过 log.SetFlags(log.Llongfile| log.LstdFlags) log.Println(e) 一旦代码分层,为了定位错误,可能出现每一个层次的同一个error,都得log好几次,比如: func DB()error{ return errors.New("time out") } func Dao()error{ if er:= DB();er!=nil

  • Logger.error打印错误异常的详细堆栈信息

    一.问题场景 使用Logger.error方法时只能打印出异常类型,无法打印出详细的堆栈信息,使得定位问题变得困难和不方便. 二.先放出结论 Logger类下有多个不同的error方法,根据传入参数的个数及类型的不同,自动选择不同的重载方法. 当error(Object obj)只传入一个参数时会将异常对象作为Object使用,并最终当做String打印出来,当使用两个参数error(String message, Throwable t),且第二个参数为Throwable时,才会将完整的异常堆

  • 使用Python将Exception异常错误堆栈信息写入日志文件

    假设需要把发生异常错误的信息写入到log.txt日志文件中去: import traceback import logging logging.basicConfig(filename='log.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') try: raise Exception('发生异常错误信息') except: #方案一,自己定义一个文件,自己把错误堆栈信息写入文件. #er

  • jstack+jdb命令查看线程及死锁堆栈信息的实例

    如果程序挂死,有时使用jstack查看进程中线程信息时,需要添加上-F参数,此时如果有死锁信息,则可能不会打印出死锁堆栈信息,使用jdb则可以查看当前死锁线程的运行堆栈. 如下模拟一个简单的死锁程序 package com.demo.bootdemo; import java.util.HashMap; import java.util.Map; import org.springframework.context.ApplicationListener; import org.springfr

  • Java如何自定义异常打印非堆栈信息详解

    前言 在学习Java的过程中,想必大家都一定学习过异常这个篇章,异常的基本特性和使用这里就不再多讲了.什么是异常?我不知道大家都是怎么去理解的,我的理解很简单,那就是不正常的情况,比如我现在是个男的,但是我却有着女人所独有的东西,在我看来这尼玛肯定是种异常,简直不能忍.想必大家都能够理解看懂,并正确使用. 但是,光学会基本异常处理和使用不够的,在工作中出现异常并不可怕,有时候是需要使用异常来驱动业务的处理,例如: 在使用唯一约束的数据库的时候,如果插入一条重复的数据,那么可以通过捕获唯一约束异常

  • 浅析golang开发Error的使用详解

    Error是Go语言开发中最基础也是最重要的部分,跟其他语言的try catch的作用基本一致,想想在PHP JAVA开发中,try catch 不会使用,或者使用不灵活,就无法感知到程序运行中出现了什么错误,是特别可怕的一件事. Error 基础 Golang中 error类型就是一个最基本interface,定义了一个Error()的方法 type error interface { Error() string } 平常使用最多的是这样的 errors.New("error")

  • 一篇文章带你轻松搞懂Golang的error处理

    目录 Golang中的error error的几种玩法 哨兵错误 自定义错误类型 Wrap error Golang1.13版本error的新特性 errors.UnWrap() errors.Is() errors.As() error处理最佳实践 优先处理error 只处理error一次 不要反复包装error 不透明的错误处理 简化错误处理 bufio.scan errWriter 何时该用panic 小补充 总结 Golang中的error Golang中的 error 就是一个简单的接

  • java自带的工具Jstack截取进程中的堆栈信息

    在Java软件的使用过程中,有时会莫名的出现奇怪的问题.而这些问题常常无法使用日志信息定位,这时我们就需要通过查看进程内部线程的堆栈调用关系来分析问题出在哪里. 举个例子,当我们在做某个操作时,莫名的会弹出多个警告框,其中有些信息是正常的,有些则不是.对于这些错误的警告信息,我们该如何定位是哪个位置的代码出现了错误弹出的框呢? 我们就需要在弹框以后,去查看软件的各个线程,去查找究竟是哪个线程导致了该问题.可是有时因为环境.时间等问题,我们根本不能拿着IDE去调试, 只能通过工具软件拍下内存快照,

  • Python捕获异常堆栈信息的几种方法(小结)

    程序出错的时候,我们往往需要根据异常信息来找到具体出错的代码.简单地用print打印异常信息并不能很好地追溯出错的代码: # -*- coding: utf-8 -*- def foo(a, b): c = a + b raise ValueError('test') return c def bar(a): print('a + 100:', foo(a, 100)) def main(): try: bar(100) except Exception as e: print(repr(e))

随机推荐