Debug a snap application
Once a snap is built and installed one might face unexpected problems like missing a configuration file or a library or simply not the expected behaviour.
Even if snaps are immutable there are still means to introspect and analyse their state as well as running tests inside the snap environment.
Keep in mind that we want to debug the packaging. Debugging your own code etc should be done prior and outside the packaging.
When we call a snap app command, the logs are usually printed in the terminal. On the contrary when we are running a daemon, the logs are not instantly visible. Snap daemon are
systemd background services.
To visualize the last 100 lines of a snap daemon:
sudo snap logs SNAP_NAME.DAEMON_NAME -n 100
In case we want to wait for new lines and print them as they come in. We can use the -f option.
Additionally, if our snap contains multiple applications daemons, we can log them all by simply omitting the application name:
sudo snap logs SNAP_NAME -f
Similarly, we can use the pure systemd command:
journalctl -u snap.SNAP_NAME.DAEMON_NAME.service
As we can see, snap daemon are simply
systemd services with the
snap. prefix and the
.service suffix. For the sake of simplicity, the
snap logs command is preferred,
If the robot is not behaving as expected this should be the first action.
This way we can quickly check the output of our
When our snap is built and installed but doesn’t work as expected there are solutions. Our snap is running in a confined and containerized environment making the debugging sometimes more difficult.
Snap file structure
If we are curious about the folder/file structure of our system, we can simply check it from our host. As an example, we can list the files at the root of our snap system with:
$ ls /snap/SNAP_NAME/current etc/ lib/ meta/ opt/ usr/ var/
Everything under this directory
/snap/SNAP_NAME/current is only for our snap. When strictly confined, our snap cannot access anything outside this (apart from the different data directories). Checking the files in this directory can sometimes be enough to figure out our issue.
When it’s not enough, and we actually need to be in the snap environment to debug, we can run the snap run command along with the
snap run --shell SNAP_NAME.APP_NAME
This command is actually going to start a shell of the snap app environment (
command-chain included) instead of starting our app. This way, we have the exact same environment to run any kind of command. We can even call the application ourselves if we want to reproduce the issue. We can also potentially launch an entirely different command. Furthermore, we can then check the environment variables, files location, permissions etc.
Note that when calling
snap run --shell the started shell will be in the same directory where the command was called. Shelling into the snap environment will keep the original snap permissions.
This method has a very high potential for debugging our snaps.
Debugging a missing library
Robotics applications sometimes rely on hundreds of dynamic libraries. A very common error is that when an application starts, a library is missing. When this is happening a good way to verify that is to use
ldd. It will print the shared object libraries and their paths as they are found. So after calling the
snap run --shell SNAP_NAME.APP_NAME it’s the perfect moment to call
ldd on a library.
$ ldd $SNAP/opt/ros/foxy/lib/librmw.so linux-vdso.so.1 (0x00007fff841c5000) librcutils.so => /snap/MYSNAP/REVISION/opt/ros/foxy/lib/librcutils.so (0x00007f4c2276a000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4c2251b000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f4c22515000) /lib64/ld-linux-x86-64.so.2 (0x00007f4c2278d000)
In case one library is marked as not found, the definition of
$LD_LIBRARY_PATH is usually at fault.
If a library is missing in the library path but is installed, we can find its location with the help of the find command after entering the snap shell:
find $SNAP -type f -name "librmw.so"
Snaps are strictly confined, but they can access our host by the means of interfaces. These interfaces can sometimes be the source of our problems. Let’s see the different ways to troubleshoot them.
The very first thing that can help is the following command:
$ snap connections lxd Interface Plug Slot Notes lxd multipass:lxd lxd:lxd - Lxd-support lxd:lxd-support :lxd-support - network lxd:network :network - network-bind lxd:network-bind :network-bind - system-observe lxd:system-observe :system-observe -
Here we listed all the connections of our snap
lxd. As we can see all the interfaces have a
plug and a
slot. This means that everything is connected.
Some interfaces are auto-connect while some others are not. This means that we must connect them manually.
To do so we must use the command snap connect. An example of the usage would be:
sudo snap connect SNAP_NAME:camera :camera
The command above presupposes that our snap application had the
camera plug declared. Similarly, we can use the
snap disconnect command to undo the
When a snap cannot access a host resource that it was declared to access, checking the connection is usually a good starting point.
One can request “auto-connect“ on the forum of an interface that doesn’t auto-connect for a snap.
The snap, being strictly confined, sometimes tries to access resources that were not declared. It generates an App Armor policy violation that might be hard to diagnose.
The easiest way to find and fix policy violations is to use the
snappy-debug tool. It’s a tool provided by Canonical and allows us to:
- watches syslog for policy violations
- shows them in a human-readable format
- get recommendations for how to solve them
We can install the
snappy-debug tool with the command:
sudo snap install snappy-debug
We can then call the
snappy-debug command and in another terminal, call our snap app. The
snappy-debug tool could then produce an output similar to the following one:
mars 02 17:27:39 user-computer audit: AVC apparmor="DENIED" operation="open" profile="snap.SNAP_NAME" name="/dev/video0" pid=721546 comm="APP" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
In this log we can see that the access to
/dev/video0 was attempted and denied. This gives us the information that either our snap misses the
plug, or that we simply forgot to connect it.