QLogger
Loading...
Searching...
No Matches
QLogger

QLogger is made to be compatible with Qt framework logs management, this library provide an easy (and thread-safe) way to use multiple sinks behaviour.

Remarks
Latest development/pull requests will be committed into main branch.
Each stable release have their dedicated branch:
  • 1.0.x: branch dev/1.0
  • 1.1.x: branch dev/1.1
  • etc...

Table of contents:

1. Requirements

1.1. C++ Standards

This library requires at least C++ 11 standard (see implementation section for more details)

1.2. Dependencies

Below, list of required dependencies:

Dependencies Comments
Qt Library built with Qt framework and compatible with series 5.15.x and 6.x

2. How to build

This library can be use as an embedded library in a subdirectory of your project (like a git submodule for example):

  1. In the root CMakeLists, add instructions:
    add_subdirectory(qlogger) # Or if library is put in a folder "dependencies" : add_subdirectory(dependencies/qlogger)
  1. In the application CMakeLists, add instructions :
    # Link QLogger library
    target_link_libraries(${PROJECT_NAME} PRIVATE qlogger)

3. How to use

3.1. Initialization

This library only have to be initialized in the main method of the application, then all calls to Qt logs methods (qDebug(), qInfo(), qWarning(), etc...) of the application and used libraries will be redirected to QLogger. Multiple sinks behaviour are available:

Example:

#include "qlogger/qloggerfactory.h"
int main(int argc, char *argv[])
{
/* Set logs */
QLogger::QLoggerFactory::instance().initLoggerRotating(QFileInfo("logs/log.txt"), 3, 1024 * 1024 * 5, true);
/* Manage application properties */
QApplication app(argc, argv);
...
return app.exec();
}
void initLoggerRotating(const QFileInfo &file, int maxFiles, qint64 maxSize, bool enableConsole)
Use to configure rotating file log sink.
Definition qloggerfactory.cpp:113
static QLoggerFactory & instance()
Use to get current unique instance of QLoggerFactory.
Definition qloggerfactory.cpp:155

This will configure QLogger to:

  • Use logs/log.txt as main file (once rotated, generated files will be: logs/log1.txt and logs/log2.txt)
  • Number of logs files limited to 3
  • Log file max size limited to 5 megabytes (5Mb) (1 Kb = 1024 bytes, 1Mb = 1024 * 1024 bytes)
  • All logs messages will also be redirected to console (useful during development phase)

3.2. Desinitialization

QLogger library will properly destruct (and close) all used ressources automatically when application is closed. But if user need to quit QLogger manually, just use:

void desinit()
Use to release and close all used ressources.
Definition qloggerfactory.cpp:126

In this case, default Qt logger will be restablished. User can still use his own log behaviour with qInstallMessageHandler() method (QLogger must have been desinitialized !)

Remarks
If log sink must be changed while one has already been initialized, caller don't need to manually call desinit() method, each sink init method will properly take care of this.

3.3. Customization

3.3.1. Log format

By default, log message will be formatted as below, depending of type of build:

  • Release: [utc-date][type-log] log-msg
  • Debug: [utc-date][type-log] log-msg (cpp-file:cpp-line, cpp-function)

If source file informations must appears on logs even on release mode, please use the associated macro in your main CMakefile: QT_MESSAGELOGCONTEXT.

So for example, when using:

const QString strValue = "nine";
const int value = 9;
qDebug() << "My value is:" << myValue;
qDebug("String [%s] converted as number is [%d]", qUtf8Printable(strValue), value);

This will log:

[2023-07-09T13:36:09.245Z][debug] My value is: 9 (mainwindow.cpp:14, onMyCustomBtnClicked)
[2023-07-09T13:36:09.246Z][debug] String [nine] converted as number is [9] (mainwindow.cpp:15, onMyCustomBtnClicked)

Format log message can also be customized by using a custom QLogger::LogFormatter method, here an example:

