Note: You can find the source code for the bit flag logger generator on Github.
The logging system I wrote for Metric Panda Engine uses bit masks to support arbitrary composition of logging categories like so:
Log macro takes a bit mask that is used to filter log messages based on a verbosity mask. The log message, in this case a simple
printf, is prepended with a prefix that is generated from the bit mask.
Category labels used in the log prefix are resolved at compile time, when building in optimized mode, and the only branch is on the verbosity bit-mask.
Why bit masks
Other than the fact that, in my opinion, the API is quite comfortable, using bit masks makes pinpoint filtering much easier.
For example, in Metric Panda Engine I use three log categories, with labels along these lines:
When investigating a particular subsystem, it is quite easy to filter only events related to it, for example by setting the verbosity mask to
RENDER|INIT messages of any severity coming from the initialization part of the rendering subsystem are shown.
In order to keep category labels short and easy to type, while also avoiding name collisions, the
Log macro looks like this:
As you can see, the short labels are “aliases” to longer equivalents with the
LOG_ prefix. The shorter labels are confined to the scope of the macro so they don’t leak out causing collisions.
Unfortunately collisions can still occur if macros in the outer scope have the same name as the short labels, like the following example:
Fortunately the collision is detected at compile time, so it can be easily fixed by changing the conflicting log label. In Metric Panda Engine I removed all external includes so I have the luxury of using concise names without fear of collisions.
Filtering log entries
Filtering is done by wrapping the actual logging function in an
if statement like so:
GlobalVerbosity variable is an integer that can be set to the desired bit mask. Since the
GlobalVerbosity is set outside the macro, the longer version of the log labels are used, like so:
Printing label strings
In order to print the labels I’m using simple lookup functions that look like this:
As I mentioned earlier, this function is trivially collapsed by the compiler since the
Flags variable is known at compile time, so there is no cost to this approach.
LOG_PRIORITIES_MASK is an integer that masks only the bits that, in this case, make up the priorities labels.
Generating the logger code
I extracted the relevant bits into a standalone logger generator, loggen that is up on Github.
Give it a try!