Logging

Introduction

The header <utilities/log.h> supplies a couple of macros for simple logging and debugging messages.

1LOG(...)
2DBG(...)
1
These messages are dispatched unless the NO_LOGS flag is set at compile time.
2
These messages are dispatched only if the DEBUG flag is set at compile time.

These macros create and dispatch utilities::message objects, which hold the user-supplied message and location information specifying the message’s creation location. The LOG and DBG macros automatically pass the correct source code location information to the message.

The message payload can be anything that works for the facilities in std::format. The default message handler prints the source code location if there is no payload.

Microsoft’s old traditional preprocessor is not happy with these macros, but their newer cross-platform compatible one is fine. Add the /Zc:preprocessor flag to use that upgrade at compile time. Our CMake module compiler_init does that automatically for you.

Message Handling

The macros create and immediately dispatch messages to a message handler. The default handler prints the message and the location information to a default stream std::cout. You can change that default stream, for example:

log_file = std::ofstream("log.txt");
utilities::message::stream = &log_file;

For fancier usage, you can interpose your message handler

void my_handler(const utilities::message& msg) { ... }
utilities::message::handler() = my_handler;

Your handler can do whatever it likes with the messages it receives. You can revert to the default handler by calling the class method utilities::message::use_default_handler().

Everything here is deliberately rudimentary, and there is no consideration for rotating log files, etc., or for streaming efficiencies. The primary use case for the macros above and the underlying utilities::message class is easily printing useful messages during the development cycle. The emphasis is on ease of use as opposed to great generality or speed. During the development cycle, the typical output is going to be small anyway.

Example (source file named example.cpp)

#include <utilities/log.h>
int add(int x, int y)
{
    DBG("The DEBUG flag was set at compile time.");
    LOG("x = {}, y = {}", x, y);
    return x + y;
}

int main()
{
1    LOG();
    return add(10, 11);
}
1
A call to LOG without any message will print the source location.

Output

[LOG] function 'main' (example.cpp, line 11)
[DBG] function 'add' (example.cpp, line 4): The DEBUG flag was set at compile time.
[LOG] function 'add' (example.cpp, line 5): x = 10, y = 11

See Also

verify.h

Back to top