libqb  0.16.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Logging

The logging API provides four main parts (basics, filtering, threading & blackbox).

The idea behind this logging system is not to be prescriptive but to provide a set of tools to help the developer achieve what they want quickly and easily.

Basic logging API.
Call qb_log() to generate a log message. Then to write the message somewhere meaningful call qb_log_ctl() to configure the targets.

Simplist possible use:

main() {
qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
// ...
qb_log(LOG_WARNING, "watch out");
// ...
}
Configuring log targets.
A log target can by syslog, stderr, the blackbox or a text file. By default only syslog is enabled.

To enable a target do the following

syslog, stderr and the blackbox are static (they don't need to be created, just enabled or disabled. However you can open multiple logfiles (32 - QB_LOG_BLACKBOX). To do this use the following code.

mytarget = qb_log_file_open("/var/log/mylogfile");
Once your targets are enabled/opened you can configure them as follows: Configure the size of blackbox

Make logging to file threaded:

To workaround your syslog daemon filtering all messages > LOG_INFO

To ensure all logs to file targets are fsync'ed (default QB_FALSE)

Filtering messages.
To have more power over what log messages go to which target you can apply filters to the targets. What happens is the desired callsites have the correct bit set. Then when the log message is generated it gets sent to the targets based on which bit is set in the callsite's "target" bitmap. Messages can be filtered based on the:
  1. filename + priority
  2. function name + priority
  3. format string + priority

So to make all logs from evil_fnunction() go to stderr do the following:

So to make all logs from totem* (with a priority <= LOG_INFO) go to stderr do the following:

So to make all logs with the substring "ringbuffer" go to stderr do the following:

Threaded logging.
To achieve non-blocking logging you can use threaded logging. So any calls to write() or syslog() will not hold up your program.

Threaded logging use:

main() {
qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
// ...
daemonize();
// call this after you fork()
// ...
qb_log(LOG_WARNING, "watch out");
// ...
}
A blackbox for in-field diagnosis.
This stores log messages in a ringbuffer so they can be written to file if the program crashes (you will need to catch SIGSEGV). These can then be easily printed out later.
Note
the blackbox is not enabled by default.

Blackbox usage:

static void sigsegv_handler(int sig)
{
(void)signal (SIGSEGV, SIG_DFL);
qb_log_blackbox_write_to_file("simple-log.fdata");
raise(SIGSEGV);
}
main() {
signal(SIGSEGV, sigsegv_handler);
qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
// ...
qb_log(LOG_WARNING, "watch out");
// ...
}
Tagging messages.
You can tag messages using the second argument to qb_logt() or by using qb_log_filter_ctl(). This can be used to add feature or sub-system information to the logs.
const char* my_tags_stringify(uint32_t tags) {
return "libqb";
} else if (tags == 3) {
return "three";
} else {
return "MAIN";
}
}
main() {
// ...
qb_log_tags_stringify_fn_set(my_tags_stringify);
// ...
qb_logt(LOG_INFO, 3, "hello");
qb_logt(LOG_INFO, 0, "hello");
}

The code above will produce:

[libqb] some message
[three] info hello
[MAIN ] info hello

See Also
qblog.h