- Published on
Debugging with delve
- Authors
Learn how to use Delve to debug your Go applications and tests.
delve?
What isDelve is an open source debugger for the Go programming language.
When should I use delve to debug my Go programmes?
If you use one of the popular Code Editors (e.g. VSCode, Golang) they will handle this for you. If you use VIM, and Print statements aren't cutting it, then this tutorial is for you.
Pre-requisites
Setting up
- Create a new directory in a place of your choice
- Run the
go mod init
command (e.ggo mod init github.com/simondrake/biggest-num
) - Create our
pkg
directory -mkdir -p pkg/biggestNum
- Add a
biggestNum.go
file in thebiggestNum
directory with the following contents:
package biggestNum
func BiggestEvenNum(nums []int) int {
var biggest int
for _, n := range nums {
if n > biggest && isEven(n) {
biggest = n
}
}
return biggest
}
func isEven(num int) bool {
isEven := num%2 == 0
return isEven
}
- Create another directory, separate from the one you created at the beginning of this section
- Run
go mod init example.com
- Change your
go.mod
file to the following, which basically imports ourbiggestNum
package without having to push it up to GitHub (change directory names as required):
module example.com
go 1.16
require (
github.com/simondrake/biggestNum v1.0.0
)
replace github.com/simondrake/biggestNum => ../biggest-num
- Create a
main.go
file with the following contents (change import forbiggestNum
as required):
package main
import (
"fmt"
"github.com/simondrake/biggestNum/pkg/biggestNum"
)
func main() {
b := biggestNum.BiggestEvenNum([]int{1, 4, 23, 12, 41, 51})
fmt.Println(b)
}
- Run
go run main.go
and make sure you don't get any compilation errors.
Debugging your Application
We now have a Go application we can debug, so let's start the debugger with dlv debug
and you should see the following:
$ dlv debug
Type 'help' for list of commands.
(dlv)
Add a breakpoint at line 10 of our main.go
file by running breakpoint main.go:10
(or b main.go:10
for short).
(dlv) b main.go:10
Breakpoint 1 set at 0x10cb9cf for main.main() ./main.go:10
Run continue
(or c
) to run-to-breakpoint.
(dlv) c
> main.main() ./main.go:10 (hits goroutine(1):1 total:1)
5:
6: "github.com/simondrake/biggestNum/pkg/biggestNum"
7: )
8:
9: func main() {
=> 10: b := biggestNum.BiggestEvenNum([]int{1, 4, 23, 12, 41, 51})
11:
12: fmt.Println(b)
13: }
From here we could continue (c
), which would run the programme to completion because there are no more breakpoints, but instead let's step-into the BiggestEvenNum
method by running step
(or s
).
> github.com/simondrake/biggestNum/pkg/biggestNum.BiggestEvenNum() /path/to/biggest-num/pkg/biggestNum/biggestNum.go:3
1: package biggestNum
2:
=> 3: func BiggestEvenNum(nums []int) int {
4: var biggest int
5:
6: for _, n := range nums {
7: if n > biggest && isEven(n) {
8: biggest = n
Note how the first line gives us a handy reference to where we are (/path/to/biggest-num/pkg/biggestNum/biggestNum.go:3
).
Now let's add another breakpoint in our biggestNum
package, on line 7:
(dlv) b /path/to/biggest-num/pkg/biggestNum/biggestNum.go:7
Breakpoint 2 set at 0x10cb8ea for github.com/simondrake/biggestNum/pkg/biggestNum.BiggestEvenNum() /path/to/biggest-num/pkg/biggestNum/biggestNum.go:7
Run continue
to get to our next breakpoint.
(dlv) c
> github.com/simondrake/biggestNum/pkg/biggestNum.BiggestEvenNum() /path/to/biggest-num/pkg/biggestNum/biggestNum.go:7 (hits goroutine(1):1 total:1)
2:
3: func BiggestEvenNum(nums []int) int {
4: var biggest int
5:
6: for _, n := range nums {
=> 7: if n > biggest && isEven(n) {
8: biggest = n
9: }
10: }
11:
12: return biggest
You can evaluate expressions by running print
(or p
)
(dlv) p n
1
You can evaluate a function call by running call
(dlv) call isEven(n)
> github.com/simondrake/biggestNum/pkg/biggestNum.BiggestEvenNum() /path/to/biggest-num/pkg/biggestNum/biggestNum.go:7 (hits goroutine(1):2 total:2)
Values returned:
~r1: false
You can continue
to run the programme to the next iteration of the loop, or run next
(or n
) to go to the next line, but we're going to skip that by removing this breakpoint. First, get the name of the breakpoint with breakpoints
(or bp
) and then delete it
(dlv) clear 2
Breakpoint 2 cleared at 0x10cb8ea for github.com/simondrake/biggestNum/pkg/biggestNum.BiggestEvenNum() /path/to/biggest-num/pkg/biggestNum/biggestNum.go:7
Then we'll stepout
(or so
) of this package
(dlv) so
> main.main() ./main.go:10
Values returned:
~r1: 12
5:
6: "github.com/simondrake/biggestNum/pkg/biggestNum"
7: )
8:
9: func main() {
=> 10: b := biggestNum.BiggestEvenNum([]int{1, 4, 23, 12, 41, 51})
11:
12: fmt.Println(b)
13: }
From here you can restart
if you want to run the same debugger again, or continue
until completion of the application.
Debugging tests
So far, we've seen how to debug a Go application. But what if we wanted to debug our biggestNum
standalone? If you try running dlv debug
you'll get an error.
$ dlv debug pkg/biggestNum/biggestNum.go
could not launch process: not an executable file
But, delve does have a test
subcommand we can use to run our tests in debug mode. So, first, let's add the following test under biggestNum_test.go
:
package biggestNum
import (
"testing"
)
func TestBiggestEvenNum(t *testing.T) {
expected := 290
out := BiggestEvenNum([]int{23, 51, 4, 32, 45, 290})
if out != expected {
t.Fatalf("'%d' did not match expected '%d'", out, expected)
}
}
To run the tests in debug mode, use dlv test
$ dlv test pkg/biggestNum/*.go -test.v
Type 'help' for list of commands.
Then set a breakpoint as we did in the previous step
(dlv) b biggestNum.go:6
Breakpoint 1 set at 0x11607d3 for command-line-arguments.BiggestEvenNum() ./pkg/biggestNum/biggestNum.go:6``
Run continue
as we did before
(dlv) continue
> command-line-arguments.BiggestEvenNum() ./pkg/biggestNum/biggestNum.go:6 (hits goroutine(4):1 total:1)
1: package biggestNum
2:
3: func BiggestEvenNum(nums []int) int {
4: var biggest int
5:
=> 6: for _, n := range nums {
7: if n > biggest && isEven(n) {
8: biggest = n
9: }
10: }
11:
And then debug your package, as we did our application, in the previous section.
Closing thoughts
You've learnt the basics of debugging with delve, but you should refer to the help
command output to learn about what else delve can do.