Qt Weekly #1: Categorized Logging

Published Tuesday March 11th, 2014 | by

Categorized logging allows you to structure your logging statements into categories, and to conveniently configure logging for individual categories in a central place. The feature is part of Qt 5.2, but will get some convenient extensions in Qt 5.3.

Since the dawn of times Qt has had it’s own little logging helpers – qDebug(), qWarning(), qCritical(), and qFatal(). Being part of QtCore, they are ubiquitous, also in the Qt code itself. Anyhow, the problem with logging is often enough that you’re doing too much of it (you get flooded with output), too few (you do not get enough to e.g. debug a problem), or both … In Qt 5.2 we started to address this by letting you split your logging messages into “categories”, and with Qt 5.3 there will finally be an easy, default way to enable output for these rules, through a configuration file.

Logging Categories

Let’s have a look at an example. Say you’re working on an awsome new game named “FlappyCat”, which features a high score:

bool Highscore::load(const QString &filepath)
{
    QLoggingCategory fcIo("fc.io");
    qCDebug(fcIo) << "Loading highscore ...";

    QFile file(filepath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qCWarning(fcIo) << "Could not open file " << filepath << "!";
        return;
    }
    // ...
}

which prints:

fc.io: Loading highscore ...
fc.io: Could not open file  "highscore.xml" !

So, what’s happening here?

  • QLoggingCategory represents a category in code, in this case it’s “fc.io”. It’s not a one to one mapping though … you can have multiple instances representing the same category.
  • qCDebug, qCWarning, and qCCritical allow you to log into a specific category. They also check whether the category has been enabled or not before assembling the message, which ensures adding logging statements is cheap when not used (which is the reason we could not just overload qDebug() and friends).
  • The default QtMessageHandler prints the logging category in front of the message.

Alternatively, we could also define all categories in one place:

fclogging.h:

#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(fcIo)
Q_DECLARE_LOGGING_CATEGORY(fcRender)
Q_DECLARE_LOGGING_CATEGORY(fcLogic)

fclogging.cpp:

#include "fclogging.h"
Q_LOGGING_CATEGORY(fcIo, "fc.io")
Q_LOGGING_CATEGORY(fcRender, "fc.render")
Q_LOGGING_CATEGORY(fcLogic, "fc.logic")

Q_DECLARE_LOGGING_CATEGORY and Q_LOGGING_CATEGORY are macros that let you conveniently define global categories.

Logging Rules

So how can you tweak the categories to suppress or enable individual levels? Let’s have a look at main.cpp:

int main(int argc, char **argv)
{
    QGuiApplication app(argc, argv);
    QLoggingCategory::setFilterRules("*.debug=false\n"
                                     "fc.io.debug=true");
    // ...
}

Logging rules are defined as free text, and set e.g. by calling setFilterRules(). In this case the first filter disabled any QtDebugMsg output, for all categories. But the second rule overwrites this for the “fc.io” category.

Logging Configuration File (5.3 addition!)

However, it’s still inconvenient to recompile your application, just to set the rules. In Qt 5.3 you will therefore be able to set a logging configuration file, too.

~/.config/QtProject/qtlogging.ini:

[rules]
*.debug=false
fc.io.debug=true

The logging configuration file is looked up in different locations depending on the platform. Another convenient addition in Qt 5.3 will be that you can use categorized logging also in a printf-style way:

qCDebug(fcIo, "Loading highscore ...");

Check out the documentation in Qt 5.3, once it becomes available !

Qt Weekly is a new blog post series that aims to give your daily Qt usage a boost. Stay tuned for next week’s post!

Did you like this? Share it:

Posted in C++, Qt | Tags: ,

15 comments to Qt Weekly #1: Categorized Logging

Scorp1us says:

I recently became enamored with Q_FUNC_INFO and I don’t see that being replaced by this, unless I can include that information in the logger. Also, does this mean there is now a logging application with filter capability?

./myprog 2&> logfile.txt && log logfile.txt
?

Scorp1us says:

It also seems that you’re filtering logging output at the application level. I think that is backwards. I’d rather get the full logging output and then sort/filter through that rather than having to adjust the filter level and restart the program.

If you’ve ever used procmon.exe on windows, you know how handy this methodology is.

Kai Koehne says:

If you’re using procmon.exe on Windows you’re probably also aware that the windows debugger log is a system global thing, and how annoying it can be if spurious apps dump heaps of debugging information in there all the time :)

On a more serious node: It’s completely up to you whether you use the rules to filter early on, or whether you filter the log afterwards … Both has it’s use cases.

The nice thing about the early check though is that the overhead is very small (basically a boolean check) if the category/debug level is disabled, which means you can safely use it even in performance critical code.

Kai Koehne says:

Regarding Q_FUNC_INFO, you can tweak the default message handler to print function names with the QT_MESSAGE_PATTERN environment variable and qSetMessagePattern() function, e.g.

QT_MESSAGE_PATTERN=”%{function} %{message}” ./myapp

See also the documentation of http://qt-project.org/doc/qt-5/qtglobal.html#qSetMessagePattern .

Regarding a logging application with filter capability … well, we don’t ship one, but filtering the output should be really easy to do with on board tools like grep, awk, perl, …

Andy says:

This is cool – I can see it being useful.

I also really like the idea of a short, bite-sized “weekly” like this – you can highlight some of the little classes and features that are less well-known or explored.

Thanks!

Andy Brice says:

Looks useful.

Your RSS feed is broken, I get:
502 Bad Gateway

Kai Koehne says:

You’re right, I’ll forward this …

Kai Koehne says:

Looks like it’s working again.

Markus says:

Thanks for the article. I also like the idea of short weekly articles highlighting some nice tools/classes making your work with Qt even more productive.

thank you for finally including this functionality in Qt!

Kai Koehne says:

You’re welcome :) The categorized logging feature has actually quite some history (back to Qtopia), so a lot of people have been involved over the time …

JR says:

Oh, Qt Weekly, really nice. How about making it Qt Monthly with an option to print it out as pdf similar to Qt Quarterly ;)? Really respect these deeper into and way to do it – articles and honest will to share the information.

QT_Commercial_customer says:

Is there a plan to include a rotating file logging system? Something able to replace the third party Log4QT library (or others) widely used for application logging.

Kai Koehne says:

No detailed plans I’m aware of, but it’s certainly something that would be a natural extension … not in QtCore, but e.g. as a addon library.

Maybe you can file this as feature request / suggest it to Qt Support?

Commenting closed.