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
Some things to note here. In our
go-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
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
Adding the Docker Compose file #
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
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
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
Above you can see our custom server runtime code listed as
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
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
Continue execution by calling
next until you hit line 21 and then inspect the local variables by using
Let’s continue execution using
next and observe the value of
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
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.