Event Reporting (ER)

The ER framework in RCSW is meant to be a flexible and adaptable “front-end” to any number of implementations (plugins), providing a common interface and facilities. Important aspects/terminology:

  • The unit into which related functionality (and therefore event reporting) is grouped is called a module. Modules are file-based; that is, each .c file can correspond to at most one module.

  • A module is active if it has a valid handle; that is, if RCSW_ER_PLUGIN_INSMOD() was previously called for the module.

Usage

To use one of the existing RCSW ER plugins in your code, you need to:

  1. #define RCSW_ER_MODID and/or #define RCSW_ER_MODNAME to be the numeric UUID and string UUID for a module in your code and then #include <rcsw/er/client.h>.

    Tip

    Not all ER plugins use both RCSW_ER_MODID and RCSW_ER_MODNAME; see documentation for relevant plugins for details. Still, it’s generally good practice to always define both to make your code more robust and compatible with any RCSW ER plugin.

    For example, in src/ds/rbuffer.c we have something like this near the top of the file:

    #define RCSW_ER_MODID 0x0000100000000000
    #define RCSW_ER_MODNAME "rcsw.ds.rbuffer"
    #include "rcsw/er/client.h"
    
  2. Call RCSW_ER_MODULE_INIT() somewhere in your .c file, ideally in an initialization function. If a .c file you want to define a module for does not have such a function, you can put it in a common initialization function for your library/application. E.g.:

    void library_init(void) {
       #define RCSW_ER_MODID 0x1
       #define RCSW_ER_MODNAME "myapp.module1"
       RCSW_ER_MODULE_INIT()
    
       #define RCSW_ER_MODID 0x2
       #define RCSW_ER_MODNAME "myapp.module2"
       RCSW_ER_MODULE_INIT()
    }
    

    or:

    void library_init(void) {
       RCSW_ER_INSMOD(0x1, "myapp.module1")
       RCSW_ER_INSMOD(0x2, "myapp.module1h2")
    }
    

The two forms are equivalent. The first is generally more convenient for more OOP-oriented modules in separate files.

Note

If you want to be able to use the same code to define modules for different plugins, use RCSW_ER_MODNAME_BUILDER to define the names so that they will work with every plugin.

Levels

The reporting levels which RCSW uses across all its plugins should be familiar if you’ve dealt with logging before. All plugins support all logging levels. The levels are, ordered from most to least severe:

  • NONE - No event reporting

  • FATAL - Only FATAL events are emitted

  • ERROR - [FATAL, ERROR] events emitted

  • INFO - [FATAL, ERROR, INFO] events emitted

  • DEBUG - [FATAL, ERROR, INFO, DEBUG] events emitted

  • TRACE - [FATAL, ERROR, INFO, DEBUG, TRACE] events emitted

  • ALL - All events emitted

A somewhat unique feature: because RCSW works with LIBRA, you can set the levels for modules in two ways:

  • At compile-time, effectively disabling any events are lower severity levels; i.e., they will be compiled out.

  • At run-time, as you would expect (if the selected plugin supports it).

Plugins

The simple bare-bones logger.

This plugin uses RCSW’s built-in stdio_printf() and minimal stdlib implementation, to provide the necessary logging functionality in environments where stdlib is not available, and/or using stdlib hogs too much space.

In this plugin, each source file within RCSW and of each project which links with RCSW can define a logging “module”; modules are file-based, and therefore you can’t have multiple modules/loggers in a single file. If you architect your projects well, this should not be a burdensome restriction. You can split a logging module across several files if you want by defining RCSW_ER_MODNAME equivalently.

The modules in this plugin:

  • Are unconditionally enabled and cannot be disabled; that is, each time a logging statement is encountered during execution, it is always emitted.

  • Do not have a “level” associated with them which determines if a given logging statement should be emitted. Put another way, there is only a single global module whose level is set at compile time; statements less than the compile-time level are compiled out.

  • The name of each module is prepended to each logging statement to help identify the logging source.

Each emitted logging statement is of the form:

<RCSW_ER_MODNAME> [LVL] <message>

LVL is one of [FATAL, ERROR, INFO, WARN, DEBUG, TRACE], and <message> is the rendered message. RCSW_ER_MODNAME defines the logical name of the module.

This plugin is useful in:

  • Bare metal environments such as bootstraps without an OS.

  • Bare metal hardware validation tests.

Plugin Configuration Details

Configuration Item

Notes

RCSW_ER_PLUGIN_PRINTF

Defined as stdio_printf().

RCSW_ER_PLUGIN_INIT()

Idempotent/not used by this plugin.

RCSW_ER_PLUGIN_DEINIT()

Idempotent/not used by this plugin.

RCSW_ER_PLUGIN_REPORT()

None.

RCSW_ER_PLUGIN_INSMOD

Idempotent/not used by this plugin.

RCSW_ER_PLUGIN_LVL_CHECK

Not used by this plugin/always true.

RCSW_ER_MODNAME

The name of the module. Can have any format; it can be convenient to use a hierarchical format such as foo.bar.baz for interoperability with other plugins. See also RCSW_ER_MODNAME_BUILDER.

RCSW_ER_MODID

Not used by this plugin.