All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
Logging

Overview

Logging is an essential part of any application and can make it easier to figure out what is going on during application development and debugging. Qtilities provides a ready to use, thread safe and powerful logger which can easily be embedded into any Qt application. Logging is done through short and easy to use macros, or for more advanced logging requirements more sophisticated logging functions are available.

Logger engines provide back-ends for the logger and messages are formatted on a per engine basis. New logger engines or formatting engines can easily be created and added to the logger. The logger is able to store its configuration between sessions and a ready to use logging configuration widget is available in GUI applications.

The logger is only dependent on QtCore, thus it can be used in console or GUI applications. The Qtilities CoreGui library provides a widget logger engine which can be used with the logger in GUI applications. This article will show how to use the logger in a Qt application and provide an overview of the available features.

Table of contents:

First Steps

Overviews

First steps: Setting up the logger and logging example messages

The Qtilities::Logging::Logger provides macros to initialize it on application startup and to finalize in when the application exists. During initialization the logger will create standard logger engines and formatting engines and restore its settings from the previous session. The finalization does the opposite: it saves the current settings and deletes all the logger engines currently in the application.

Basic logging can be done through a set of macros which makes it very easy to log different types of messages. Lets look at a simple console application:

#include <QtilitiesLogging>
using namespace QtilitiesLogging;
int main(int argc, char *argv[])
{
QtilitiesCoreApplication a(argc, argv);
QtilitiesCoreApplication::setApplicationName("Console Logging Example");
// Before we initialize the logger, we want to use the same path in the logger and in
// QtilitiesCoreApplication. Since the logging lib does not depend on the core lib, we need to
// call QtilitiesCoreApplication::applicationSessionPath() which will set the session
// path in the logger to match the path used in QtilitiesCoreApplication.
// If it is still the default from QtilitieCoreApplicationPrivate, we set it to use AppData:
Log->setLoggerSessionConfigPath(QtilitiesCoreApplication::applicationSessionPath());
// Initialize the logger:
LOG_INITIALIZE();
// We want to capture all messages <= Debug level:
Log->setGlobalLogLevel(Logger::Debug);
// Create a file engine to verify the results.
// The file extensions are used to determine the formatting engine used for each file:
QString xml_example = QtilitiesCoreApplication::applicationSessionPath() + "/XML_Log.xml";
Log->newFileEngine("XML File Example",xml_example);
QString plain_example = QtilitiesCoreApplication::applicationSessionPath() + "/Plain_Log.log";
Log->newFileEngine("Plain File Example",plain_example);
QString html_example = QtilitiesCoreApplication::applicationSessionPath() + "/HTML_Log.html";
Log->newFileEngine("HTML File Example",html_example);
// Enable the Qt Message logger engine:
Log->toggleQtMsgEngine(true);
// Log messages to all engines:
LOG_INFO("Information Message");
LOG_WARNING("Warning Message");
LOG_ERROR("Error Message");
LOG_FATAL("Fatal Message");
LOG_DEBUG("Debug Message");
LOG_TRACE("Trace Message");
// Enable the console logger engine:
Log->toggleConsoleEngine(true);
// Disable the Qt Message logger engine:
Log->toggleQtMsgEngine(false);
// Disable the console logger engine:
Log->toggleConsoleEngine(false);
// Capture messages from the Qt Message System:
Log->setIsQtMessageHandler(true);
qDebug() << "Message from the Qt Message System";
Log->setIsQtMessageHandler(false);
qDebug() << "Message from the Qt Message System which will not be caught.";
int result = a.exec();
// Finalize the logger:
LOG_FINALIZE();
return result;
}

Logging in GUI applications

The above example showed basic usage of the logger in a console application, however in many applications the QtGui module is used and an user interface is provided to the user. In such applications it is desirable to have one or more ready to use logging widgets to display log messages to the user.

Ready to use logging widgets

The Qtilities CoreGui library provides ready to use logging widgets which can be accessed through the Qtilities::CoreGui::LoggerGui singleton's static methods. For example we can get log dock widgets as follows:

QMainWindow* mainWindow = new QMainWindow;
// Get a widget that shows all log messages:
QString log_widget_name = tr("Session Log");
QDockWidget* session_log_dock = LoggerGui::createLogDockWidget(&log_widget_name);
mainWindow->addDockWidget(Qt::BottomDockWidgetArea,session_log_dock);
// When creating new logger widgets through the LoggerGui class the name assigned
// to the log can change if a engine with the same name already exists. Therefore you pass
// the name to the logger as a pointer which will be updated with the new name if it
// was changed.
// We can now access the AbstractLoggerEngine instance like this:
AbstractLoggerEngine* log_engine = Log->loggerEngineReference(log_widget_name);
Q_ASSERT(log_engine);
// As an example, lets change the message context to log only messages logged to this engine:
log_engine->setMessageContexts(Logger::EngineSpecificMessages);
// Get a widget that shows only warning messages:
log_widget_name = tr("Warning Log");
QDockWidget* warning_dock = LoggerGui::createLogDockWidget(&log_widget_name,log_widget_name,true,Logger::Warning);
mainWindow->addDockWidget(Qt::TopDockWidgetArea,warning_dock);

The obtained dock widget will look similar to the image shown below:

log_dock_widget.jpg
Ready To Use Log Dock Widget

Logging configuration widget

The logging configuration widget can also be accessed using the Qtilities::CoreGui::LoggerGui class. For example:

