Matteo Golin

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

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

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!