QBLOG.H(3)
π qblog.h β the logging API, bestie edition π
okay so this is qblog.h, from the libqb Programmer's Manual β it's the header you pull in, and the man page is qblog.h(3). sit down, grab a strawberry π, we're gonna go through the whole thing together.
β¨ NAME β¨
qblog.h β the logging API, and it's giving four main parts: basics, filtering, threading & blackbox. that's the whole vibe. four icons, one header. π
πΈ SYNOPSIS πΈ
#include <qb/qblog.h>
that's it. that's the entrance fee. π
π¦ DESCRIPTION π¦
the whole idea behind this logging system is that it is not prescriptive. it's not gonna boss you around. it's just a set of tools so you, the developer, can get to what you want quickly and easily. no cap. π«Ά
π Basic logging API
call qb_log() to make a log message. then, to actually write that message somewhere that matters, call qb_log_ctl() to configure the targets. that's the whole loop, bestie.
simplest possible use:
main() {
qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
// ...
qb_log(LOG_WARNING, "watch out");
// ...
qb_log_fini();
}
look at that. clean. iconic.
π Configuring log targets
a log target can be syslog, stderr, the blackbox, stdout, or a text file. by default, only syslog is enabled. and like β that's normal for daemons, sure, but it's rarely appropriate for ordinary programs. so if you're using other targets (see below, keep reading bestie), you should turn syslog off:
qb_log_ctl(B_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
to enable a target, do this:
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
so: syslog, stderr, the blackbox, and stdout are static β they don't need to be created, you just enable or disable them. periodt.
but you can open multiple logfiles, as long as they fall within the inclusive range QB_LOG_TARGET_DYNAMIC_START up to QB_LOG_TARGET_DYNAMIC_END. to do that:
mytarget = qb_log_file_open("/var/log/mylogfile");
qb_log_ctl(mytarget, QB_LOG_CONF_ENABLED, QB_TRUE);
once your targets are enabled/opened, you can configure them. β¨
configure the size of blackbox:
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024*10);
make logging to file threaded:
qb_log_ctl(mytarget, QB_LOG_CONF_THREADED, QB_TRUE);
now β sometimes syslog daemons are (pre)configured to filter messages not exceeding a particular priority. when that happens to be your logging target, the designated priority of the message gets passed along unchanged, which can possibly result in message loss. π for messages up to LOG_DEBUG importance, you can work around it by proportionally bumping the priorities passed to syslog β here, the step is such that LOG_DEBUG gets promoted to LOG_INFO:
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP,
LOG_INFO - LOG_DEBUG);
and to make sure all logs to file targets are fsync'ed β meaning new messages are expressly transferred to the storage device as they keep coming β use this (otherwise it defaults to QB_FALSE):
qb_log_ctl(mytarget, QB_LOG_CONF_FILE_SYNC, QB_TRUE);
π§ Filtering messages
want more power over what log messages go to which target? apply filters to the targets, babe. here's the tea: the desired callsites get 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:
okay not me pointing out that the original just... trails off there π the sentence ends at "based on the:" and that's literally it. i'm not adding anything, i'm just saying β cliffhanger. anyway. moving on. π
so to make all logs from evil_function() go to stderr, do:
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FUNCTION, "evil_function", LOG_TRACE);
so to make all logs from totem* (with a priority <= LOG_INFO) go to stderr, do:
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "totem", LOG_INFO);
so to make all logs with the substring "ringbuffer" go to stderr, do:
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FORMAT, "ringbuffer", LOG_TRACE);
three filters, three vibes, all slaying. π
β Thread safe non-blocking logging
read this part twice, bestie, it matters:
logging is only thread safe when threaded logging is in use. so if you plan on logging from multiple threads, you must initialize libqb's logger thread and use qb_log_filter_ctl to set the QB_LOG_CONF_THREADED flag on all the logging targets in use.
and to achieve non-blocking logging β so that any calls to write() or syslog() won't hold up your program β you can use threaded logging as well.
threaded logging use:
main() {
qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_THREADED, QB_TRUE);
// ...
daemonize();
// call this after you fork()
qb_log_thread_start();
// ...
qb_log(LOG_WARNING, "watch out");
// ...
qb_log_fini();
}
note the comment: call qb_log_thread_start() after you fork(). that's the whole point of the placement, don't move it. π
π A blackbox for in-field diagnosis
this one stores log messages in a ringbuffer so they can be written to file if the program crashes (and yeah β you will need to catch SIGSEGV). then you can easily print them out later. it's literally a little time capsule for your crash. π
blackbox usage:
static void sigsegv_handler(int sig)
{
(void)signal (SIGSEGV, SIG_DFL);
qb_log_blackbox_write_to_file("simple-log.fdata");
qb_log_fini();
raise(SIGSEGV);
}
main() {
signal(SIGSEGV, sigsegv_handler);
qb_log_init("simple-log", LOG_DAEMON, LOG_INFO);
qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_SIZE, 1024*10);
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE);
// ...
qb_log(LOG_WARNING, "watch out");
// ...
qb_log_fini();
}
π Tagging messages
you can tag messages using the second argument to qb_logt(), or by using qb_log_filter_ctl(). this is how you add feature or sub-system info to your logs. so cute, so useful.
const char* my_tags_stringify(uint32_t tags) {
if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT) {
return "libqb";
} else if (tags == 3) {
return "three";
} else {
return "MAIN";
}
}
main() {
// ...
qb_log_tags_stringify_fn_set(my_tags_stringify);
qb_log_format_set(QB_LOG_STDERR, "[%5g] %p %b");
// ...
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 how [MAIN ] has that space? that's the %5g doing its thing. it's giving aligned. β¨
π NOTE π
the blackbox is not enabled by default. like, at all. you have to go get it. π«Ά
π SEE ALSO π
all the sibling pages, no skips, here they are:
qb_log_filter_fn_set(3), qb_log_from_external_source_va2(3), qb_log_thread_start(3), qb_log_target_user_data_get(3), qb_log_tags_stringify_fn_set(3), qb_log_file_reopen(3), qb_log_fini(3), qb_log_callsites_dump(3), qb_log_ctl2(3), qb_log_target_user_data_set(3), qb_log_target_format(3), qb_log_thread_priority_set(3), qb_log_facility2int(3), qb_log_callsites_register(3), qb_log_filter_ctl2(3), qb_log_file_close(3), qb_log_format_set(3), qb_log_real_(3), qb_log_from_external_source_va(3), qb_log_callsite_get(3), qb_log_blackbox_write_to_file(3), qb_log_real_va_(3), qb_log_from_external_source(3), qb_log_blackbox_print_from_file(3), qb_log_facility2str(3), qb_log_callsite_get2(3), qb_log_ctl(3), qb_log_filter_ctl(3), qb_log_custom_close(3), qb_log_init(3), qb_log_file_open(3), qb_log_custom_open(3)
πΈ COPYRIGHT πΈ
Copyright (c) 2017 Red Hat, Inc.
and that's the whole page, bestie!! LIBQB, dated 2025-09-16 β that's the source and the version and the date, all wrapped up in a bow π go forth and log responsibly, you absolute main character. πβ¨π¦
π¦ where this page comes from
- fedora 44: libqb-devel 2.0.9-2.fc44 Β· LGPL-2.1-or-later
- fedora 44: libqb-devel 2.0.9-2.fc44 Β· LGPL-2.1-or-later
- ubuntu resolute: libqb-dev 2.0.9-1ubuntu1 Β· LGPL-2.1-or-later
- ubuntu stonking: libqb-dev 2.0.9-1ubuntu1 Β· LGPL-2.1-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms