/remote-debug-example

Example to illustrate my blogpost on remote debugging go code

Primary LanguageGoMIT LicenseMIT

remote-debug-example

Example to illustrate my Remote Debug with Go blogpost.

The project contains a simple go http server in main.go.

The server responds with Hello, world at <current-time>! to any http request.

Build and run

It contains to Dockerfiles:

  • Dockerfile builds the app and creates an image which can be used to run it.
  • Dockerfile.debug is the same, but also contains delve -- a debugger for Go. Additionally, it opens :40000 to connect the remote debugger.

We have a docker compose spec to show how to start the containers:

$ docker-compose up
...
example_1               | 2020/05/17 17:57:36 Starting server on :8080
example-remote-debug_1  | API server listening at: [::]:40000

The regular app starts right away on :8080:

$ curl localhost:8080
Hello, world at 2020-05-17 18:02:49!

The remote debug version doesn't start right away:

$ curl localhost:8081
curl: (52) Empty reply from server

Connect with the remote debugger

You need to connect to the app with the debugger before it starts. This is to give you possibility to debug the initialization of the app.

connection example

One you've connected you can interact with the app as usual:

$ curl localhost:8081
Hello, world at 2020-05-17 18:11:20!

You can also add breakpoints, and run the app step-by-step.

Remote debug

The screenshots are from Intellij Ultimate with go plugin, but the remote debugger can work with vscode and possibly other editors as well.

See also vscode launch.json configuration contributed by @cboudereau.

How does the remote debug work exactly?

  • In contrast with the JVM world, the remote debug is not built-in. We need to use delve -- a debugger for go.

  • Instead of the binary, we start devle and tell it to run the binary.

  • It can run in a headless mode where it waits for remote connections:

dlv --listen=:40000 --headless=true --api-version=2 --accept-multiclient exec app
  • If we list processes in the remote debug container we see both delve and the app:
root@257cd949c4c1:/# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.1  1.5 1383152 30964 ?       Ssl  18:21   0:00 /dlv --listen=:40000 --headless=true --api-version=2 --accept-multiclient exec /app
root        10  0.0  0.2 1005372 5768 ?        tl   18:21   0:00 /app
  • Delve needs to fork-and-exec to run the binary, therefore we explicitly need to allow the SYS_PTRACE capability.