Skip to main content

Small minimal-overhead logging toolkit

Project description

smolt

Small minimal-overhead logging toolkit.

Introduction

Would you like to do printf-style logging on a microcontroller without the firmware needing to spend time doing string formatting? Format and print floating point values without pulling in large and slow formatting routines? Have logging be fast enough you can use it from interrupt handlers without the additional latency becoming an issue? Leave the format strings out of the flash entirely?

Smolt is a small header-only C++ library with no dependencies beyond a C++20 compiler with STL. All use of STL is constexpr.

When you make a log call, the format string and other metadata is given a tag ID, so the only data that needs to be sent or stored is the tag ID and the format arguments. The host side utilities can then use the tag ID to look up all the metadata from the .elf file and handle string formatting.

Features

  • Formatting of values on the host with Python's format string syntax.
    • Currently supports integral and floating point types up to 64 bit.
    • Basic support for std::span and std::string_view.
  • Optional metadata attached to messages.
    • Source location.
  • Pluggable transports.
    • transport::itm
      • Streaming logging over ARM ITM over SWO or parallel trace.
    • transport::ringbuffer
      • Logging to internal ringbuffer for later readout.
    • transport::blackhole
      • Dummy transport. Allows leaving logging calls sprinkled through the code without them needing to do anything.
    • Custom transports only have to implement log_tag(uint32_t) and log_value(uint32_t).
  • CLI utility
    • Receive and format log messages over ITM from Orbuculum and other sources that relay ITM messages over TCP.
  • GDB plugin
    • Read out and format log messages from a ringbuffer in target memory.

TODO

  • Add a custom formatter for std::span that allows setting both an element formatting specifier and an element separator.
  • Support for more argument types:
    • Pointers? (I.e. implicit conversion to uintptr_t and default formatting as hex.)
  • More transports:
    • transport::tee
      • Allows feeding a single logger into multiple transports.
  • More metadata that can be attached to messages:
    • Severity (info, warning, error, etc…).
  • CLI command that checks format string validity (i.e. whether the format specifiers are valid for the types of arguments passed). Can be added to the end of the build process to allow catching typos in format strings at compile time.
  • More checks and error handling.
  • Documentation.
  • More tests.

Usage

Example firmware

Try it in Compiler Explorer.

#include <limits>
#include <numbers>

#include <smolt.h>
using namespace smolt::info;

constexpr smolt::logger logger { smolt::transport::itm {} };

//smolt::transport::ringbuffer<256> log_buf;
//constexpr smolt::logger logger { log_buf };

//constexpr smolt::logger logger { smolt::transport::blackhole {} };

int main() {
    logger.log<"uint32_t max: {}", loc()>(std::numeric_limits<uint32_t>::max());
    logger.log<"uint32_t min: {}", loc()>(std::numeric_limits<uint32_t>::min());
    logger.log<"int32_t max: {}", loc()>(std::numeric_limits<int32_t>::max());
    logger.log<"int32_t min: {}", loc()>(std::numeric_limits<int32_t>::min());
    logger.log<"pi: {}", loc()>(std::numbers::pi_v<float>);

    while (true) {}
}

CLI usage

% smolt cflags
-I/Users/zyp/.pyenv/versions/3.12.0/lib/python3.12/site-packages/smolt/include
% smolt list example.elf
08000285: example.cpp:19 "pi: {}", float
08000281: example.cpp:18 "int32_t min: {}", long
08000279: example.cpp:16 "uint32_t min: {}", unsigned long
08000275: example.cpp:15 "uint32_t max: {}", unsigned long
0800027d: example.cpp:17 "int32_t max: {}", long
% smolt itm example.elf 
23:26:12 example.cpp:15 uint32_t max: 4294967295
23:26:12 example.cpp:16 uint32_t min: 0
23:26:12 example.cpp:17 int32_t max: 2147483647
23:26:12 example.cpp:18 int32_t min: -2147483648
23:26:12 example.cpp:19 pi: 3.1415927410125732

GDB usage

(gdb) python import smolt.gdb

(gdb) run

The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: example.elf 
^C
Program received signal SIGINT, Interrupt.
main () at example.cpp:21
21	    while (true) {}

(gdb) smolt rb log_buf

example.cpp:15 uint32_t max: 4294967295
example.cpp:16 uint32_t min: 0
example.cpp:17 int32_t max: 2147483647
example.cpp:18 int32_t min: -2147483648
example.cpp:19 pi: 3.1415927410125732
(gdb) 

How does it work?

A tag is effectively a dummy function that will never be called and therefore doesn't need to do anything, so it'll only contain a single return instruction and therefore only take up 2-4 bytes of flash. The reason it exists is so that we can use its address as a tag ID.

By making a function template for a tag, the compiler will emit these functions on demand whenever we ask for its address. Whatever template arguments are passed to the function template becomes part of the function identifier and therefore goes into the mangled symbol name.

This means that the source can easily create tags with arbitrary metadata attached, and the host side tools can easily retrieve the metadata by finding and decoding the tag symbols from the resulting .elf.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

smolt-0.2.tar.gz (12.3 kB view details)

Uploaded Source

Built Distribution

smolt-0.2-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

Details for the file smolt-0.2.tar.gz.

File metadata

  • Download URL: smolt-0.2.tar.gz
  • Upload date:
  • Size: 12.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.13.2 CPython/3.12.0 Darwin/23.1.0

File hashes

Hashes for smolt-0.2.tar.gz
Algorithm Hash digest
SHA256 fe8e23b0d6b89abc0491c76fde3ef1b0f6952080bfeea854d1f9be13180c1cdc
MD5 ce9f168c7645168fc0fde3dd3aedab17
BLAKE2b-256 803436830797aac4021842f51081d044a6b0cb19a10a482259f0ddfa9b9bb8da

See more details on using hashes here.

File details

Details for the file smolt-0.2-py3-none-any.whl.

File metadata

  • Download URL: smolt-0.2-py3-none-any.whl
  • Upload date:
  • Size: 9.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.13.2 CPython/3.12.0 Darwin/23.1.0

File hashes

Hashes for smolt-0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 ec2ebb1e6fcb02982bb1b6c9192804b168e27faf79da855a635e393d59703d94
MD5 3d0608f5df60eb49adf52329f2ea5c33
BLAKE2b-256 e09f2f82964b13ef9c75264683a62eb5e53359053c45d90e8116edf8b393fd56

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page