In the previous issue of learning by observing, I’ve described how one can debug the Go compiler. This time, I’d like to share with you how one can debug gopls
using GoLand.
gopls
is a language server protocol implementation for Go. Its source code is available on GitHub. While, typically, debugging a program in GoLand is as easy as a couple of clicks, the problem with gopls
is that a) it’s launched by an editor b) at an arbitrary moment in time. This makes it harder to attach a debugger to it. Fortunately, there’s a better way called a daemon. It allows splitting gopls
into a client and a server. The former works as a proxy while the latter does all the work. What is more important in our case, it’s trivial to launch the server right in the IDE.
Let’s start with checking out Go tools
and opening gopls/main.go
. Before launching it, we need to add an argument -listen=:37374
(you can use any other port or even a Unix socket) that tells gopls
to act as a server. In GoLand, one does it by modifying a run configuration.
It’s enough to update Program arguments. The rest is automatically generated by the IDE.
After saving the run configuration with OK, we can launch gopls
by choosing Debug ‘go build golang.org/…’ instead of Modify Run Configuration… Now, we need to teach an editor to start a client version of gopls
. The process might look different for different editors. I use Visual Studio Code as the most popular one.
Actually, there’s not much to tell here. The Go plugin for VS Code has a setting go.languageServerFlags
that allows passing arguments to gopls
. It’s enough to add -remote=:37374
to the list of flags (don’t forget to update the port if you’ve decided to change it for -listen
). In my case, .vscode/settings.json
looks pretty much basic.
{
"go.languageServerFlags": [
"-remote=:37374"
]
}
Now, let’s add a breakpoint in GoLand. internal/lsp/server_gen.go
is an LSP server entry point. For many commands, it’s easy enough to start here. The next logical step would be to call a command and see what happens.
The official LSP documentation uses Go to Definition as an example. Let’s find out how it’s implemented for Go.
That’s it; we’re good to dive in. GoLand hits the breakpoint, so one can examine the program’s state and control its execution in an interactive manner. All variables have actual values, and we can even change them. The most curious can go further and evaluate expressions right inside the running application instance.
P.S. Special thanks go to Hana Kim, who gave me a hint about the gopls
daemon on Gophers Slack. Thank you!
Sometimes it's easier to start learning an unfamiliar project by interactively playing with its functionality rather than just reading its source code. In today's blog post, I'm describing how one can debug gopls (the Go's LSP server) with GoLand. https://t.co/ZfSCoN7nO7
— Artem Khvastunov (@art_spb) September 13, 2021