当前位置: 首页 > news >正文

使用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 0nil
}

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 truenil
 }

 return falsenil

}

执行结果:

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 0nil
}

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 truenil
 }

 return falsenil

}

执行:

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), nilnil0)
 })
 return n
}
alt



参考:

golang 打印error的堆栈信息[3]

Go错误处理最佳实践[4]

参考资料

[1]

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 顺序&#xff1a;* <p> 1、加载 XML中的 SQL </p>* <p> 2、加载 SqlP…...

基于jeecg-boot的flowable流程审批时增加下一个审批人设置

更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/nbcio-boot 前端代码&#xff1a;https://gitee.com/nbacheng/nbcio-vue.git 在线演示&#xff08;包括H5&#xff09; &#xff1a; http://122.227.135.243:9888 因为有时…...

HTML 与 CSS 有什么区别?

HTML&#xff08;超文本标记语言&#xff09;和 CSS&#xff08;层叠样式表&#xff09;是构建网页的两个核心技术。HTML负责定义网页的结构和内容&#xff0c;而CSS则用于控制网页的样式和布局。虽然它们在构建网页时密切相关&#xff0c;但它们在功能和用途上有明显的区别。 …...

服务器数据恢复-vmware ESXI虚拟机数据恢复案例

服务器数据恢复环境&#xff1a; 从物理机迁移一台虚拟机到ESXI&#xff0c;迁移后做了一个快照。该虚拟机上部署了一个SQLServer数据库&#xff0c;存放了5年左右的数据。ESXI上有数十台虚拟机&#xff0c;EXSI连接了一台EVA存储&#xff0c;所有的虚拟机都在EVA存储上。 服务…...

Rabbitmq的Shovel

Federation 具备的数据转发功能类似&#xff0c; Shovel 够可靠、持续地从一个 Broker 中的队列 ( 作为源端&#xff0c;即source)拉取数据并转发至另一个 Broker 中的交换器 ( 作为目的端&#xff0c;即 destination) 。作为源端的队列和作为目的端的交换器可以同时位于…...

华为手机实用功能介绍

一、内置app介绍 分四块介绍&#xff0c;包括出门款、规划款、工作款和生活款。 出门款&#xff1a;红色框框部分&#xff0c;照镜子化妆/看天气 规划款&#xff1a;黄色框框部分&#xff0c;日程表/计划表/番茄时间/计时 工作款&#xff1a;蓝色框框部分&#xff0c;便笺/录…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...