Go在工程实践的错误处理Golang在工程实践中的错误处理 彭友顺 石墨文档 产研负责人 目 录 为什么我们处理错误会这么慢 01 如何完善错误信息 02 优雅处理错误信息 03 分布式错误处理 04 错误信息手册的必要性 05 为什么我们处理错误 会这么慢 第一部分 错误信息不够完善 why 原因 出现 错误 定位 慢 恢复 慢 效率低 为什么我们处理错误会这么慢 错误处理不够优雅 分布式错误难以串联 对接起来会非常麻烦 优雅处理错误信息 第三部分 为什么定位慢?-- 错误处理 不要透传错误 错误码唯一性 记录一次错误 假设用户反馈了无法打开一个文件 我们的程序员非常认真 记录了文件不存在的错误日志 • 同样的错误信息,非常多的杂音 • 每个Error,都去查看一次对应代码,排查效率低 • 占用存储空间 • 最外层入口处只记录一次错误日志 为什么定位慢?-- 错误处理 带来新的问题,无法定位整个代码执行链路 日志分析不出是哪个service 调用了MySQL 为什么定位慢?-- 错误处理 带来新的问题,无法定位整个代码执行链路 不要透传错误 错误码唯一性 记录一次错误 • 不能透传错误,fmt.Errorf • 如果不考虑性能 • 日志开启Stack • 错误追加Stack 为什么定位慢?-- 错误处理 不要透传错误 错误码唯一性 记录一次错误 文件不存在 数据表里不存在0 码力 | 30 页 | 3.11 MB | 1 年前3
Golang 101(Go语言101 中文版) v1.21.a型的时候,舍入(或者精 度丢失)也是允许的。 具体规则如下: 当从一个比特位数多的整数类型的非常量整数值向一个比特位数少的整数 类型转换的时候,高位的比特将被舍弃,低位的比特将被保留。我们称这 种处理方式为截断(truncated)。 当从一个非常量的浮点数向一个整数类型转换的时候,浮点数的小数部分 将被舍弃(向零靠拢)。 当从一个非常量整数或者浮点数向一个浮点数类型转换的时候,精度丢失 是可以发生的。 当一个程序的主协程退出后,此程序也就退出了,即使还有一些其它协程在运 行。 和前面的几篇文章不同,上面的例子程序使用了log标准库而不是fmt标准库 中的Println函数。 原因是log标准库中的打印函数是经过了同步处理的(下 一节将解释什么是并发同步),而fmt标准库中的打印函数却没有被同步。 如 果我们在上例中使用fmt标准库中的Println函数,则不同协程的打印可能会 交织在一起。(虽然对此例来说,交织的概率很低。) 必须被另外一个协程通过 某种并发同步方法来被动地结束阻塞状态。 如果一个运行中的程序当前所有 的协程都出于阻塞状态,则这些协程将永远阻塞下去,程序将被视为死锁了。 当一个程序死锁后,官方标准编译器的处理是让这个程序崩溃。 比如下面这个程序将在运行两秒钟后崩溃。 1| package main 2| 3| import ( 4| "sync" 5| "time" 6| ) 7|0 码力 | 821 页 | 956.82 KB | 1 年前3
Golang 101(Go语言101 中文版) v1.21.a时候,舍入(或者精度 丢失)也是允许的。 具体规则如下: 当从一个比特位数多的整数类型的非常量整数值向一个比特位数少的整数 类型转换的时候,高位的比特将被舍弃,低位的比特将被保留。我们称这 种处理方式为截断(truncated)。 当从一个非常量的浮点数向一个整数类型转换的时候,浮点数的小数部分 将被舍弃(向零靠拢)。 当从一个非常量整数或者浮点数向一个浮点数类型转换的时候,精度丢失 是可以发生的。 当一个程序的主协程退出后,此程序也就退出了,即使还有一些其它协程在运 行。 和前面的几篇文章不同,上面的例子程序使用了log标准库而不是fmt标准库中 的Println函数。 原因是log标准库中的打印函数是经过了同步处理的(下一节 将解释什么是并发同步),而fmt标准库中的打印函数却没有被同步。 如果我 们在上例中使用fmt标准库中的Println函数,则不同协程的打印可能会交织在 一起。(虽然对此例来说,交织的概率很低。) 须被另外一个协程通过 某种并发同步方法来被动地结束阻塞状态。 如果一个运行中的程序当前所有的 协程都出于阻塞状态,则这些协程将永远阻塞下去,程序将被视为死锁了。 当 一个程序死锁后,官方标准编译器的处理是让这个程序崩溃。 比如下面这个程序将在运行两秒钟后崩溃。 package main import ( "sync" "time" ) var wg sync.WaitGroup0 码力 | 608 页 | 1.08 MB | 1 年前3
Golang 101(Go语言101 中文版) v1.21.a常量值(比如一个变量)转换为一个整数类型的时候,舍入(或者精度丢失)也是 允许的。 具体规则如下: 当从一个比特位数多的整数类型的非常量整数值向一个比特位数少的整数类型 转换的时候,高位的比特将被舍弃,低位的比特将被保留。我们称这种处理方 式为截断(truncated)。 当从一个非常量的浮点数向一个整数类型转换的时候,浮点数的小数部分将被 舍弃(向零靠拢)。 当从一个非常量整数或者浮点数向一个浮点数类型转换的时候,精度丢失是可 当一个程序的主协程退出后,此程序也就退出了,即使还有一些其它协程在运行。 和前面的几篇文章不同,上面的例子程序使用了log标准库而不是fmt标准库中的 Println函数。 原因是log标准库中的打印函数是经过了同步处理的(下一节将解 释什么是并发同步),而fmt标准库中的打印函数却没有被同步。 如果我们在上例 第13章:协程、延迟函数调用、以及恐慌和恢复 97 中使用fmt标准库中的Println函数,则不同协程的打印可能会交织在一起。(虽 外一个协程通过某种 并发同步方法来被动地结束阻塞状态。 如果一个运行中的程序当前所有的协程都出 于阻塞状态,则这些协程将永远阻塞下去,程序将被视为死锁了。 当一个程序死锁 后,官方标准编译器的处理是让这个程序崩溃。 比如下面这个程序将在运行两秒钟后崩溃。 1| package main 2| 3| import ( 4| "sync" 5| "time" 6|0 码力 | 591 页 | 21.40 MB | 1 年前3
Go Web编程web工作方式 3.2 Go搭建一个简单的web服务 3.3 Go如何使得web工作 3.4 Go的http包详解 3.5 小结 4.表单 4.1 处理表单的输入 4.2 验证表单的输入 4.3 预防跨站脚本 4.4 防止多次递交表单 4.5 处理文件上传 4.6 小结 5.访问数据库 5.1 database/sql接口 5.2 使用MySQL数据库 5.3 使用SQLite数据库 5.4 session和cookie 6.2 Go如何使用session 6.3 session存储 6.4 预防session劫持 6.5 小结 7.文本文件处理 7.1 XML处理 7.2 JSON处理 7.3 正则处理 7.4 模板处理 7.5 文件操作 7.6 字符串处理 7.7 小结 8.Web服务 8.1 Socket编程 8.2 WebSocket 8.3 REST 8.4 RPC 8.5 小结 国际化和本地化 10.1 设置默认地区 10.2 本地化资源 10.3 国际化站点 4 10.4 小结 11.错误处理,调试和测试 11.1 错误处理 11.2 使用GDB调试 11.3 Go怎么写测试用例 11.4 小结 12.部署与维护 12.1 应用日志 12.2 网站错误处理 12.3 应用部署 12.4 备份和恢复 12.5 小结 13.如何设计一个Web框架 13.1 项目规划0 码力 | 295 页 | 5.91 MB | 1 年前3
Go可观测性实践Exporter • Collector OTel Collector • Receiver • Processor • Exporter 微服务业务架构图 项目工程layout 遥测数据处理架构 链路追踪 第二部分 无所不在的部署 持续监控 低消耗 应用级透明 延展性 链路追踪设计目标 链路追踪 Dapper 每个请求都生成一个全局唯一的 tr 执行时长:每个Span都必须记录工作开始到结束时花费的时长。 Go工程插桩(Instrument) 需要对业务开发者几乎零成本的接入链路追踪,几乎完全依赖于少量通用组件库的改造。 当一个请求在处理跟踪控制路径的过程中,需要把跟踪的上下文存储在ThreadLocal中,在Go中 就是存储在Context中,一般约定每个方法第一个参数为Context(上下文)。 覆盖组件不限于:数据库、缓存、消息队列、RPC、HTTP等。 p Header来存取这个对象,最后达到传播的效果, TraceContext就是一个Context上下文对象。 Inject Extract 数据流转 使用Collector的好处在于一些 计算操作可以再Collector中统 一处理,一些逻辑如压缩、过滤、 配置变更等可以集中到 Collector中实现,服务只需要 实现很薄的一层埋点、采样逻辑 即可,这也能使得链路追踪对业0 码力 | 35 页 | 2.88 MB | 1 年前3
Hello 算法 1.1.0 Go版“如果我当年学数据结构与算法的时候有《Hello 算法》,学起来应该会简单 10 倍!” ——李沐,亚马逊资深首席科学家 计算机的出现给世界带来了巨大变革,它凭借高速的计算能力和出色的可编程性,成为了执行算法与处理数 据的理想媒介。无论是电子游戏的逼真画面、自动驾驶的智能决策,还是 AlphaGo 的精彩棋局、ChatGPT 的自然交互,这些应用都是算法在计算机上的精妙演绎。 事实上,在计算机问世之前, 2 张扑克已经有序。 3. 不断循环步骤 2. ,每一轮将一张扑克牌从无序部分插入至有序部分,直至所有扑克牌都有序。 图 1‑2 扑克排序步骤 上述整理扑克牌的方法本质上是“插入排序”算法,它在处理小型数据集时非常高效。许多编程语言的排序 库函数中都有插入排序的身影。 例三:货币找零。假设我们在超市购买了 69 元的商品,给了收银员 100 元,则收银员需要找我们 31 元。他 会很自然地完成如图 2‑5 尾递归过程 Tip 请注意,许多编译器或解释器并不支持尾递归优化。例如,Python 默认不支持尾递归优化,因此即 使函数是尾递归形式,仍然可能会遇到栈溢出问题。 3. 递归树 当处理与“分治”相关的算法问题时,递归往往比迭代的思路更加直观、代码更加易读。以“斐波那契数列” 为例。 Question 给定一个斐波那契数列 0, 1, 1, 2, 3, 5, 8, 13, …0 码力 | 383 页 | 18.48 MB | 1 年前3
Hello 算法 1.0.0 Golang版2 张扑克已经有序。 3. 不断循环步骤 2. ,每一轮将一张扑克牌从无序部分插入至有序部分,直至所有扑克牌都有序。 图 1‑2 扑克排序步骤 上述整理扑克牌的方法本质上是“插入排序”算法,它在处理小型数据集时非常高效。许多编程语言的排序 库函数中都有插入排序的身影。 例三:货币找零。假设我们在超市购买了 69 元的商品,给了收银员 100 元,则收银员需要找我们 31 元。他 会很自然地完成如图 图 2‑5 尾递归过程 � 请注意,许多编译器或解释器并不支持尾递归优化。例如,Python 默认不支持尾递归优化, 因此即使函数是尾递归形式,仍然可能会遇到栈溢出问题。 3. 递归树 当处理与“分治”相关的算法问题时,递归往往比迭代的思路更加直观、代码更加易读。以“斐波那契数列” 为例。 � 给定一个斐波那契数列 0, 1, 1, 2, 3, 5, 8, 13, … ,求该数列的第 从本质上看,递归体现了“将问题分解为更小子问题”的思维范式,这种分治策略至关重要。 ‧ 从算法角度看,搜索、排序、回溯、分治、动态规划等许多重要算法策略直接或间接地应用了这种思维 方式。 ‧ 从数据结构角度看,递归天然适合处理链表、树和图的相关问题,因为它们非常适合用分治思想进行分 析。 2.2.3 两者对比 总结以上内容,如表 2‑1 所示,迭代和递归在实现、性能和适用性上有所不同。 表 2‑1 迭代与递归特点对比0 码力 | 382 页 | 17.60 MB | 1 年前3
Hello 算法 1.2.0 简体中文 Go 版“如果我当年学数据结构与算法的时候有《Hello 算法》,学起来应该会简单 10 倍!” ——李沐,亚马逊资深首席科学家 计算机的出现给世界带来了巨大变革,它凭借高速的计算能力和出色的可编程性,成为了执行算法与处理数 据的理想媒介。无论是电子游戏的逼真画面、自动驾驶的智能决策,还是 AlphaGo 的精彩棋局、ChatGPT 的自然交互,这些应用都是算法在计算机上的精妙演绎。 事实上,在计算机问世之前, 2 张扑克已经有序。 3. 不断循环步骤 2. ,每一轮将一张扑克牌从无序部分插入至有序部分,直至所有扑克牌都有序。 图 1‑2 扑克排序步骤 上述整理扑克牌的方法本质上是“插入排序”算法,它在处理小型数据集时非常高效。许多编程语言的排序 库函数中都有插入排序的身影。 例三:货币找零。假设我们在超市购买了 69 元的商品,给了收银员 100 元,则收银员需要找我们 31 元。他 会很自然地完成如图 2‑5 尾递归过程 Tip 请注意,许多编译器或解释器并不支持尾递归优化。例如,Python 默认不支持尾递归优化,因此即 使函数是尾递归形式,仍然可能会遇到栈溢出问题。 3. 递归树 当处理与“分治”相关的算法问题时,递归往往比迭代的思路更加直观、代码更加易读。以“斐波那契数列” 为例。 Question 给定一个斐波那契数列 0, 1, 1, 2, 3, 5, 8, 13, …0 码力 | 384 页 | 18.49 MB | 10 月前3
Go 入门指南(The way to Go)章)。我们会对 Go 语 言的函数式和面向对象编程进行透彻的讲解,包括如何使用 Go 语言来构造大型项目(第 9 章)。 在本书的第三部分,你将会学习到如何处理不同格式的文件(第 12 章)和如何在 Go 语言中巧妙地使用 错误处理机制(第 13 章)。然后我们会对 Go 语言中最值得称赞的设计 goroutine 和 channel 进行并发 和多核应用的基本技巧的讲解(第 14 章)。最后,我们会讨论如何将 很庆幸 Stroustrup 做了让 C++ 兼容 C 语言以能够让其编译 C 程序这个正确的决定。我们当时需要 C++ 的出 现。” “之后我们学到了更多。我们毫无疑问地接受了垃圾回收,异常处理和虚拟机这些当年人们认为只有疯子 才会想的东西。C++ 的复杂程度(新版的 C++ 甚至更加复杂)极大了影响了软件开发的高效性,这使得 它再也不再适合这个时代。人们不再像过往那样认同在 C++ 中兼容使用 来实现各个 goroutine 之间的通信。他们实现了分段栈增长和 goroutine 在线程基础上多路复用技术的自动化。 这个特性显然是 Go 语言最强有力的部分,不仅支持了日益重要的多核与多处理器计算机,也弥补了现存 编程语言在这方面所存在的不足。 Go 语言中另一个非常重要的特性就是它的构建速度(编译和链接到机器代码的速度),一般情况下构建 一个程序的时间只需要数百毫秒到几秒。作为大量使用0 码力 | 380 页 | 2.97 MB | 1 年前3
共 52 条
- 1
- 2
- 3
- 4
- 5
- 6













