使用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介绍 分四块介绍,包括出门款、规划款、工作款和生活款。 出门款:红色框框部分,照镜子化妆/看天气 规划款:黄色框框部分,日程表/计划表/番茄时间/计时 工作款:蓝色框框部分,便笺/录…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...