#include "qlogger/qloggerfactory.h"
/*****************************/
/* Macro definitions */
/*****************************/
#define APP_LOG_FILE "logs/log.txt"
#define APP_LOG_NB_FILES 3
#define APP_LOG_SIZE (1024 * 1024 * 5) // Equals 5 megabytes (Mb)
#define APP_LOG_ENABLE_CONSOLE true
/*****************************/
/* Custom log formatter */
/*****************************/
QString logFormatter(const QLogger::LogEntry &log)
{
QString fmt = QString("[%1][%2] %3").arg(
QDateTime::currentDateTimeUtc().toString(Qt::ISODateWithMs),
log.getMsg()
);
/* Can we add context informations ? */
if(log.contextIsAvailable()){
fmt += QString(" (%1:%2, %3)")
.arg(log.getCtxFile().fileName())
.arg(log.getCtxLine())
.arg(log.getCtxFctName());
}
/* Terminate log line */
fmt += '\n';
return fmt;
}
/*****************************/
/* Main method */
/*****************************/
int main(int argc, char *argv[])
{
/* Set logs */
QLogger::QLoggerFactory::instance().initLoggerRotating(QFileInfo(APP_LOG_FILE), APP_LOG_NB_FILES, APP_LOG_SIZE, APP_LOG_ENABLE_CONSOLE);
/* Manage application properties */
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
Used to store all log entry informations.
Definition logentry.h:13
QString getTypeString() const
Get string type.
Definition logentry.cpp:88
const QString & getMsg() const
Get log message.
Definition logentry.cpp:221
bool contextIsAvailable() const
Use to know if context informations are available.
Definition logentry.cpp:110
QString getCtxFctName() const
Get function name.
Definition logentry.cpp:200
int getCtxLine() const
Get line of source code associated to log entry.
Definition logentry.cpp:146
const QFileInfo & getCtxFile() const
Get file of source code associated to log entry.
Definition logentry.cpp:128
static void setCustomFormat(CbFormatter formatter)
Register a custom formatter.
Definition logformatter.cpp:79

3.3.2. Log level

User can also configure whether or not all messages should be logged. By default, all messages are logged but that can be changed by choosing minimum level to use (see Qt log level enum doc):

void setLevel(QtMsgType idType)
Use to set minimum log level to use.
Definition qloggerfactory.cpp:141
Note
This example will set logger to only manage message of level: QtWarningMsg, QtCriticalMsg and QtFatalMsg

3.4. Library version

3.4.1. Compilation time

In order to easily check at compilation time library version (to manage compatibility between multiple versions for example), macro QLOGGER_VERSION_ENCODE (defined inside qloggerglobal.h file) can be used:

#if QLOGGER_VERSION >= QLOGGER_VERSION_ENCODE(2,0,0)
// Do stuff for version 2.0.0 or higher
#else
// Do stuff for earlier versions
#endif

3.4.2. Runtime

At runtime, it is recommended to use the static method:

#include "qlogger/qloggerfactory.h"
const QVersionNumber &qloggerSemver = QLogger::QLoggerFactory::getLibraryVersion();
static const QVersionNumber & getLibraryVersion()
Retrieve library semantic version at runtime.
Definition qloggerfactory.cpp:174

4. Documentation

All classes/methods has been documented with Doxygen utility and automatically generated at online website documentation.

Note
This repository contains two kinds of documentation:
  • Public API: Available via online website documentation or locally via Doxyfile docs/fragments/Doxyfile-public-api.in
  • Internal: Available locally only via docs/fragments/Doxyfile-internal.in

To generate documentation locally, we can use:

# Run documentation generation
doxygen ./Doxyfile-name
# Under Windows OS, maybe doxygen is not added to the $PATH
"C:\Program Files\doxygen\bin\doxygen.exe" ./Doxyfile-name
Remarks
You can also load the Doxyfile into Doxywizard (Doxygen GUI) and run generation.

5. Library details

5.1. Why another log library ?

We already have many good C++ logs libraries outside, so why to create a new one ? Since many of my custom application are built with Qt framework, I thought that having Qt framework as a dependency was already enough and didnt' want to use another just for logging. Besides, alternatives C++ logs libraries doesn't behave properly when used inside a library (.dll under Windows, .so under Linux) but Qt log framework allow such usage.

Qt log module allow to easily add our custom log behaviour throught qInstallMessageHandler(). This library is just build around that extension feature.

5.2. Implementation

This library use the singleton pattern to manage QLoggerFactory instance. This singleton was implemented using Meyer's Singleton pattern, this implementation use static variable initialization to ensure thread-safety at initialization. This doesn't ensure your singleton to be thread-safe... only his initialization and desininitialization are !
Note that (at least !) a C++11 compiler is required (C++11 added requirement for static variable initialization to be thread-safe).

‍For more informations about Meyer's Singleton, see below:

Then, library thread-safety is ensured by using a mutex whenever a log message is received (to prevent from thread-race issues when trying to write to log to file for example).

6. License

This library is licensed under [MIT license][repo-license].

7. Ressources