Debugging with Delve #
This guide assumes you are already familiar with running Nakama inside a Docker container. For more information see the Installing Nakama with Docker Compose documentation.
The main.go file #
For this guide we’ll be using an example main.go
file that registers a single test RPC function that we can debug using Delve.
|
|
Creating the Dockerfile #
In order to build our server runtime code in a way that can be debugged with dlv
we need to make a Dockerfile that ensures both the runtime code and the Nakama binary are built without optimizations.
Create a new Dockerfile and call it Dockerfile
:
|
|
Some things to note here. In our builder
step we install some packages that will then allow us to build our Go runtime plugin using the --gcflags "all=-N -l"
flag which effectively disables optimizations in the resulting plugin file.
We also install dlv
using RUN go install github.com/go-delve/delve/cmd/dlv@latest
. We’ll copy this over to the final docker image in the next step.
In our final Docker step, we are using the nakama-dsym
image rather than the standard nakama
image. This is an image that provides us with a Nakama binary with optimizations disabled, suitable for running with dlv
just like our plugin.
We then copy over the dlv
binary as well as our server runtime plugin and local.yml
configuration file as normal.
The other modification here is that we override the default ENTRYPOINT
so that Nakama does not attempt to automatically start up. This gives us the opportunity to docker exec
into the container and run dlv
ourselves.
Adding the Docker Compose file #
The docker-compose.yml
file we will use for debugging is similar to the standard one provided in the Installing Nakama with Docker Compose documentation, however we have made a few adjustments. Here we make sure we’re building our Dockerfile
image and removing the entrypoint
property on the nakama
server to ensure that Nakama does not launch when running the container. We’re also setting a few values that are needed to successfully run dlv
inside the container. These are the security_opt
, stdin_open
and tty
properties.
|
|
Exec’ing into Docker #
With our Docker configuration files done, we will now launch our Nakama and Postgres containers:
|
|
With our containers running, open a new terminal window and exec
into the Nakama docker container (where server-nakama-1
is the name of your Nakama container).
|
|
This will drop you into a bash
shell inside the Nakama container.
Manually migrating the Nakama database #
From here, we will first make sure we migrate the Postgres database for use with Nakama.
|
|
Running Nakama with Delve #
With the database migrated we can now run Nakama via Delve. Note the extra --
between the path to the Nakama binary and the Nakama config flags. It is important you include this or dlv will not correctly pass those flags to the Nakama binary.
|
|
Here we’re using the dlv exec
command to execute our precompiled Nakama binary and begin the debug session. You’ll be presented with the dlv
command line interface:
|
|
Debugging custom server runtime code with Delve #
Delve is now waiting for user input to tell it how to proceed. At this point, if we typed continue
, Delve would continue execution of Nakama and we would see the standard Nakama server output log. However, because Nakama goes into a state of waiting for a termination signal after startup is complete, we would not be able to debug our runtime code if we did this as Delve would be unable to interject.
Instead, what we must do is set a breakpoint to some point before Nakama goes into this waiting phase, but after which our custom server runtime plugin has been loaded.
To do this, let’s set a breakpoint on line 181 of main.go
.
|
|
You should see an output similar to the following, confirming the breakpoint:
|
|
Now, let’s continue execution of Nakama until we hit that breakpoint.
|
|
At this point, our custom server runtime code should be loaded. We can confirm this by using the libraries
command and looking for our plugin .so
file.
|
|
Above you can see our custom server runtime code listed as /nakama/data/modules/backend.so
.
For this example, the custom server runtime has an RpcTest
function which simply logs a message out to the Nakama server console and returns a JSON response with a value indicating whether a payload was given or not.
Let’s verify that the function exists:
|
|
We can set a breakpoint on this function:
|
|
and then continue execution:
|
|
Going to the Nakama console now and triggering this Rpc from a user will allow us to debug this function.
As soon as we hit the breakpoint, Delve will give us back control and allow us to inspect various things:
|
|
The first thing we can do here is inspect the arguments that have been passed to the RPC by using the args
command.
|
|
We can see from above that as well as the typical RPC arguments (context, logger, database etc) we also see the value of the JSON payload passed to the RPC.
Next we can step into the executing function, see the call to the logger execute and then inspect the locals. We can do this using the next
and locals
commands.
|
|
Continue execution by calling next
until you hit line 21 and then inspect the local variables by using locals
.
|
|
Let’s continue execution using next
and observe the value of payloadExists
changing.
|
|
We can see here that the value of payloadExists
has changed due to the if
statement evaluating to true
and thus changing the value of that variable.
Let’s fully continue execution and let the RPC return by calling continue
.
|
|
You should now see the appropriate response from the RPC in your Nakama console API Explorer.
|
|
Further debugging #
The above demonstrates a very basic example of stepping through the execution of a custom server runtime RPC, inspecting the arguments and local variables and continuing execution.
Delve is a powerful debugger and if you would like to learn more about what commands are available please visit the official Delve CLI documentation.