Debugging Tools

There are several ways to debug Jami from a developer perspective, depending on what you want to debug.


The first way is to use runtime loggers. Starting jami with -d will enable logging by the daemon (or the Troubleshoot section in the General settings). Because Jami uses several libraries, we do not enable all logs by default. But you can pass some environment variables to show it:

  • SIPLOGLEVEL=5 for enabling logs from PJSIP.

  • DHTLOGLEVEL=5 for enabling logs from OpenDHT.

  • AVLOGLEVEL=50 for enabling logs from ffmpeg.


Generally your IDE has an embedded debugger. Else, you can use gdb for example to be able to add breakpoints, backtraces from crashes, print internal structures, etc. You need to compile the project in DEBUG mode to get debug symbols.

Some useful commands:

  • b file.cpp:line - Add a breakpoint (file.cpp:line can be replaced by a symbol)

  • t a a bt - (thread apply all backtrace) to get all backtraces

  • Ctrl + X / A - pass in graphical view

  • p - print an internal value.

Note: VSCode is fully supported by Jami and can be used to debug the project.


Debuggers are useful, but they do not show real-time memory consumption/network activity/CPU usage. For this, you can use the embedded profiler in your IDE (from Android Studio or Qt Creator/Visual Studio for example).

Address Sanitizer

This can be useful to detect leaks, crashes, potential deadlocks at runtime. To enable this, you can compile the daemon with CXXFLAGS+=”-fsanitize=address”. Other flags like tsan may be useful.


Valgrind is a tool to watch allocations, CPU usage and more and can be used via: valgrind –tool=callgrind ./jami -d. This will make the application very slow but can provide useful reports about memory allocation/performance usage (KCacheGrind can be used to read reports).


Daemon has many tests and coverage enabled. If the daemon is built in static (else private symbols will not be available), adding new tests can help to reproduce bugs, solve bugs and avoid any regression. (cf. daemon/tests/unitTests`)


Tests are only using one daemon to simulate both peers. So it can be difficult to test in various environments. Another possibility is to write a scenario and run an agent (documentation is available in the daemon’s repository).


Finally, tracepoints can be created and analyzed. daemon/tools/trace provide the documentation and some examples. The advantage of LTTng is that it is quicker than logs, can be triggered by system events and can be used with tracepoints already present in the kernel (so that it can be used with tracepoints from network interfaces).


Both clients and daemon have tests. Daemon’s tests are written in C++ and use the cppunit framework. They are located in the daemon/tests directory.