使用errors.Wrapf()代替log.Error()
介绍不同语言的错误处理机制: Error handling patterns[1]
Musings about error handling mechanisms in programming languages[2]
项目中 main调func1,func1调取func2...
这样就会出现很多的 if err != nil { log.Printf()} , 在Kibana上查看时会搜到多条日志, 需要逐级定位, 确定错误抛出的点
希望只有一条, 能清晰看到整个堆栈调用信息
使用log.xxxx方法:
package main
import (
"fmt"
"log"
"strconv"
"time"
)
func init() {
log.SetFlags(log.Lshortfile | log.LstdFlags)
}
func main() {
str := "123a"
rs, err := func1(str)
if err != nil {
log.Printf("err is (%+v)\n", err)
return
}
fmt.Println("最终结果为:", rs)
}
func func1(str string) (int, error) {
b, err := func2()
if err != nil {
log.Printf("There is func11111, func2 err(%+v)\n", err)
}
if b == false {
strInt, err := strconv.Atoi(str)
if err != nil {
log.Printf("There is func11111, err(%+v)\n", err)
}
return strInt, err
}
return 0, nil
}
func func2() (bool, error) {
now := time.Now().Unix()
endTimeStr := "2021-08-06 20:00:0000"
endtime, err := time.ParseInLocation("2006-01-02 15:04:05", endTimeStr, time.Local)
if err != nil {
log.Printf("There is func22222, err(%+v)\n", err)
return false, err
}
if endtime.Unix() > now {
return true, nil
}
return false, nil
}
执行结果:
2021/06/07 21:52:56 vs.go:56: There is func22222, err(parsing time "2021-08-06 20:00:0000": extra text: "00")
2021/06/07 21:52:56 vs.go:33: There is func11111, func2 err(parsing time "2021-08-06 20:00:0000": extra text: "00")
2021/06/07 21:52:56 vs.go:40: There is func11111, err(strconv.Atoi: parsing "123a": invalid syntax)
2021/06/07 21:52:56 vs.go:20: err is (strconv.Atoi: parsing "123a": invalid syntax)
使用errors.Wrapf方法:
package main
import (
"fmt"
"github.com/pkg/errors"
"strconv"
"time"
)
func main() {
str := "123a"
rs, err := func1(str)
if err != nil {
fmt.Printf("err: %+v\n", err)
//fmt.Println("err:", lastErr) //必须%+v才会打印完整堆栈信息,否则只打印错误信息
return
}
fmt.Println("最终结果为:", rs)
}
func func1(str string) (int, error) {
b, err := func2()
if err != nil {
err = errors.Wrapf(err, "There is func11111, func2 err, b is(%b) \n", b)
}
if b == false {
var strInt int
strInt, err = strconv.Atoi(str)
if err != nil {
err = errors.Wrapf(err, "There is func11111,str is(%s)\n", str)
}
return strInt, err
}
return 0, nil
}
func func2() (bool, error) {
now := time.Now().Unix()
endTimeStr := "2021-08-06 20:00:0000"
endtime, err := time.ParseInLocation("2006-01-02 15:04:05", endTimeStr, time.Local)
if err != nil {
err = errors.Wrapf(err, "There is func22222,endTimeStr is(%s)\n", endTimeStr)
return false, err
}
if endtime.Unix() > now {
return true, nil
}
return false, nil
}
执行:
err: strconv.Atoi: parsing "123a": invalid syntax
There is func11111,str is(123a)
main.func1
/Users/fliter/go/src/shuang/llog/1.go:39
main.main
/Users/fliter/go/src/shuang/llog/1.go:13
runtime.main
/usr/local/Cellar/go/1.16.3/libexec/src/runtime/proc.go:225
runtime.goexit
/usr/local/Cellar/go/1.16.3/libexec/src/runtime/asm_amd64.s:1371
注意赋值这步, 必不可少!
有一个问题, 即对于f1调f2,f2调f3这种, 如果f3发生error, 可以逐级将error抛出.
但如果一个方法里有两个error, 则第二条会覆盖掉第一条,如上 err = errors.Wrapf(err, "There is func11111, func2 err, b is(%b) \n", b)这一条就被覆盖了
// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is called, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
return &withStack{
err,
callers(),
}
}
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
var st stack = pcs[0:n]
return &st
}
// Callers fills the slice pc with the return program counters of function invocations
// on the calling goroutine's stack. The argument skip is the number of stack frames
// to skip before recording in pc, with 0 identifying the frame for Callers itself and
// 1 identifying the caller of Callers.
// It returns the number of entries written to pc.
//
// To translate these PCs into symbolic information such as function
// names and line numbers, use CallersFrames. CallersFrames accounts
// for inlined functions and adjusts the return program counters into
// call program counters. Iterating over the returned slice of PCs
// directly is discouraged, as is using FuncForPC on any of the
// returned PCs, since these cannot account for inlining or return
// program counter adjustment.
func Callers(skip int, pc []uintptr) int {
// runtime.callers uses pc.array==nil as a signal
// to print a stack trace. Pick off 0-length pc here
// so that we don't let a nil pc slice get to it.
if len(pc) == 0 {
return 0
}
return callers(skip, pc)
}
func callers(skip int, pcbuf []uintptr) int {
sp := getcallersp()
pc := getcallerpc()
gp := getg()
var n int
systemstack(func() {
n = gentraceback(pc, sp, 0, gp, skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
})
return n
}
参考:
golang 打印error的堆栈信息[3]
Go错误处理最佳实践[4]
参考资料
Error handling patterns: https://andreabergia.com/blog/2023/05/error-handling-patterns/
[2]Musings about error handling mechanisms in programming languages: https://www.amazingcto.com/best-way-to-handle-errors-for-a-programming-language/
[3]golang 打印error的堆栈信息: https://blog.csdn.net/fwhezfwhez/article/details/82854986
[4]Go错误处理最佳实践: https://lailin.xyz/post/go-training-03.html
本文由 mdnice 多平台发布
相关文章:
使用errors.Wrapf()代替log.Error()
介绍不同语言的错误处理机制: Error handling patterns[1] Musings about error handling mechanisms in programming languages[2] 项目中 main调func1,func1调取func2... 这样就会出现很多的 if err ! nil { log.Printf()} , 在Kibana上查看时会搜到多条日志, 需要…...
企业面临的IP风险,如何应对?
IP风险画像为企业或组织在知识产权领域面临的潜在风险和威胁的综合概览。通过对相关知识产权的保护和管理,企业可以预测和应对潜在的法律、商业和声誉风险。 IP数据云帮助企业更好地了解和应对知识产权方面的风险。并提供了关于当前全球知识产权环境的重要信息&…...
L1-046 整除光棍(Python实现) 测试点全过
题目 这里所谓的“光棍”,并不是指单身汪啦~ 说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。 现在,你的程序要读入一个整数x,这个整…...
《Web安全基础》04. 文件上传漏洞
web 1:文件上传漏洞2:WAF 绕过2.1:数据溢出2.2:符号变异2.3:数据截断2.4:重复数据 本系列侧重方法论,各工具只是实现目标的载体。 命令与工具只做简单介绍,其使用另见《安全工具录》…...
文本匹配实战系列
引言 本系列文章开始介绍深度学习在文本匹配领域的应用,并且会尝试得到各种模型在给定的数据集上的表现。 深度文本匹配发展比较久,积累了很多文本匹配方法。也有很多的分类方式,一种分类方式是表示型和交互型。 表示型方法 表示型(repre…...
【Kafka】Kafka Stream简单使用
一、实时流式计算 1. 概念 一般流式计算会与批量计算相比较。在流式计算模型中,输入是持续的,可以认为在时间上是无界的,也就意味着,永远拿不到全量数据去做计算。同时,计算结果是持续输出的,也即计算结果…...
在Linux服务器上,查看系统最近的重启记录
在Linux服务器上,您可以查看系统的重启记录以了解系统何时进行了重启。系统的重启记录通常被记录在系统日志文件中。以下是在不同Linux发行版上查看系统重启记录的方法: 1. 使用 last 命令: 打开终端,并输入以下命令来查看系统的…...
Vue2023 面试归纳及复习
1. Vue 3中的Composition API(Hooks)是什么?它与Options API有何不同? 答:Composition API是Vue 3中引入的一种新的API风格, 用于组织和重用组件逻辑。它与Options API相比, 提供了更灵活和可…...
Android动态可编辑长度列表
概述 在界面实现一个列表,用户可以随意给列表新增或者删除项目,在开发中比较常用,但是真正做起来又有点花时间,今天花时间做一个,以便在以后的开发中用到。 详细 运行效果: 二、实现思路: 1…...
合并对象在 Typescript 中的实现与应用
合并对象在 Typescript 中的实现与应用 文章目录 合并对象在 Typescript 中的实现与应用一、简介二、实现1、函数实现2、参数说明3、返回值 三、使用示例四、实际应用场景五、拓展:使用 lodash-es 的 assign 函数进行对象合并1、简介2、安装与导入3、基础用法4、注意…...
antd upload组件beforeUpload返回promise之后,获取的文件不是file类型导致上传失败
之前的beforeUpload直接返回一个false值 ,文件是可以正常与服务端进行传输的 beforeUpload: (file) > {return false},但是这样并不能阻止文件上传,看了官方文档后,改用返回promise对象上传 beforeUpload: (file) > {console.log(-befo…...
创建ffmpeg vs2019工程
0 写在前面 本文主要参考链接:https://www.cnblogs.com/suiyek/p/15669562.html 感谢作者的付出; 1 目录结构 2 下载yasm和nasm 如果自己在安装VS2019等IDE的时候已经安装了它们,则不用再单独进行安装,比如我这边已经安装了&a…...
无涯教程-机器学习 - Jupyter Notebook函数
Jupyter笔记本基本上为开发基于Python的数据科学应用程序提供了一个交互式计算环境。它们以前称为ipython笔记本。以下是Jupyter笔记本的一些功能,使其成为Python ML生态系统的最佳组件之一- Jupyter笔记本可以逐步排列代码,图像,文本,输出等内容,从而逐步说明分析过程。 它有…...
ubuntu安装单机的Consul
文章目录 场景解决启动方式 场景 公司使用Consul做注册发现中心以及管理配置,之前没有用过consul, 现在记录下ubuntu部署的过程 解决 apt 安装 wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-…...
聊聊mybatis-plus的sql加载顺序
序 本文主要研究一下如果mybatis mapper定义了多个同名方法会不会有问题 MybatisConfiguration com/baomidou/mybatisplus/core/MybatisConfiguration.java /*** MybatisPlus 加载 SQL 顺序:* <p> 1、加载 XML中的 SQL </p>* <p> 2、加载 SqlP…...
基于jeecg-boot的flowable流程审批时增加下一个审批人设置
更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码: https://gitee.com/nbacheng/nbcio-boot 前端代码:https://gitee.com/nbacheng/nbcio-vue.git 在线演示(包括H5) : http://122.227.135.243:9888 因为有时…...
HTML 与 CSS 有什么区别?
HTML(超文本标记语言)和 CSS(层叠样式表)是构建网页的两个核心技术。HTML负责定义网页的结构和内容,而CSS则用于控制网页的样式和布局。虽然它们在构建网页时密切相关,但它们在功能和用途上有明显的区别。 …...
服务器数据恢复-vmware ESXI虚拟机数据恢复案例
服务器数据恢复环境: 从物理机迁移一台虚拟机到ESXI,迁移后做了一个快照。该虚拟机上部署了一个SQLServer数据库,存放了5年左右的数据。ESXI上有数十台虚拟机,EXSI连接了一台EVA存储,所有的虚拟机都在EVA存储上。 服务…...
Rabbitmq的Shovel
Federation 具备的数据转发功能类似, Shovel 够可靠、持续地从一个 Broker 中的队列 ( 作为源端,即source)拉取数据并转发至另一个 Broker 中的交换器 ( 作为目的端,即 destination) 。作为源端的队列和作为目的端的交换器可以同时位于…...
华为手机实用功能介绍
一、内置app介绍 分四块介绍,包括出门款、规划款、工作款和生活款。 出门款:红色框框部分,照镜子化妆/看天气 规划款:黄色框框部分,日程表/计划表/番茄时间/计时 工作款:蓝色框框部分,便笺/录…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
