Logging System

TEMU has a built in logging API for emitting logging messages. Logging messages are emitted with a C-style formatting string.

Messages are organized using firstly a category and secondly a severity.

Logging Backends

The TEMU logging system is constructed around a single logging frontend (which is not visible to users), connected to a logging backend.

Several backends exists in TEMU. It is not possible for users to add their own backends, however generic backends can be added by TERMA on request.

The current logging backends include:

  • Stdout logging backend

  • Stderr logging backend

  • Legacy logging function backend

  • Advanced logging function backend

Stdout and Stderr Backends

The default backend is the stdout backend. The stderr backend is selected when launching temu with the --log-stderr command line flag.

Legacy Function Backend

The legacy function backend is enabled using the temu_logSetFunc() function:

void
myLoggingFunc(const char *msg) {
  printf("%s", msg);
}

temu_logSetFunc(myLoggingFunc)

The function receives a complete message string, including time stamp, source object name, category, severity AND a terminating linefeed.

Advanced Function Backend

The advanced function backend is a modernized logging backend, leaving more choices to the user.

It also lets you pass an arbitrary pointer as an extra argument.

It is enabled by calling the temu_logSetAdvancedFunc() function.

void
myAdvancedLoggingFunc(void *userData, temu_Object *source,
                      unsigned category, temu_LogLevel severity,
                      const char *msg)
{
  auto logger = reinterpret_cast<ILogger*>(userData);

  if (source) {
    logger->emitMessage(source->Name, msg);
  }
}


// ILogger *logger = ...;
temu_logSetAdvancedFunc(myAdvancedLoggingFunc,
                        &logger);

The advanced logging backend does not append a linefeed after the message.

Categories

Logging categories exist to organize messages and hint on the reason for the message being emitted.

Categories also provide the option of filtering using severity level using a per category basis.

In the text log (stdout or stderr),

The following categories are built in:

default

The default category is not named when emitting messages.

sim

The sim category is for various simulation related issues. E.g. if a device logs the reception of a packet from another model, the message should probably be in the sim category.

target

The target category indicates that the message is triggered by target software, i.e. .

config

The config category is intended to be used when errors are detected in the configuration of a model. E.g. if the user configures the model to raise an invalid interrupt number.

Categories are identified using an integer, and the first 8 categories are reserved for TEMU (although only the 4 above are defined at the moment). The default categories are all global at present.

An additional 8 categories can be defined by the user in a per class basis.

This is done using the temu_addLoggingCategory() function when the class is being registered.

Severities

Severities allows the filtering and handling of messages. On stdout/stderr messages are color coded for the terminal, with red indicating an error, orange a warning etc.

The following severities are defined:

fatal

A fatal error occurred, message is printed and then the program is aborted.

error

An error occurred, but TEMU will keep on running. E.g. target software writes an illegal value to a register.

warning

Something was detected that could be a problem, but is not necessarily that.

info

Informational messages.

trace

High volume trace messages.

debug

Debugging messages, these are NOT emitted if the model emitting these is compiled with -DNDEBUG=1. The +asserts configuration of TEMU will not emit debug messages.

The debug severity messages are emitted with an inline function. This lets the compiler optimize away the calls when -DNDEBUG is enabled.

Filtering

TEMU applies two filters on a per category basis.

The first filter that is applied is the per object filter. The per object filter bits are stored in the LoggingFlags field in temu_Object.

If the message is passed on through the per object filter, the global filter is applied which is also per category.

Filtering is typically controlled using the TEMU command line or TScript files using the log-level command.

However there is an API for controlling filtering as well.

Debug messages are controlled with the normal filters, but they are never emitted if -DNDEBUG is passed to the compiler. This setting is per compiled file in a model.
// Set global log level for all categories to warning
// Info messages or below will not be emitted.
temu_logSetLevel(teLL_Warning);

// Set the per object log level in myObj to error, for the sim category.
temu_objectSetLogLevel(myObj, teLC_SimCat, teLL_Error);

In the example above, after running the two lines:

  • All messages, independent of source object will be dropped if logging level is info or below using the global filter.

  • Messages from myObj, in the sim category will be dropped if the level is warning or below. Other messages from myObj will be filtered by the global level.