| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |  @file | 
					
						
							|  |  |  |  @author Stefan Frings | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "filelogger.h"
 | 
					
						
							|  |  |  | #include <QTime>
 | 
					
						
							|  |  |  | #include <QStringList>
 | 
					
						
							|  |  |  | #include <QThread>
 | 
					
						
							|  |  |  | #include <QtGlobal>
 | 
					
						
							|  |  |  | #include <QFile>
 | 
					
						
							|  |  |  | #include <QTimerEvent>
 | 
					
						
							|  |  |  | #include <QDir>
 | 
					
						
							|  |  |  | #include <QFileInfo>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace qtwebapp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FileLogger::refreshSettings() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     mutex.lock(); | 
					
						
							| 
									
										
										
										
											2017-11-11 22:27:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (useQtSettings) { | 
					
						
							|  |  |  |         refreshQtSettings(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         refreshFileLogSettings(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mutex.unlock(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FileLogger::refreshQtSettings() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-22 23:14:23 +02:00
										 |  |  |     // Save old file name for later comparison with new settings
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     QString oldFileName = fileName; | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Load new config settings
 | 
					
						
							|  |  |  |     settings->sync(); | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     fileName = settings->value("fileName").toString(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     // Convert relative fileName to absolute, based on the directory of the config file.
 | 
					
						
							|  |  |  | #ifdef Q_OS_WIN32
 | 
					
						
							|  |  |  |     if (QDir::isRelativePath(fileName) && settings->format()!=QSettings::NativeFormat) | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     if (QDir::isRelativePath(fileName)) | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QFileInfo configFile(settings->fileName()); | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |         fileName = QFileInfo(configFile.absolutePath(), fileName).absoluteFilePath(); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     maxSize = settings->value("maxSize", 0).toLongLong(); | 
					
						
							|  |  |  |     maxBackups = settings->value("maxBackups", 0).toInt(); | 
					
						
							|  |  |  |     msgFormat = settings->value("msgFormat", "{timestamp} {type} {msg}").toString(); | 
					
						
							| 
									
										
										
										
											2018-05-11 11:00:08 +02:00
										 |  |  |     timestampFormat = settings->value("timestampFormat", "yyyy-MM-dd HH:mm:ss.zzz").toString(); | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     minLevel = static_cast<QtMsgType>(settings->value("minLevel", 0).toInt()); | 
					
						
							|  |  |  |     bufferSize = settings->value("bufferSize", 0).toInt(); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Create new file if the filename has been changed
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     if (oldFileName != fileName) | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |         fprintf(stderr, "FileLogger::refreshQtSettings: Logging to %s\n", qPrintable(fileName)); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |         close(); | 
					
						
							|  |  |  |         open(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 22:27:02 +01:00
										 |  |  | void FileLogger::refreshFileLogSettings() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-22 23:14:23 +02:00
										 |  |  |     // Save old file name for later comparison with new settings
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     QString oldFileName = fileName; | 
					
						
							| 
									
										
										
										
											2017-11-11 22:27:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Load new config settings
 | 
					
						
							|  |  |  |     fileName = fileLoggerSettings.fileName; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Convert relative fileName to absolute, based on the current working directory
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     if (QDir::isRelativePath(fileName)) { | 
					
						
							| 
									
										
										
										
											2017-11-11 22:27:02 +01:00
										 |  |  |         fileName = QFileInfo(QDir::currentPath(), fileName).absoluteFilePath(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     maxSize = fileLoggerSettings.maxSize; | 
					
						
							|  |  |  |     maxBackups = fileLoggerSettings.maxBackups; | 
					
						
							|  |  |  |     msgFormat = fileLoggerSettings.msgFormat; | 
					
						
							|  |  |  |     timestampFormat = fileLoggerSettings.timestampFormat; | 
					
						
							|  |  |  |     minLevel = fileLoggerSettings.minLevel; | 
					
						
							|  |  |  |     bufferSize = fileLoggerSettings.bufferSize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create new file if the filename has been changed
 | 
					
						
							|  |  |  |     if (oldFileName != fileName) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |         fprintf(stderr, "FileLogger::refreshQtSettings: Logging to new file %s\n", qPrintable(fileName)); | 
					
						
							| 
									
										
										
										
											2017-11-11 22:27:02 +01:00
										 |  |  |         close(); | 
					
						
							|  |  |  |         open(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  | FileLogger::FileLogger(QSettings* settings, const int refreshInterval, QObject* parent) : | 
					
						
							|  |  |  |         Logger(parent), fileName(""), useQtSettings(true) | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     Q_ASSERT(settings != 0); | 
					
						
							|  |  |  |     Q_ASSERT(refreshInterval >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this->settings = settings; | 
					
						
							|  |  |  |     file = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (refreshInterval > 0) { | 
					
						
							|  |  |  |         refreshTimer.start(refreshInterval, this); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     flushTimer.start(1000, this); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     refreshSettings(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  | FileLogger::FileLogger(const FileLoggerSettings& settings, const int refreshInterval, QObject* parent) : | 
					
						
							|  |  |  |         Logger(parent), fileName(""), useQtSettings(false) | 
					
						
							| 
									
										
										
										
											2017-11-11 22:27:02 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     Q_ASSERT(refreshInterval >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 22:27:02 +01:00
										 |  |  |     fileLoggerSettings = settings; | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     file = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (refreshInterval > 0) { | 
					
						
							|  |  |  |         refreshTimer.start(refreshInterval, this); | 
					
						
							| 
									
										
										
										
											2017-11-11 22:27:02 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     flushTimer.start(1000, this); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 22:27:02 +01:00
										 |  |  |     refreshSettings(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  | FileLogger::~FileLogger() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     close(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FileLogger::write(const LogMessage* logMessage) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Try to write to the file
 | 
					
						
							|  |  |  |     if (file) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Write the message
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |         file->write(qPrintable(logMessage->toString(msgFormat, timestampFormat))); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Flush error messages immediately, to ensure that no important message
 | 
					
						
							|  |  |  |         // gets lost when the program terinates abnormally.
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |         if (logMessage->getType() >= QtCriticalMsg) { | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |             file->flush(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Check for success
 | 
					
						
							|  |  |  |         if (file->error()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             close(); | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |             fprintf(stderr, "FileLogger::write: Cannot write to log file %s: %s\n", qPrintable(fileName), qPrintable(file->errorString())); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Fall-back to the super class method, if writing failed
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     if (!file && useQtSettings) { | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |         Logger::write(logMessage); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FileLogger::open() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (fileName.isEmpty()) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |         fprintf(stderr, "FileLogger::open: Name of logFile is empty\n"); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         file = new QFile(fileName); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |         if (!file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |             fprintf(stderr, "FileLogger::open: Cannot open log file %s: %s\n", qPrintable(fileName), qPrintable(file->errorString())); | 
					
						
							|  |  |  |             file = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             fprintf(stderr, "FileLogger::open: Opened log file %s\n", qPrintable(fileName)); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FileLogger::close() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (file) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         file->close(); | 
					
						
							|  |  |  |         delete file; | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |         file = 0; | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  | void FileLogger::rotate() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     fprintf(stderr, "FileLogger::rotate\n"); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     // count current number of existing backup files
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     int count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     forever | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |         QFile bakFile(QString("%1.%2").arg(fileName).arg(count + 1)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (bakFile.exists()) { | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |             ++count; | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Remove all old backup files that exceed the maximum number
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     while (maxBackups > 0 && count >= maxBackups) | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         QFile::remove(QString("%1.%2").arg(fileName).arg(count)); | 
					
						
							|  |  |  |         --count; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Rotate backup files
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     for (int i = count; i > 0; --i) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QFile::rename(QString("%1.%2").arg(fileName).arg(i), QString("%1.%2").arg(fileName).arg(i + 1)); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Backup the current logfile
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     QFile::rename(fileName, fileName + ".1"); | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FileLogger::timerEvent(QTimerEvent* event) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     if (!event) { | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     } else if (event->timerId() == refreshTimer.timerId()) { | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |         refreshSettings(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |     else if (event->timerId() == flushTimer.timerId() && file) | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         mutex.lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Flush the I/O buffer
 | 
					
						
							|  |  |  |         file->flush(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Rotate the file if it is too large
 | 
					
						
							| 
									
										
										
										
											2017-11-12 02:23:55 +01:00
										 |  |  |         if (maxSize > 0 && file->size() >= maxSize) | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |         { | 
					
						
							|  |  |  |             close(); | 
					
						
							|  |  |  |             rotate(); | 
					
						
							|  |  |  |             open(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mutex.unlock(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |