McuLog: Logging Framework for small Embedded Microcontroller Systems

An essential tool especially developing larger applications or distributed firmware is to use logging. This article presents an open source logging framework I’m using. It is small and easy to use and can log to a console, to a file on the host or even to a file on an embedded file system as FatFS.

Log Output

Log Output

Outline

While it is possible to monitor with the debugger multiple targets, it gets very difficult if the system is distributed or runs for days and weeks continuously as in this system. If something goes wrong, logs will be invaluable. While logging framework for host development are common, I have not found much suitable for embedded system. What I have found close to what I wanted was https://github.com/rxi/log.c by rxi or uLog (https://github.com/rdpoor/ulog) by Robert Poor. But I needed something more integrated and ready to use for my applications:

  • Different log levels (trace, warning, information, error, fatal)
  • Ability to set a log level (only log above a level)
  • Color coding based on log level
  • Open argument list (printf() style)
  • Different ways to log: UART/Terminal, file on the host, embedded file system
  • Command line/Shell interface
  • Small footprint, depending on the features used
  • Configurable, up to the point to completely disable it
  • Reentrant and integrated with FreeRTOS
  • Automatic and configurable date/timestamping
  • Easy to integrate, written in C

Source Files

The McuLog consists of three files (see links to GitHub at the end of this article) only:

  1. McuLogconfig.h: configuration header file
  2. McuLog.h: interface file
  3. McuLog.c: imlementation file

The configuration header file is used to configure the log format (with or without date, colors, if file system or RTT file logging shall be supported, etc). At the time of this article the following configuration items are available:

 
/*
 * Copyright (c) 2020, Erich Styger
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef MCULOGCONFIG_H_
#define MCULOGCONFIG_H_

#include "McuLib.h"

#ifndef MCULOG_CONFIG_IS_ENABLED
  #define MCULOG_CONFIG_IS_ENABLED            (1)
    /* 1: Logging is enabled; 0: Logging is disabled, not adding anything to the application code */
#endif

#ifndef MCULOG_CONFIG_USE_MUTEX
  #define MCULOG_CONFIG_USE_MUTEX             (1 && McuLib_CONFIG_SDK_USE_FREERTOS)
    /* 1: use a RTOS mutex for the logging module; 0: do not use a mutex */
#endif

#ifndef MCULOG_CONFIG_USE_COLOR
  #define MCULOG_CONFIG_USE_COLOR             (1)
    /* 1: use use ANSI color for terminal, 0: do not use color */
#endif

#ifndef MCULOG_CONFIG_USE_FILE
  #define MCULOG_CONFIG_USE_FILE              (0)
    /* 1: use use file for logging, 0: do not use file */
#endif

#ifndef MCULOG_CONFIG_LOG_TIMESTAMP_DATE
  #define MCULOG_CONFIG_LOG_TIMESTAMP_DATE    (1)
    /* 1: add date to timestamp, 0: do not date for timestamp */
#endif

#ifndef MCULOG_CONFIG_USE_RTT_LOGGER
  #define MCULOG_CONFIG_USE_RTT_LOGGER        (1)
    /* use use SEGGER RTT Logger (Channel 1), 0: do not use SEGGER RTT Logger */
#endif

#ifndef MCULOG_CONFIG_PARSE_COMMAND_ENABLED
  #define MCULOG_CONFIG_PARSE_COMMAND_ENABLED  (1 && MCULOG_CONFIG_IS_ENABLED)
  /* 1: shell command line parser enabled; 0: not enabled */
#endif

#endif /* MCULOGCONFIG_H_ */

Settings can be turned on/off at runtime too, e.g.

 
void McuLog_set_color(bool enable);

can be used to turn on/off color coding.

Usage

To use the McuLog module, include its interface:

 
#include "McuLog.h"

Before using it, call its initialization routine:

 
McuLog_Init();

Next, register one or more logger for the output, for example:

 
McuLog_open_logfile("0:\log.txt"); /* logging to a file */
McuLog_set_console(&UART_stdio); /* logging to a console */
McuLog_set_rtt_logger(true); /* log to a file on the host using RTT Data Logging */

After that, you can log messages with one of the available logging functions, e.g.

McuLog_trace("This is a trace message");
McuLog_debug("Function called returned error code %d", returnValue);
McuLog_info("Application started");
McuLog_warn("Log on memory, available bytes %d", HeapNofBytes);
McuLog_error("Failed creating task '%s', error code %d", taskName, res);
McuLog_fatal("Watchdog timed out, waiting for reset...");

Command Line Shell

McuLog includes an optional command line shell which is used to check the status and to configure it:

McuLog Command Line and Status

McuLog Command Line and Status

Logging to a Console

If logging to a console (or UART), it will print the messages on that connection. If the console is able to display colors (e.g. PuTTY or Segger RTT Console/Viewer), the messages are shown with different colors:

ANSI Colors in SEGGER RTT

ANSI Colors in SEGGER RTT

color coding

color coding

Logging to a File on the Host

Logging to a file on the host is implemented using RTT.

Start Data Logging on the host:

Start Data Logging

Start Data Logging

Then select the file where to log the data. Data is logged in a text file:

RTT Log File

RTT Log File

Logging to a file can be stopped any time.

Logging to a file on the target

The logger includes logging to an embedded file system using FatFS. It is possible to open and manage the file on the application side.
Or simply create or open the file with the McuLog:

McuLog_open_logfile("0:\myLogFile.txt");

The file is ‘synced’ for each log entry. To stop logging call

McuLog_close_logfile();

The messages will be present in the file on the embedded file system:

Logging to Embedded File System

Logging to Embedded File System

Summary

With the McuLog I have a small and versatile logging module which can log to console, host file system or to an embedded file system with small overhead. The module requires about 6 KByte flash (mostly because of printf() style), this without any code optimization. It uses simple callbacks and hooks, so if you need logging over I2C, USB, SPI, … or any other communication channel, this can be easily added or extended.

I hope you find this McuLog module as useful as I do.

Happy Logging 🙂

Links

 

16 thoughts on “McuLog: Logging Framework for small Embedded Microcontroller Systems

  1. What would be the requirements to run McuLog? For example, the cpu must be capable of running FreeRTOS and have 6KB of program space.. what about RAM? SEGGER RTT Logger?

    Like

  2. I like this as a small simple logging module- thanks Erich.
    I’ve extended the ‘trace’ logic to be enableable, via a bitmask- mainly because I have only a single UART to get any information over. This way I can group messages by logical function:
    Trace_feature(TraceMaskBitUART, “A UART trace\n”);
    This is only displayed when the TraceMaskBitUART bit is set, which I’d do with
    traceon 400
    for instance (also, ‘traceoff %x’)
    I’ve found this really useful to be able to debug modules by logical function without excessive ‘noise’. In fact, it has been my primary debugging method for several years. Hopefully it’ll help someone out.
    Cheers

    Like

    • Hi Rhys,
      I really like that idea of having such a bit mask, and that you can turn on/off logging for a group of things! I think I have to add something like this too :-).

      Like

      • Glad if you can make some use of it. Happy to send you my source as a reference if you like, I’d just rather not post it verbatim publicly. Can you contact me offline? (and not post this comment 😛 )

        Like

  3. Hi Erich,
    I am looking for a simple embedded log which should:
    1. Store the log in SRAM or flash memory, and the log has only 100 entries of 32 or 64-byte each, and organized as circular buffer manner.
    2. No any specific SW needed but a terminal SW such as TeraTerm to access the log via a serial port, and it will display the log content only when a command is received.

    Not sure if your log or the logs you mentioned can be the modified and configured with the requirements above.
    Thanks

    Like

  4. Pingback: How to get Data off an Embedded System: FatFS with USB MSD Host and FreeRTOS Direct Task Notification | MCU on Eclipse

  5. Pingback: How to Use Eclipse CDT Environment Variables in C/C++ Code | MCU on Eclipse

  6. Hello @Erich, seems a very interesting library indeed! Allow me for a probably noob question, but this library is only implemented in MCULib (so I’d guess it only works for NXP Processor Expert projects), so if I would repurpose it for a STM32Cube project, I’d need to reimplement it?

    Thank you for your attention

    Like

    • No, it can work with any microcontroller, as the library and McuLib is implemented in C. I’m mainly using it with NXP parts, but as well with microcontrollers from other vendors (see the list of processors in McuLibConfig.h).

      Like

Leave a Reply to Tommy Murphy Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.