Basic logging system - problems
-
I wrote a basic thread-safe logging system using a namespace:
Logger.h
#ifndef LOGGER_H #define LOGGER_H #include <QMutex> #include <QDateTime> #include <QFile> #include <QString> #include <QDir> namespace Logger { enum LogLevel {INFO, WARNING, ERROR, FATAL}; // Function declarations bool init(const QDir& baseLogDir); void log(LogLevel level, const QString& message); void info(const QString& message); void warning(const QString& message); void error(const QString& message); void fatal(const QString& message); void closeLogFile(); // Helper functions declaration QString formatLogEntry(LogLevel level, const QString& message); QString levelToString(LogLevel level); // Static members static QMutex mutex; static QFile logFile; static bool logInitialized; } // namespace Logger #endif // LOGGER_H
Logger.cpp
#include "Logger.h" #include <QDateTime> #include <QFile> #include <QTextStream> namespace Logger { QMutex mutex; QFile logFile; bool logInitialized = false; QString levelToString(LogLevel level) { static const QMap<LogLevel, QString> levelMap { {INFO, "INFO"}, {WARNING, "WARNING"}, {ERROR, "ERROR"}, {FATAL, "FATAL"} }; return levelMap.value(level, "UNKNOW"); } QString formatLogEntry(LogLevel level, const QString& message) { QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); return QString("%1 [%2] %3").arg(timestamp).arg(levelToString(level)).arg(message); } bool init(const QDir& baseLogDir) { QMutexLocker locker(&mutex); // Create the daily log directory if it doesn't exist if (!baseLogDir.exists()) { if (!baseLogDir.mkpath(baseLogDir.absolutePath())) { qWarning() << "Failed to create base log directory:" << baseLogDir.path(); return false; } } // Construct the full path to the daily log directory QString logFolderPath = baseLogDir.filePath(QDate::currentDate().toString("yyyy-MM-dd")); QDir logDirectory(logFolderPath); // Create the daily log directory if it does't exist if (!logDirectory.exists()) { if (!logDirectory.mkdir(".")) { qWarning() << "Failed to create daily log directory:" << logDirectory.path(); } } // Get the current date and time // Get the current date and time and format it as "yyyy-MM-dd_hh-mm-ss.log" QString logFileName = QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") + ".log"; QString logFilePath = logDirectory.filePath(logFileName); if (logFile.isOpen()) { logFile.close(); } // Open the new log file logFile.setFileName(logFilePath); if (!logFile.open(QIODevice::WriteOnly | QIODevice::Append)) { qWarning() << "Failed to open log file: " << logFilePath; return false; } logInitialized = true; return true; } void log(LogLevel level, const QString& message) { QMutexLocker locker(&mutex); if (logInitialized && logFile.isOpen()) { QTextStream out(&logFile); out << formatLogEntry(level, message) << Qt::endl << Qt::flush; } } void info(const QString& message) { log(INFO, message); } void warning(const QString& message) { log(WARNING, message); } void error(const QString& message) { log(ERROR, message); } void fatal(const QString& message) { log(FATAL, message); } void closeLogFile() { QMutexLocker locker(&mutex); if (logFile.isOpen()) { logFile.close(); } } } // namespace Logger
I am having problems in initializing the static variables in the cpp file and also when I include Logger.h in any file, I get linker errors saying that there are linker conflicts even it there is not the same routine.
What am i doing wrong? -
I wrote a basic thread-safe logging system using a namespace:
Logger.h
#ifndef LOGGER_H #define LOGGER_H #include <QMutex> #include <QDateTime> #include <QFile> #include <QString> #include <QDir> namespace Logger { enum LogLevel {INFO, WARNING, ERROR, FATAL}; // Function declarations bool init(const QDir& baseLogDir); void log(LogLevel level, const QString& message); void info(const QString& message); void warning(const QString& message); void error(const QString& message); void fatal(const QString& message); void closeLogFile(); // Helper functions declaration QString formatLogEntry(LogLevel level, const QString& message); QString levelToString(LogLevel level); // Static members static QMutex mutex; static QFile logFile; static bool logInitialized; } // namespace Logger #endif // LOGGER_H
Logger.cpp
#include "Logger.h" #include <QDateTime> #include <QFile> #include <QTextStream> namespace Logger { QMutex mutex; QFile logFile; bool logInitialized = false; QString levelToString(LogLevel level) { static const QMap<LogLevel, QString> levelMap { {INFO, "INFO"}, {WARNING, "WARNING"}, {ERROR, "ERROR"}, {FATAL, "FATAL"} }; return levelMap.value(level, "UNKNOW"); } QString formatLogEntry(LogLevel level, const QString& message) { QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); return QString("%1 [%2] %3").arg(timestamp).arg(levelToString(level)).arg(message); } bool init(const QDir& baseLogDir) { QMutexLocker locker(&mutex); // Create the daily log directory if it doesn't exist if (!baseLogDir.exists()) { if (!baseLogDir.mkpath(baseLogDir.absolutePath())) { qWarning() << "Failed to create base log directory:" << baseLogDir.path(); return false; } } // Construct the full path to the daily log directory QString logFolderPath = baseLogDir.filePath(QDate::currentDate().toString("yyyy-MM-dd")); QDir logDirectory(logFolderPath); // Create the daily log directory if it does't exist if (!logDirectory.exists()) { if (!logDirectory.mkdir(".")) { qWarning() << "Failed to create daily log directory:" << logDirectory.path(); } } // Get the current date and time // Get the current date and time and format it as "yyyy-MM-dd_hh-mm-ss.log" QString logFileName = QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") + ".log"; QString logFilePath = logDirectory.filePath(logFileName); if (logFile.isOpen()) { logFile.close(); } // Open the new log file logFile.setFileName(logFilePath); if (!logFile.open(QIODevice::WriteOnly | QIODevice::Append)) { qWarning() << "Failed to open log file: " << logFilePath; return false; } logInitialized = true; return true; } void log(LogLevel level, const QString& message) { QMutexLocker locker(&mutex); if (logInitialized && logFile.isOpen()) { QTextStream out(&logFile); out << formatLogEntry(level, message) << Qt::endl << Qt::flush; } } void info(const QString& message) { log(INFO, message); } void warning(const QString& message) { log(WARNING, message); } void error(const QString& message) { log(ERROR, message); } void fatal(const QString& message) { log(FATAL, message); } void closeLogFile() { QMutexLocker locker(&mutex); if (logFile.isOpen()) { logFile.close(); } } } // namespace Logger
I am having problems in initializing the static variables in the cpp file and also when I include Logger.h in any file, I get linker errors saying that there are linker conflicts even it there is not the same routine.
What am i doing wrong?@franco-amato said in Basic logging system - problems:
What am i doing wrong?
You're not posting the error messages you get.
You're redefining mutex, LogFile and logInitialized in your cpp file.
I also do not see a reason to have those variables exposed to the code using logger - they should be moved to cpp file. -
static
in the context of namespaces does not mean the same asstatic
inside classes/structs. Your variables are basically kind of global variables. However, thestatic
in front of it makes them local to the compilation unit (i.e. each .cpp file including Logger.h will have their own set of variables). Because you are including Logger.h in Logger.cpp it will have its own set of these variables and then you redeclare them inside Logger.cpp. If those variables should only be accessed from within Logger.cpp, just throw them out of the header file. Otherwise,extern
is most likely the keyword you are looking for instead ofstatic
. But, global variables are usually not a good idea. You could also just change the namespace Logger to the class Logger and make all functions static. Then you'd also get what you are actually trying to do (but you loose being able to pull in the namespace to avoid always having to write Logger::info(...) etc.). -
I wrote a basic thread-safe logging system using a namespace:
Logger.h
#ifndef LOGGER_H #define LOGGER_H #include <QMutex> #include <QDateTime> #include <QFile> #include <QString> #include <QDir> namespace Logger { enum LogLevel {INFO, WARNING, ERROR, FATAL}; // Function declarations bool init(const QDir& baseLogDir); void log(LogLevel level, const QString& message); void info(const QString& message); void warning(const QString& message); void error(const QString& message); void fatal(const QString& message); void closeLogFile(); // Helper functions declaration QString formatLogEntry(LogLevel level, const QString& message); QString levelToString(LogLevel level); // Static members static QMutex mutex; static QFile logFile; static bool logInitialized; } // namespace Logger #endif // LOGGER_H
Logger.cpp
#include "Logger.h" #include <QDateTime> #include <QFile> #include <QTextStream> namespace Logger { QMutex mutex; QFile logFile; bool logInitialized = false; QString levelToString(LogLevel level) { static const QMap<LogLevel, QString> levelMap { {INFO, "INFO"}, {WARNING, "WARNING"}, {ERROR, "ERROR"}, {FATAL, "FATAL"} }; return levelMap.value(level, "UNKNOW"); } QString formatLogEntry(LogLevel level, const QString& message) { QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); return QString("%1 [%2] %3").arg(timestamp).arg(levelToString(level)).arg(message); } bool init(const QDir& baseLogDir) { QMutexLocker locker(&mutex); // Create the daily log directory if it doesn't exist if (!baseLogDir.exists()) { if (!baseLogDir.mkpath(baseLogDir.absolutePath())) { qWarning() << "Failed to create base log directory:" << baseLogDir.path(); return false; } } // Construct the full path to the daily log directory QString logFolderPath = baseLogDir.filePath(QDate::currentDate().toString("yyyy-MM-dd")); QDir logDirectory(logFolderPath); // Create the daily log directory if it does't exist if (!logDirectory.exists()) { if (!logDirectory.mkdir(".")) { qWarning() << "Failed to create daily log directory:" << logDirectory.path(); } } // Get the current date and time // Get the current date and time and format it as "yyyy-MM-dd_hh-mm-ss.log" QString logFileName = QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") + ".log"; QString logFilePath = logDirectory.filePath(logFileName); if (logFile.isOpen()) { logFile.close(); } // Open the new log file logFile.setFileName(logFilePath); if (!logFile.open(QIODevice::WriteOnly | QIODevice::Append)) { qWarning() << "Failed to open log file: " << logFilePath; return false; } logInitialized = true; return true; } void log(LogLevel level, const QString& message) { QMutexLocker locker(&mutex); if (logInitialized && logFile.isOpen()) { QTextStream out(&logFile); out << formatLogEntry(level, message) << Qt::endl << Qt::flush; } } void info(const QString& message) { log(INFO, message); } void warning(const QString& message) { log(WARNING, message); } void error(const QString& message) { log(ERROR, message); } void fatal(const QString& message) { log(FATAL, message); } void closeLogFile() { QMutexLocker locker(&mutex); if (logFile.isOpen()) { logFile.close(); } } } // namespace Logger
I am having problems in initializing the static variables in the cpp file and also when I include Logger.h in any file, I get linker errors saying that there are linker conflicts even it there is not the same routine.
What am i doing wrong?@franco-amato
Just checking you are aware of existing QMessageLogger Class.