LLDB

Rust has good support for two debuggers—GDB and LLDB. We will try the second here. LLDB is a modern command-line debugger. It's a part of the LLVM project. 

Let's try to look inside our working router microservice. Move to the directory with the microservice and compile it with the cargo build command. However, you have to be sure you don't set the --release flag, because it removes all debugging information. If you don't use cargo and want to add debugging information directly using rustc, add the -g -C debuginfo=2 arguments to keep debugging symbols in the output file. After the building is finished, use a command to start a debugger with scripts to support the Rust programming language:

rust-lldb ./target/debug/router-microservice

This command is already installed if you used the rustup installation tool to install Rust. You will have also installed LLDB debugger on your machine. When the debugger starts, it will print something like this:

(lldb) command script import "/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/etc/lldb_rust_formatters.py"
(lldb) type summary add --no-value --python-function lldb_rust_formatters.print_val -x ".*" --category Rust
(lldb) type category enable Rust
(lldb) target create "./target/debug/router-microservice"
Current executable set to './target/debug/router-microservice' (x86_64).
(lldb)

It will prompt for your input.

Let's set a breakpoint to the comments handler. You can do that with the following command:

breakpoint set --name comments

It will print that your breakpoint was set:

Breakpoint 1: where = router-microservice`router_microservice::comments::h50a827d1180e4955 + 7 at main.rs:152, address = 0x00000000001d3c77

Now, we can start the microservice with this command:

run

It will inform you that the process has launched:

Process 10143 launched: '/home/user/sources/Chapter15/deploy/microservices/router/target/debug/router-microservice'

Now, if you try to open the http://localhost:8080/comments URL in a browser, then the debugger will interrupt the execution of the handler in the breakpoint you set, and the debugger will show you the position of the line of code where it has interrupted:

   151     fn comments(req: HttpRequest<State>) -> FutureResponse<HttpResponse> {
-> 152 debug!("/api/comments called");
153 let url = format!("{}/list", req.state().content());
154 let fut = get_req(&url)
155 .map(|data| {

At this point, you can explore the running microservices. For example, you can get to know which alive threads exists with the following command:

thread list

It will show you the main thread and arbiter threads of actix:

  thread #3: tid = 10147, 0x00007ffff7e939d7 libc.so.6`.annobin_epoll_wait.c + 87, name = 'actix-web accep'
thread #4: tid = 10148, 0x00007ffff7f88b4d libpthread.so.0`__lll_lock_wait + 29, name = 'arbiter:77596ed'
thread #5: tid = 10149, 0x00007ffff7f8573c libpthread.so.0`__pthread_cond_wait + 508, name = 'arbiter:77596ed'

To see the variables that are available for the current context, you can use the frame variable command. To move execution to the next line of code, use the next command. To continue execution, use the continue command.

Using this tool, you can go through buggy handlers step by step and find the reason for the problem. Many developers prefer GUI debuggers and we'll also try one.