pure-cpp 1.0.0
A C++ physics simulation benchmark comparing performance with Python implementations
logger.hpp
Go to the documentation of this file.
1#ifndef LOGGER_HPP
2#define LOGGER_HPP
3
4/**
5 * \file logger.hpp
6 * \brief Manages application logging based on command-line arguments.
7 * \author Le Bars, Yoann
8 * \ingroup UtilsLogging
9 *
10 * This file is part of the pure C++ benchmark.
11 *
12 * This class sets up a custom Qt message handler to filter logs by level and
13 * route them to the console, a file, or syslog as specified by the user.
14 */
15
16#include <QDebug>
17#include <QFile>
18#include <QHash>
19#include <QSet>
20#include <QString>
21#include <QTextStream>
22#include <iostream>
23
24#ifdef Q_OS_UNIX
25#include <syslog.h>
26#endif
27
28#include "cmd_line_parser.hpp"
29
30namespace AppUtils {
31
32 /**
33 * \brief Manages application logging based on command-line arguments.
34 * \ingroup UtilsLogging
35 */
36 class Logger {
37 public:
38 /**
39 * \brief Initialises the logger and installs the custom message
40 * handler.
41 *
42 * \param in_args The parsed command-line arguments.
43 */
44 explicit Logger(const CmdLine::CmdLineArgs& in_args) : args_(in_args) {
45 instance_ = this; // Set the static instance
46
47 // Define the filtering hierarchy.
48 QHash<CmdLine::LogLevel, QSet<QtMsgType>> logHierarchy;
49 logHierarchy[CmdLine::LogLevel::Debug] = {
50 QtDebugMsg, QtInfoMsg, QtWarningMsg, QtCriticalMsg, QtFatalMsg};
51 logHierarchy[CmdLine::LogLevel::Info] = {QtInfoMsg, QtWarningMsg,
52 QtCriticalMsg, QtFatalMsg};
53 logHierarchy[CmdLine::LogLevel::Warning] = {
54 QtWarningMsg, QtCriticalMsg, QtFatalMsg};
55 logHierarchy[CmdLine::LogLevel::Critical] = {QtCriticalMsg,
56 QtFatalMsg};
57 logHierarchy[CmdLine::LogLevel::Fatal] = {QtFatalMsg};
58 activeLevels_ = logHierarchy.value(args_.log_level_);
59
60 levelPrefixes_[QtDebugMsg] = "[debug]";
61 levelPrefixes_[QtInfoMsg] = "[info]";
62 levelPrefixes_[QtWarningMsg] = "[warning]";
63 levelPrefixes_[QtCriticalMsg] = "[critical]";
64 levelPrefixes_[QtFatalMsg] = "[fatal]";
65
66#ifdef Q_OS_UNIX
67 if (!args_.debug_syslog_.empty()) {
68 openlog(args_.debug_syslog_.c_str(), LOG_PID, LOG_USER);
69 }
70#endif
71 if (!args_.debug_file_.empty()) {
72 logFile_ = std::make_unique<QFile>(
73 QString::fromStdString(args_.debug_file_));
74 if (logFile_->open(QIODevice::WriteOnly | QIODevice::Text)) {
75 logStream_ = std::make_unique<QTextStream>(logFile_.get());
76 } else {
77 qWarning()
78 << "Could not open log file:" << logFile_->fileName();
79 logFile_.reset();
80 }
81 }
82
83 // Store the old handler to restore it later.
84 oldHandler_ = qInstallMessageHandler(messageHandler);
85 }
86
87 /**
88 * \brief Restores the original message handler and cleans up logging
89 * resources, such as closing the log file.
90 */
92 instance_ = nullptr; // Clear the static instance
93 qInstallMessageHandler(oldHandler_);
94 if (logFile_) {
95 logFile_->close();
96 }
97#ifdef Q_OS_UNIX
98 if (!args_.debug_syslog_.empty()) {
99 closelog();
100 }
101#endif
102 }
103
104 // Make Logger non-copyable and non-movable to prevent issues with
105 // handler installation.
106 Logger(const Logger&) = delete;
107 Logger& operator=(const Logger&) = delete;
108 Logger(Logger&&) = delete;
109 Logger& operator=(Logger&&) = delete;
110
111 private:
112 /**
113 * \brief The static Qt message handler that intercepts all log
114 * messages.
115 *
116 * This function filters messages based on the current log level and
117 * routes them to the configured outputs (console, file, syslog).
118 *
119 * \param type The level of the message (e.g., QtDebugMsg).
120 * \param context The context where the message was generated.
121 * \param msg The log message.
122 */
123 static void messageHandler(QtMsgType type,
124 const QMessageLogContext& context,
125 const QString& msg) {
126 if (!instance_ || !instance_->activeLevels_.contains(type)) {
127 return;
128 }
129
130 const QString prefix =
131 instance_->levelPrefixes_.value(type, "[unknown]");
132 const QString formattedMsg = QString("%1 %2").arg(prefix, msg);
133
135 std::cout << formattedMsg.toStdString() << "\n";
136 }
137
138#ifdef Q_OS_UNIX
139 if (!instance_->args_.debug_syslog_.empty()) {
140 syslog(LOG_INFO, "%s", formattedMsg.toStdString().c_str());
141 }
142#endif
143
144 if (instance_->logStream_) {
145 *instance_->logStream_ << formattedMsg << "\n";
146 }
147 }
148
149 /// \brief Singleton instance of the logger.
150 inline static Logger* instance_ = nullptr;
151
152 /// \brief A reference to the parsed command-line arguments.
154
155 /// \brief The set of Qt message types to be logged.
156 QSet<QtMsgType> activeLevels_;
157
158 /**
159 * \brief A map from message type to its string prefix (e.g.,
160 * “[debug]”).
161 */
162 QHash<QtMsgType, QString> levelPrefixes_;
163
164 /// \brief A smart pointer to the log file.
165 std::unique_ptr<QFile> logFile_;
166
167 /**
168 * \brief A smart pointer to the text stream for writing to the log
169 * file.
170 */
171 std::unique_ptr<QTextStream> logStream_;
172
173 /**
174 * \brief Stores the original Qt message handler to be restored on
175 * exit.
176 */
177 QtMessageHandler oldHandler_ = nullptr;
178 };
179
180} // namespace AppUtils
181
182#endif // LOGGER_HPP
Manages application logging based on command-line arguments.
Definition: logger.hpp:36
std::unique_ptr< QTextStream > logStream_
A smart pointer to the text stream for writing to the log file.
Definition: logger.hpp:171
std::unique_ptr< QFile > logFile_
A smart pointer to the log file.
Definition: logger.hpp:165
QtMessageHandler oldHandler_
Stores the original Qt message handler to be restored on exit.
Definition: logger.hpp:177
QHash< QtMsgType, QString > levelPrefixes_
A map from message type to its string prefix (e.g., “[debug]”).
Definition: logger.hpp:162
static Logger * instance_
Singleton instance of the logger.
Definition: logger.hpp:150
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
The static Qt message handler that intercepts all log messages.
Definition: logger.hpp:123
QSet< QtMsgType > activeLevels_
The set of Qt message types to be logged.
Definition: logger.hpp:156
const CmdLine::CmdLineArgs & args_
A reference to the parsed command-line arguments.
Definition: logger.hpp:153
~Logger()
Restores the original message handler and cleans up logging resources, such as closing the log file.
Definition: logger.hpp:91
Logger(const CmdLine::CmdLineArgs &in_args)
Initialises the logger and installs the custom message handler.
Definition: logger.hpp:44
Command-line argument parsing and validation.
Namespace for application-wide utility functions, primarily for exception handling.
Holds and parses command-line arguments.
bool debug_console_
Flag to enable diagnostic output.
std::string debug_syslog_
Identifier for syslog logging.
LogLevel log_level_
Log level filter.
std::string debug_file_
File path for logging.