Tag Archives: logging

Log4Qt for Jolla Sailfish OS and in general

I had troubles with logging from my Qt code efficiently, so took an effort to find a good and flexible logging framework that works. Log4Qt is very powerful and works well, but lacks docs and examples. So I created a sample project that uses it and tried commenting it as much as I could. It is a Jolla Sailfish OS app, but with very small changes same should work for other platforms as well (Sailfish OS is pretty much just Linux + custom QML controls + requirements for the app binaries/data to be located in specific places).

If you are in a hurry, just go grab the code on github. If you are making Jolla apps, you can use the HelloWorld Pro wizard for renaming the project into my-cool app. The rest of this post is just an overview of what happens in the code and repeats comments quite a lot.

Why logging example

Logging in the Qt world is easy, but not really configurable. Here’s how you do it typically in c++:

and here’s how you do it in QML:

Most of the time I just comment out logging statements when there is too many of them. You can also stream the logs to file via qInstallMessageHandler() and there are some code examples for it.

That works great for normal development, but always takes time when you want to log the particular code unit without too much noise from the other ones. In Qt 5.3 situation will become better with the addition of configurable categories, you will be able to enable or disable whole groups of logs yet I still find it not flexible and configurable enough. Also Jolla Sailfish OS which I care at the moment most about is still on Qt 5.1

Log4Qt

Log4Qt is a port of a [not the latest version of the] popular Log4J library (that I happen to use too). It lets you be very simple or as advanced as you like: you can set priorities on many levels, stream logs to files, syslog, console, database even network and configure it all at run-time or via the settings files. There is only one problem: a lack of examples and documentation (docs are pretty much the ones that were ported from Log4J code).

Well, so I created a reference copy-pastable example project demonstrating many of the project features in [hopefully] the proper way. That is the project for Jolla Sailfish OS on which I focus lately, but with very minimal changes it should work for any other platforms as well (join to create ports or expand the current example to multiple platforms).

Features demonstrated

  • Multiple logging destinations: console, file (with daily log files), syslog
  • Different logging levels for different C++ classes and QML objects
  • Different logging levels for the different destinations (e.g. only ERROR+ messages to syslog, and DEBUG+ to console)
  • Configuration via stand-alone .conf files
  • Prioritized .conf file selection (falling back to default settings unless user puts another .conf file to a particular dir)
  • Different default configurations for the debug and release builds
  • A project structure that makes sense for the production projects: engine with C++ objects, app with QML objects, c++ tests and QML tests with little dependency on Log4Qt
  • A project that is good enough for passing Jolla Harbour criteria and getting to the app store
  • A separate “pseudo app” project that can be installed to the user’s device for generating more logs from the main app (basically just drops another .conf file to the proper directory)

How you use logging in your app

The easiest way to get started is to just clone log4qt-demo project. You can use rename-to-my-project.py script for renaming the project into my-cool-app, see HelloWorld Pro docs on how to do it.

Starting with Log4Qt one class at a time

Demo project configuration captures all console.log, qDebug(), qWarning() messages to the Log4Qt streams as a logger (unit of logging) called “Qt”, so you can continue using your current logging practices while introducing new logging facilities step by step

Logging from c++ objects

Then for the classes you want to log you state the following macro in their cpp implementation:

and from the class’s function you log one of the following ways

Logging from where these classes are used

For streaming syntax support you need to have the following in the class implementation:

And then from you main.cpp or from wherever else you can do, for example, the following:

Logging from QML

For intercepting QML logs, app part of the demo project injects QmlLogger into the QML engine. Then inside QML you can make as many loggers as you like (I recommend creating one per QML source file) and use them in the following manner:

File-based configuration

There are a couple of demo config files in the project.
What you mostly pay attention at during daily work is the bottom part where you shut up certain logging units or let them speak at the default DEBUG level:

How it is structured

There are two completely independent projects in the repository: the main one consisting of log4qt itself, engine, app, qmlTests, cppTests and increasedLoggingPackage that is sort of a fake app that makes main app produce more logs when installed (e.g. to the user experiencing tech issues).

Project structure

log4qt-demo-project-structure

  • increasedLoggingPackage is a completely stand-alone micro-project that just happens to exist in the same source tree. You build it separately and send to user if you want his app installation to produce more logs
  • Note that qmlTests project also exports a shell script to /usr/share/tst-harbour-log4qtdemo-qmlTests/runTestsOnDevice.sh that runs both cppTests and qmlTests. You can check HelloWorld Pro docs to see how to run it straight from Qt Creator.

Logging streams

Here’s what sort of structure a demo .conf file creates for your project:

log4qt-demo-logging-streams

You can have as many loggers as you like. I find it convenient to have one logger per class + logger called “Qt” that intercepts console.log and qDebug()/qWarning() streams. Then everything gets to rootLogger and spread further to so-called appenders that write to console, file or syslog (journalctl in Sailfish OS case).

Other things to note

  • Log4Qt is fetched via git subtree straight from https://gitorious.org/log4qt/ that is a slight variation of original http://log4qt.sourceforge.net/ that I chose for support for colored console output (that happened to be not working for *nix) and some other modifications that seemed to be maintained in 2014. That is good enough for my purposes, you may like to use the original Log4Qt in your projects.

Where help is needed most

There is a number of TODOs in the code and in github readme. The main need is in creating ports of the solution that won’t be Sailfish OS specific. You can create simple ports or ideally improve the current project so that it builds and runs for desktop as well

Your impressions

What do you think? Makes sense? Do you want to improve it? Go fork a github project and propose pull requests or create ports