译 | 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(下)
53 0
|
13天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
34 2
|
12天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
21 2
|
12天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
25 2
|
2天前
|
Go 调度 开发者
Go语言中的并发编程:深入理解goroutines和channels####
本文旨在探讨Go语言中并发编程的核心概念——goroutines和channels。通过分析它们的工作原理、使用场景以及最佳实践,帮助开发者更好地理解和运用这两种强大的工具来构建高效、可扩展的应用程序。文章还将涵盖一些常见的陷阱和解决方案,以确保在实际应用中能够避免潜在的问题。 ####
|
2天前
|
测试技术 Go 索引
go语言使用 range 关键字遍历
go语言使用 range 关键字遍历
13 3
|
2天前
|
测试技术 Go 索引
go语言通过 for 循环遍历
go语言通过 for 循环遍历
10 3
|
4天前
|
安全 Go 数据处理
Go语言中的并发编程:掌握goroutine和channel的艺术####
本文深入探讨了Go语言在并发编程领域的核心概念——goroutine与channel。不同于传统的单线程执行模式,Go通过轻量级的goroutine实现了高效的并发处理,而channel作为goroutines之间通信的桥梁,确保了数据传递的安全性与高效性。文章首先简述了goroutine的基本特性及其创建方法,随后详细解析了channel的类型、操作以及它们如何协同工作以构建健壮的并发应用。此外,还介绍了select语句在多路复用中的应用,以及如何利用WaitGroup等待一组goroutine完成。最后,通过一个实际案例展示了如何在Go中设计并实现一个简单的并发程序,旨在帮助读者理解并掌
|
3天前
|
Go 索引
go语言按字符(Rune)遍历
go语言按字符(Rune)遍历
13 3
|
6天前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
27 4