| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  | /**
 | 
					
						
							|  |  |  |   @file | 
					
						
							|  |  |  |   @author Stefan Frings | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "logger.h"
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <QMutex>
 | 
					
						
							|  |  |  | #include <QDateTime>
 | 
					
						
							|  |  |  | #include <QThread>
 | 
					
						
							|  |  |  | #include <QObject>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace qtwebapp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Logger* Logger::defaultLogger=0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QThreadStorage<QHash<QString,QString>*> Logger::logVars; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QMutex Logger::mutex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Logger::Logger(QObject* parent) | 
					
						
							|  |  |  |     : QObject(parent), | 
					
						
							|  |  |  |     msgFormat("{timestamp} {type} {msg}"), | 
					
						
							| 
									
										
										
										
											2018-05-11 11:00:08 +02:00
										 |  |  |     timestampFormat("yyyy-MM-dd HH:mm:ss.zzz"), | 
					
						
							| 
									
										
										
										
											2017-11-11 10:29:32 +01:00
										 |  |  |     minLevel(QtDebugMsg), | 
					
						
							|  |  |  |     bufferSize(0) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Logger::Logger(const QString msgFormat, const QString timestampFormat, const QtMsgType minLevel, const int bufferSize, QObject* parent) | 
					
						
							|  |  |  |     :QObject(parent) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     this->msgFormat=msgFormat; | 
					
						
							|  |  |  |     this->timestampFormat=timestampFormat; | 
					
						
							|  |  |  |     this->minLevel=minLevel; | 
					
						
							|  |  |  |     this->bufferSize=bufferSize; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Logger::msgHandler(const QtMsgType type, const QString &message, const QString &file, const QString &function, const int line) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     static QMutex recursiveMutex(QMutex::Recursive); | 
					
						
							|  |  |  |     static QMutex nonRecursiveMutex(QMutex::NonRecursive); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Prevent multiple threads from calling this method simultaneoulsy.
 | 
					
						
							|  |  |  |     // But allow recursive calls, which is required to prevent a deadlock
 | 
					
						
							|  |  |  |     // if the logger itself produces an error message.
 | 
					
						
							|  |  |  |     recursiveMutex.lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Fall back to stderr when this method has been called recursively.
 | 
					
						
							|  |  |  |     if (defaultLogger && nonRecursiveMutex.tryLock()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         defaultLogger->log(type, message, file, function, line); | 
					
						
							|  |  |  |         nonRecursiveMutex.unlock(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         fputs(qPrintable(message),stderr); | 
					
						
							|  |  |  |         fflush(stderr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Abort the program after logging a fatal message
 | 
					
						
							|  |  |  |     if (type==QtFatalMsg) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         abort(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     recursiveMutex.unlock(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if QT_VERSION >= 0x050000
 | 
					
						
							|  |  |  |     void Logger::msgHandler5(const QtMsgType type, const QMessageLogContext &context, const QString &message) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       (void)(context); // suppress "unused parameter" warning
 | 
					
						
							|  |  |  |       msgHandler(type,message,context.file,context.function,context.line); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     void Logger::msgHandler4(const QtMsgType type, const char* message) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         msgHandler(type,message); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Logger::~Logger() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (defaultLogger==this) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | #if QT_VERSION >= 0x050000
 | 
					
						
							|  |  |  |         qInstallMessageHandler(0); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |         qInstallMsgHandler(0); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |         defaultLogger=0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Logger::write(const LogMessage* logMessage) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     fputs(qPrintable(logMessage->toString(msgFormat,timestampFormat)),stderr); | 
					
						
							|  |  |  |     fflush(stderr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Logger::installMsgHandler() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     defaultLogger=this; | 
					
						
							|  |  |  | #if QT_VERSION >= 0x050000
 | 
					
						
							|  |  |  |     qInstallMessageHandler(msgHandler5); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     qInstallMsgHandler(msgHandler4); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Logger::set(const QString& name, const QString& value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     mutex.lock(); | 
					
						
							|  |  |  |     if (!logVars.hasLocalData()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         logVars.setLocalData(new QHash<QString,QString>); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     logVars.localData()->insert(name,value); | 
					
						
							|  |  |  |     mutex.unlock(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Logger::clear(const bool buffer, const bool variables) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     mutex.lock(); | 
					
						
							|  |  |  |     if (buffer && buffers.hasLocalData()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QList<LogMessage*>* buffer=buffers.localData(); | 
					
						
							|  |  |  |         while (buffer && !buffer->isEmpty()) { | 
					
						
							|  |  |  |             LogMessage* logMessage=buffer->takeLast(); | 
					
						
							|  |  |  |             delete logMessage; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (variables && logVars.hasLocalData()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         logVars.localData()->clear(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     mutex.unlock(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Logger::log(const QtMsgType type, const QString& message, const QString &file, const QString &function, const int line) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     mutex.lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // If the buffer is enabled, write the message into it
 | 
					
						
							|  |  |  |     if (bufferSize>0) { | 
					
						
							|  |  |  |         // Create new thread local buffer, if necessary
 | 
					
						
							|  |  |  |         if (!buffers.hasLocalData()) { | 
					
						
							|  |  |  |             buffers.setLocalData(new QList<LogMessage*>()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         QList<LogMessage*>* buffer=buffers.localData(); | 
					
						
							|  |  |  |         // Append the decorated log message
 | 
					
						
							|  |  |  |         LogMessage* logMessage=new LogMessage(type,message,logVars.localData(),file,function,line); | 
					
						
							|  |  |  |         buffer->append(logMessage); | 
					
						
							|  |  |  |         // Delete oldest message if the buffer became too large
 | 
					
						
							|  |  |  |         if (buffer->size()>bufferSize) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             delete buffer->takeFirst(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // If the type of the message is high enough, print the whole buffer
 | 
					
						
							|  |  |  |         if (type>=minLevel) { | 
					
						
							|  |  |  |             while (!buffer->isEmpty()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 LogMessage* logMessage=buffer->takeFirst(); | 
					
						
							|  |  |  |                 write(logMessage); | 
					
						
							|  |  |  |                 delete logMessage; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Buffer is disabled, print the message if the type is high enough
 | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         if (type>=minLevel) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             LogMessage logMessage(type,message,logVars.localData(),file,function,line); | 
					
						
							|  |  |  |             write(&logMessage); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     mutex.unlock(); | 
					
						
							|  |  |  | } |