// Get a reference to the logger configuration widget.
// The false parameter indicates that we don't want the Apply button to appear.
QWidget* config_widget = LoggerGui::createLoggerConfigWidget(false);
config_widget->show();
// The returned widget implements the IConfigPage interface, thus we can register it in the global object pool to be displayed in the configuration widget as follows:
OBJECT_MANAGER->registerObject(config_widget);

The obtained configuration widget will look like the image shown below:

logging_configuration_widget.jpg
Logging Configuration Widget

The example logging plugin

In the QtilitiesExamples project there is a session log plugin which can be used in any application which makes use of the Qtilities extension system. For more information see the Plugins Overview section of the Examples and Plugins page.

Advanced logging possibilities

Priority Logging

The logger provides the ability to log priority messages. A priority message is handled in the same way as a normal message logged with logMessage() except that it also emits the newPriorityMessage() signal. This allows selective messages to be emitted and displayed in a convenient place in an application where all messages should not necessarily be displayed. An example is the case where selective messages should be displayed in a status bar. The Qtilities::CoreGui::QtilitiesMainWindow class provides ready to use support for priority messages.

Logging of priority messages is very similar to the macros already shown in this article. Below is an example where we log different types of priority messages.

// Log different type of priority messages to all engines:
LOG_INFO_P("Priority Information Message");
LOG_WARNING_P("Priority Warning Message");
LOG_ERROR_P("Priority Error Message");
LOG_FATAL_P("Priority Fatal Message");
LOG_DEBUG_P("Priority Debug Message");
LOG_TRACE_P("Priority Trace Message");

Engine Specific Logging

The Qtilities logger allows logging to a specific engine where the name of the engine is used to determine the destination of the log messages. The following lines can be added to the example above as an example where we log specific messages to all three of the engines we created.

// Log messages to each engine separately:
LOG_INFO_E("XML File Example","XML Information Message");
LOG_WARNING_E("XML File Example","XML Warning Message");
LOG_ERROR_E("XML File Example","XML Error Message");
LOG_FATAL_E("XML File Example","XML Fatal Message");
LOG_DEBUG_E("XML File Example","XML Debug Message");
LOG_TRACE_E("XML File Example","XML Trace Message");
LOG_INFO_E("Plain File Example","Plain Information Message");
LOG_WARNING_E("Plain File Example","Plain Warning Message");
LOG_ERROR_E("Plain File Example","Plain Error Message");
LOG_FATAL_E("Plain File Example","Plain Fatal Message");
LOG_DEBUG_E("Plain File Example","Plain Debug Message");
LOG_TRACE_E("Plain File Example","Plain Trace Message");
LOG_INFO_E("HTML File Example","HTML Information Message");
LOG_WARNING_E("HTML File Example","HTML Warning Message");
LOG_ERROR_E("HTML File Example","HTML Error Message");
LOG_FATAL_E("HTML File Example","HTML Fatal Message");
LOG_DEBUG_E("HTML File Example","HTML Debug Message");
LOG_TRACE_E("HTML File Example","HTML Trace Message");

For more advanced logging operations the Qtilities::Logging::Logger::logMessage() function should be used directly. The logger singleton is directly accessible through the Log macro which returns a pointer to the logger. The log message function allows additional parameters to be passed to the logger. See the function documentation for more information.

Message Contexts

The logger groups messages using the concept of different message contexts. These contexts are described by the Qtilities::Logging::Logger::MessageContext enumeration. By default all logger engines accept messages from all message context. It is however possible to use specify combinations of message contexts explicitly for each individiual engine. For example:

// Create three file engines:
QString xml_example = QCoreApplication::applicationDirPath() + "/XML_Log.xml";
AbstractLoggerEngine* xml_file_engine = Log->newFileEngine("XML File Example",xml_example);
QString plain_example = QCoreApplication::applicationDirPath() + "/Plain_Log.log";
AbstractLoggerEngine* plain_file_engine = Log->newFileEngine("Plain File Example",plain_example);
QString html_example = QCoreApplication::applicationDirPath() + "/HTML_Log.html";
AbstractLoggerEngine* html_file_engine = Log->newFileEngine("HTML File Example",html_example);
// Do some context related logging:
if (xml_file_engine && plain_file_engine && html_file_engine) {
xml_file_engine->setMessageContexts(Logger::SystemWideMessages);
plain_file_engine->setMessageContexts(Logger::EngineSpecificMessages);
html_file_engine->setMessageContexts(Logger::PriorityMessages);
// Now log a system wide message: It will only appear in xml_file_engine.
LOG_INFO("System widge message");
// Now log some engine specific messages. Only the plain_file_engine will get the second message:
LOG_INFO_E(xml_file_engine->name(),"Engine specific message to XML.");
LOG_INFO_E(plain_file_engine->name(),"Engine specific message to PLAIN.");
LOG_INFO_E(html_file_engine->name(),"Engine specific message to HTML.");
// Now log a priority message: It will only appear in the html_file_engine.
LOG_INFO_P("Priority message");
}

Extending the logger: Create custom logger and formatting engines

The logger can easily be extended by creating new logger or formatting engines by creating classes which inherits from Qtilities::Logging::AbstractLoggerEngine and Qtilities::Logging::AbstractFormattingEngine respectively. See the class documentation for more information.



Qtilities : Reference Documentation Back to top Copyright © 2009-2013, Jaco Naudé