Implementing RFC5424 for NuttX
Remember in
my blog post about my favourite QNX feature
I mentioned that I wanted some way to have a syslog
sink
that wrote log messages to the network? Well, I did my research after
that blog post and happened across
RFC5424, which is a
protocol for syslog
that defines how logs can be
sent/received in a networking context, as well as a standard format for
logs.
As it turns out, something called
syslogd
exists for system logging locally and remotely. There was a standard way
for handling system logs to a remote device. So, obviously, I had to
implement this (or at least a subset) for NuttX as a tool for
individuals in the same situation that I was: wanting system log access
in real-time over the network, but not willing/able to roll their own
method of doing it.
First I went ahead and wrote an implementation for RFC5424 formatting, which I documented here on the NuttX website. The way I've done this is by providing a Kconfig option that forces the syslog formatting to follow the RFC5424 standard. The user can still pick and choose which parts of the option specification they want to include (i.e. omit timestamps if they want) because RFC5424 logs can get quite verbose very quickly, and many NuttX devices are resource-constrained. The process for enforcing the formatting was quite straight-forward, and just involved adding another source file to be used instead of the default syslog print logic when the user selected the RFC5424 Kconfig option.
Writing the syslogd
program was less straightforward, since
the program described by the manpages was designed for a Unix system
assuming more features than is often used on a NuttX image. I resolved
to implement a small subset of the functionality, mostly because that
was all I needed for my use case, and partially because the remaining
functionality required checking for many different features and I didn't
want to bother setting all that up.
The main question for the implementation was how to get access to the
system logs so that they could be sent by this program over UDP (as the
spec generally uses). The answer was having a dependency on the NuttX
RAMLOG
implementation. The RAMLOG
implementation uses a buffer of
a pre-determined size to store printed system logs in RAM. However, it
also creates a device which can be read to consume the logs in the RAM
buffer. This is how the dmesg
system utility works on
NuttX. Now I was able to read from the RAMLOG
device within
the syslogd
utility and transmit each syslog message as one
UDP packet. The daemon spawns a copy of itself in the background once
run and it simply loops while blocking on the
RAMLOG
device, sending all of the complete syslog entries
it receives to the configured IP address over UDP. I've documented the
syslogd
program
here on the NuttX website.

A Raspberry Pi Pico W
It was very rewarding being able to run this properly on small devices.
The test device I used was a Pi Pico W connected to my home network. I
enabled file-system logging at the INFO
level, ran
syslogd
and began poking around at the
/proc
file system to trigger some logs. In the meantime, I
had Wireshark running on my host computer and was sniffing the packets
being sent from the Pico W. Sure enough, Wireshark detected them as
valid RFC5424 packets and even parsed out the information properly!

A screenshot of the Wireshark logs capturing and parsing syslog packets from the Pico W
The syslogd
implementation is pretty rudimentary as it
stands, but it is good enough to receive syslog data over the network
from a host device, which is sufficient for the use case I had. Maybe in
the future if I do anything more complicated with network devices, I'll
improve the implementation to become closer to the manpages. Until then,
that's for other contributors to work on if they need it!