Debugging Go with Delve and VSCode
Debugging is important to figure out what's wrong with your program. However, debugging a program is sometimes not easy and can be overwhelming. This is especially true(maybe it's just me) when your program is running inside a docker container.
This blog post is going to show you how we can setup remote debugging using VSCode. This example will be setup using GoLang and the recommended debugger for Go programming language is Delve.
Part 1: Docker + GoLang
First, let's create a simple web application in Go and setup the Docker container to run the web application.
Step 1: Setup
- Create a directory for the project.
$ mkdir go-delve-docker-vscode
$ cd go-delve-docker-vscode
- Then, create a file called
main.go
in your project directory with a simple code below. This is a simple program that rendersHello, world!
when you access the url withhttp://localhost:8080/world
.
package main
import (
"log"
"net"
"net/http"
"strings"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
message := r.URL.Path
message = strings.TrimPrefix(message, "/")
message = "Hello, " + message + "!"
w.Write([]byte(message))
})
log.Print("starting web server")
listener, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
log.Printf("Start listening: %v", listener.Addr().String())
if err := http.Serve(listener, nil); err != nil {
log.Fatal(err)
}
}
Step 2: Create a Dockerfile
Now, we'll need to setup the Docker. In your project directory, create a file named Dockerfile
and paste the following:
FROM golang:1.12
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN go get github.com/go-delve/delve/cmd/dlv
# set the working directory to /go/src
WORKDIR $GOPATH/src
# Copy everything from the current directory to the working directory inside the container
# (as set by WORKDIR)
COPY . .
# 8080 is for the web application
EXPOSE 8080
Step 3: Define services in a docker-compose
In your project directory, create a file named docker-compose.yml
and paste the following:
(Note: For simplicity, this example only contains one service)
version: "3.0"
services:
web:
container_name: go-delve-docker-vscode-example
build: "./"
ports:
- "8080:8080"
security_opt:
- "seccomp:unconfined"
tty: true
stdin_open: true
command: go run main.go
Step 4: Build and run the web app with docker compose
Run docker-compose up
from the project directory. Compose will build an image and starts the service defined in docker-compose.yml
. At the end of the log, you'll see that web server is starting and listening to localhost:8080
Then, proceed to enter http://localhose:8080/world
in a browser url and see the application running.
Part 2: Delve + VSCode debugger
Moving on to the debugging section 🐛🐛
Step 1: Add the debugger
Add Delve to our project and expose 2345 port for the debugger.
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
+# add delve debugger
+RUN go get github.com/go-delve/delve/cmd/dlv
+
# set the working directory to /go/src
WORKDIR $GOPATH/src
@@ -10,4 +13,5 @@ WORKDIR $GOPATH/src
COPY . .
# 8080 is for the web application
-EXPOSE 8080
+# 2345 is for the delve debugger
+EXPOSE 8080 2345
Step 2: Setup docker compose
Then, change the command in docker-compose.yml
to start the app in debug mode. security-opt=seccomp:unconfined
is needed to run the container insecurely as mentioned in this issue.
build: "./"
ports:
- "8080:8080"
+ - "2345:2345"
+ security_opt:
+ - "seccomp:unconfined"
tty: true
stdin_open: true
- command: go run main.go
+ command: dlv debug --headless --listen=:2345 --api-version=2 --log main.go
Step 3: Configure debugging with VSCode
In order to debug with VSCode, we'll need to configure it. Run Debug: Open launch.json
command by typing cmd + shift +p. Or you could manually add a new configuration file.
Things to note in this configuration is that we have to make sure that the remotePath
is aligned with the path in your docker configuration. In this example, the working directory in the Dockerfile is set to /go/src
, thus, the remotePath
in launch.json
is set to be the same.
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "go",
"request": "launch",
"mode": "remote",
"program": "${workspaceFolder}",
"remotePath": "/go/src",
"port": 2345,
"env": {},
"args": [],
"showLog": true,
"trace": "verbose"
}
]
}
For more configuration settings, you can refer to the list here
Step 4: Run the web app with docker compose
Let's start debugging~ 💪
- Add breakpoint(s) in the
main.go
file in VSCode. - Run
docker-compose up
- Start debugger in VSCode with cmd + shift +p and type
Debug: Start Debugging
Below are some screenshots of the logs for reference.
📝 Important note:
- Make sure the log server is listening to port 8080 and then, head over to the browser and refresh the page.
- Then, go back to VSCode and the program should be stopping at the breakpoint that you've set.
That's it! Hope that you all find this tutorial helpful and you can start debugging your Go code. 💨💨
Finally, the complete code for this blog post can be found in GitHub.
🚗💨 Thanks for stopping by this blog post. 👋
Clap to support the author, help others find it, and make your opinion count.