How to Dump Goroutine Stack Traces in Go

Jay Singh Feb 02, 2024
How to Dump Goroutine Stack Traces in Go

The idiomatic approach to dealing with strange circumstances is to use errors in a Go program. Errors cause the majority of the unusual cases that arise in the software.

However, in rare cases, the software will not be able to continue running due to an aberrant state. In this situation, panic can end the program early.

When a function encounters a panic, the function’s execution will halt, any delayed functions will run, and control will return to the function’s caller.

This procedure continues until all of the current goroutine’s functions have returned, at which time the program prints the panic message, then the stack trace, before terminating.

When we construct an example program, this will become clearer.

Use panic to Dump Goroutine Stack Traces in Go

This simple script will print a person’s full name. The fullName function returns a person’s complete name.

This method checks for nil values in the firstName and lastName pointers. If it’s nil, the function sends a panic signal with a message.

When the program finishes, it will print this message.

package main

import (
	"fmt"
)

func fullName(firstName *string, lastName *string) {
	if firstName == nil {
		panic("runtime error: first name cannot be nil")
	}
	if lastName == nil {
		panic("runtime error: last name cannot be nil")
	}
	fmt.Printf("%s %s\n", *firstName, *lastName)
	fmt.Println("returned normally from fullName")
}

func main() {
	firstName := "Jay"
	fullName(&firstName, nil)
	fmt.Println("returned normally from main")
}

Output:

panic: runtime error: last name cannot be nil

goroutine 1 [running]:
main.fullName(0x405058?, 0xc000070f70?)
    /tmp/sandbox885911142/prog.go:12 +0x114
main.main()
    /tmp/sandbox885911142/prog.go:20 +0x35

Now, the below example makes the common mistake of attempting to access the slice’s final element using its length provided by the built-in len.

To demonstrate why this might induce panic, run the following code.

package main

import (
	"fmt"
)

func main() {
	names := []string{
		"Iron Man",
		"Thor",
	}
	fmt.Println("My favorite superhero is:", names[len(names)])
}

Output:

panic: runtime error: index out of range [2] with length 2

goroutine 1 [running]:
main.main()
    /tmp/sandbox2746930010/prog.go:12 +0x1b