译 | Stack Traces In Go(上)

简介: 译 | Stack Traces In Go

简介

在调试Go程序方面有一些基本技能可以为程序员节省大量时间来识别问题。我信奉log尽可能多的信息,但有时panic发生,而log的信息并不够。有时理解stack trace中的信息可能意味着立刻发现错误,抑或需要添加更多日志记录并等待它再次发生。

自从我开始写Go以来,我一直在看stack trace。在某些时候,我们都做了一些愚蠢的事情,导致运行时杀死我们的程序并抛出stack trace。我将向您展示stack trace提供的信息,包括如何识别传递到函数的每个参数的值。

Functions

让我们从一小段代码开始,它将产生一个stack trace:

01 package main
02
03 func main() {
04     slice := make([]string, 2, 4)
05     Example(slice, "hello", 10)
06 }
07
08 func Example(slice []string, str string, i int) {
09     panic("Want stack trace")
10 }

上述代码展示了一个程序,第05行其main函数调用Example函数。Example函数被声明在第08行,接受三个参数,string slices,字符串和一个整数。Example执行的唯一代码是在第09行调用内置panic函数,它立即生成stack trace:

Panic: Want stack trace
goroutine 1 [running]:
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
        /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
        temp/main.go:9 +0x64
main.main()
        /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
        temp/main.go:5 +0x85

上述stack trace显示了panic时的所有goroutine,每个协程的状态以及相应goroutine下的调用堆栈。导致stack trace的运行中goroutine位于顶部。首先我们把重点放在导致panic的goroutine。

01 goroutine 1 [running]:
02 main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
           /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
           temp/main.go:9 +0x64
03 main.main()
           /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
           temp/main.go:5 +0x85

代码第01行的stack trace 显示在panic之前goroutine 1正在运行中。第02行,我们看到panic的代码位于main包的Example函数中。缩进的行显示了此函数所在的代码文件和路径,以及正在执行的代码行。当时,第09行的代码正在运行,是一个导致panic的调用。

第03行显示调用Example的函数的名称,main包中的main函数。在函数名称下面,缩进的行显示了对Example进行调用的代码文件,路径和代码行。

stack trace显示直到panic发生时,该goroutine范围内的函数调用链。现在,我们把重点放在传递给Example函数的每个参数的值:

// Declaration
main.Example(slice []string, str string, i int)
// Call to Example by main.
slice := make([]string, 2, 4)
Example(slice, "hello", 10)
// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)

上述来自stack trace显示了当main调用时传递给Example函数的值和该函数的声明。将stack trace中的值与函数声明进行比较,似乎不匹配。Example函数的声明接受三个参数,但stack trace显示六个十六进制值。理解值如何与参数匹配的关键在于需要知道每个参数类型的实现。

让我们从第一个参数开始,这是一个string slice。slice在Go中是引用类型。意味着slice的值是header value,带有指向某些基础数据的指针。对于slice,header value是三个word大小的结构,其包含指向底层数组的指针,slice的长度和容量。与slice header相关的值由stack trace中的前三个值表示:

// Slice parameter value
slice := make([]string, 2, 4)
// Slice header values
Pointer:  0x2080c3f50
Length:   0x2
Capacity: 0x4
// Declaration
main.Example(`slice []string`, str string, i int)
// Stack trace
main.Example(`0x2080c3f50, 0x2, 0x4`, 0x425c0, 0x5, 0xa)

上述显示了堆栈跟踪中的前三个值如何与slice参数匹配。第一个值表示指向基础字符串数组的指针。用于初始化切片的长度和容量数与第二个和第三个值匹配。这三个值表示切片标头的每个值,即第一个参数。

目录
相关文章
|
缓存 Go
译 | Stack Traces In Go(下)
译 | Stack Traces In Go(下)
60 0
|
28天前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
77 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
1月前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
45 7
|
1月前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
1月前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
112 71
|
1月前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
115 67
|
9天前
|
算法 安全 Go
Go语言中的加密和解密是如何实现的?
Go语言通过标准库中的`crypto`包提供丰富的加密和解密功能,包括对称加密(如AES)、非对称加密(如RSA、ECDSA)及散列函数(如SHA256)。`encoding/base64`包则用于Base64编码与解码。开发者可根据需求选择合适的算法和密钥,使用这些包进行加密操作。示例代码展示了如何使用`crypto/aes`包实现对称加密。加密和解密操作涉及敏感数据处理,需格外注意安全性。
32 14
|
1月前
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
115 62
|
9天前
|
Go 数据库
Go语言中的包(package)是如何组织的?
在Go语言中,包是代码组织和管理的基本单元,用于集合相关函数、类型和变量,便于复用和维护。包通过目录结构、文件命名、初始化函数(`init`)及导出规则来管理命名空间和依赖关系。合理的包组织能提高代码的可读性、可维护性和可复用性,减少耦合度。例如,`stringutils`包提供字符串处理函数,主程序导入使用这些函数,使代码结构清晰易懂。
49 11
|
9天前
|
存储 安全 Go
Go语言中的map数据结构是如何实现的?
Go 语言中的 `map` 是基于哈希表实现的键值对数据结构,支持快速查找、插入和删除操作。其原理涉及哈希函数、桶(Bucket)、动态扩容和哈希冲突处理等关键机制,平均时间复杂度为 O(1)。为了确保线程安全,Go 提供了 `sync.Map` 类型,通过分段锁实现并发访问的安全性。示例代码展示了如何使用自定义结构体和切片模拟 `map` 功能,以及如何使用 `sync.Map` 进行线程安全的操作。