Skip to content

Log Handlers

Inspired by the python logging module, this library implements a handler interface with the following handler implementations:

Multiple handlers can be used in parallel and each log will be sent to all registered handlers. See Using multiple handlers for more information.

Notes:

  1. By default, if no handlers has been registered when calling logger__init(), a default console handler is created and initialised. Subsequent calls to logger__init() will reinitialise all registered handlers.
  2. On embedded systems, the file handlers will most likely not work unless a filesystem implementation exists. This library is designed to have several options for customisation. See Customising Handlers.

Console Handler

Handler to log to stdout or stderr.

// Get a default logger_handler_t struct
// by passing a name and the stream to log to (stdout|stderr)
logger_handler_t handler = logger__handler_get_console("name", stdout);

// Register handler
logger__add_handler(handler);

// Init library and handlers
logger__init();

File Handler

Handler to log to filesystem.

// Requires a name and a filename
logger_handler_t handler = logger__handler_get_file("name", "out.log");

// Register handler
logger__add_handler(handler);

// Init library and handlers
logger__init();

Rotating File Handler

Handler to log to filesystem and rotate files.

// Requires a name, a filename, the maximum file size in bytes and the maximum number of backup files.
logger_handler_t handler = logger__handler_get_rotating_file("name", "out.log", 1000000, 10);

// Register handler
logger__add_handler(handler);

// Init library and handlers
logger__init();

This handler uses the rename and append rotation strategy. When the log file has reached the configured maximum size, all backups files are renamed from the oldest to the newest:

  • "out.log.2" renamed to "out.log.3"
  • "out.log.1" renamed to "out.log.2"
  • "out.log" renamed to "out.log.1"

Subsequent logs will be added to "out.log` until the next rotation.
If the maximum backup count is reached, the oldest index file will be removed before the renaming takes place.

Using multiple handlers

You can register multiple handlers at runtime and logs will be forwarded to all handlers.

// Adding a console handler
logger_handler_t console = logger__handler_get_console("console", stdout);
logger__add_handler(console);

// Adding a file handler
logger_handler_t file = logger__handler_get_file("file", "out.log");
logger__add_handler(file);

// Init library and handlers
logger__init();

// Start logging ...
log_i("main", "Hello World!");

You can also remove a handler at runtime:

// Remove handler
logger__remove_handler("console");

Customisation

Several options exist for customisation of the handler system.

Customising existing handlers

Overriding printf

All exisiting handlers support overriding the "print" function called internally. By default, vfprintf from <stdio.h> is used.

// Custom implementation of a print function having the same signature as 'vfprintf'.
int custom_vfprintf(FILE *file, const char *format, va_list args) {
    // ...
    return 0;
}

// Overide vfprintf function used by handler
logger__handler_set_print_function("console", custom_vfprintf);

See the examples or tests directories for more concrete examples.

Custom Handler

TODO