Updated loggin component of QtWebApp to version 1.6.5

This commit is contained in:
Luis Ángel San Martín 2016-06-16 22:16:01 +02:00
parent e6d229680f
commit 1657111621
9 changed files with 162 additions and 91 deletions

View File

@ -13,8 +13,14 @@ DualFileLogger::DualFileLogger(QSettings* firstSettings, QSettings* secondSettin
secondLogger=new FileLogger(secondSettings, refreshInterval, this); secondLogger=new FileLogger(secondSettings, refreshInterval, this);
} }
void DualFileLogger::log(const QtMsgType type, const QString& message, const QString &file, const QString &function, const int line)
void DualFileLogger::log(const QtMsgType type, const QString& message) { {
firstLogger->log(type, message); firstLogger->log(type,message,file,function,line);
secondLogger->log(type, message); secondLogger->log(type,message,file,function,line);
}
void DualFileLogger::clear(const bool buffer, const bool variables)
{
firstLogger->clear(buffer,variables);
secondLogger->clear(buffer,variables);
} }

View File

@ -6,11 +6,12 @@
#ifndef DUALFILELOGGER_H #ifndef DUALFILELOGGER_H
#define DUALFILELOGGER_H #define DUALFILELOGGER_H
#include "logger.h"
#include "filelogger.h"
#include <QString> #include <QString>
#include <QSettings> #include <QSettings>
#include <QtGlobal> #include <QtGlobal>
#include "logglobal.h"
#include "logger.h"
#include "filelogger.h"
/** /**
Logs messages into two log files simultaneously. Logs messages into two log files simultaneously.
@ -18,7 +19,7 @@
@see FileLogger for a description of the two underlying loggers. @see FileLogger for a description of the two underlying loggers.
*/ */
class DualFileLogger : public Logger { class DECLSPEC DualFileLogger : public Logger {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(DualFileLogger) Q_DISABLE_COPY(DualFileLogger)
public: public:
@ -37,13 +38,24 @@ public:
DualFileLogger(QSettings* firstSettings, QSettings* secondSettings, const int refreshInterval=10000, QObject *parent = 0); DualFileLogger(QSettings* firstSettings, QSettings* secondSettings, const int refreshInterval=10000, QObject *parent = 0);
/** /**
Decorate and log a message. Decorate and log the message, if type>=minLevel.
This method is thread safe. This method is thread safe.
@param type Message type (level) @param type Message type (level)
@param message Message text @param message Message text
@param file Name of the source file where the message was generated (usually filled with the macro __FILE__)
@param function Name of the function where the message was generated (usually filled with the macro __LINE__)
@param line Line Number of the source file, where the message was generated (usually filles with the macro __func__ or __FUNCTION__)
@see LogMessage for a description of the message decoration. @see LogMessage for a description of the message decoration.
*/ */
virtual void log(const QtMsgType type, const QString& message); virtual void log(const QtMsgType type, const QString& message, const QString &file="", const QString &function="", const int line=0);
/**
Clear the thread-local data of the current thread.
This method is thread safe.
@param buffer Whether to clear the backtrace buffer
@param variables Whether to clear the log variables
*/
virtual void clear(const bool buffer=true, const bool variables=true);
private: private:

View File

@ -15,7 +15,8 @@
#include <stdio.h> #include <stdio.h>
#include "yacreader_global.h" #include "yacreader_global.h"
void FileLogger::refreshSettings() { void FileLogger::refreshSettings()
{
mutex.lock(); mutex.lock();
// Save old file name for later comparision with new settings // Save old file name for later comparision with new settings
QString oldFileName=fileName; QString oldFileName=fileName;
@ -41,7 +42,8 @@ void FileLogger::refreshSettings() {
bufferSize=settings->value("bufferSize",0).toInt(); bufferSize=settings->value("bufferSize",0).toInt();
// Create new file if the filename has been changed // Create new file if the filename has been changed
if (oldFileName!=fileName) { if (oldFileName!=fileName)
{
fprintf(stderr,"Logging to %s\n",qPrintable(fileName)); fprintf(stderr,"Logging to %s\n",qPrintable(fileName));
close(); close();
open(); open();
@ -57,7 +59,8 @@ FileLogger::FileLogger(QSettings* settings, const int refreshInterval, QObject*
Q_ASSERT(refreshInterval>=0); Q_ASSERT(refreshInterval>=0);
this->settings=settings; this->settings=settings;
file=0; file=0;
if (refreshInterval>0) { if (refreshInterval>0)
{
refreshTimer.start(refreshInterval,this); refreshTimer.start(refreshInterval,this);
} }
flushTimer.start(1000,this); flushTimer.start(1000,this);
@ -65,26 +68,31 @@ FileLogger::FileLogger(QSettings* settings, const int refreshInterval, QObject*
} }
FileLogger::~FileLogger() { FileLogger::~FileLogger()
{
close(); close();
} }
void FileLogger::write(const LogMessage* logMessage) { void FileLogger::write(const LogMessage* logMessage)
{
// Try to write to the file // Try to write to the file
if (file) { if (file)
{
// Write the message // Write the message
file->write(qPrintable(logMessage->toString(msgFormat,timestampFormat))); file->write(qPrintable(logMessage->toString(msgFormat,timestampFormat)));
// Flush error messages immediately, to ensure that no important message // Flush error messages immediately, to ensure that no important message
// gets lost when the program terinates abnormally. // gets lost when the program terinates abnormally.
if (logMessage->getType()>=QtCriticalMsg) { if (logMessage->getType()>=QtCriticalMsg)
{
file->flush(); file->flush();
} }
// Check for success // Check for success
if (file->error()) { if (file->error())
{
close(); close();
qWarning("Cannot write to log file %s: %s",qPrintable(fileName),qPrintable(file->errorString())); qWarning("Cannot write to log file %s: %s",qPrintable(fileName),qPrintable(file->errorString()));
} }
@ -92,19 +100,23 @@ void FileLogger::write(const LogMessage* logMessage) {
} }
// Fall-back to the super class method, if writing failed // Fall-back to the super class method, if writing failed
if (!file) { if (!file)
{
Logger::write(logMessage); Logger::write(logMessage);
} }
} }
void FileLogger::open() { void FileLogger::open()
if (fileName.isEmpty()) { {
if (fileName.isEmpty())
{
qWarning("Name of logFile is empty"); qWarning("Name of logFile is empty");
} }
else { else {
file=new QFile(fileName); file=new QFile(fileName);
if (!file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { if (!file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
{
qWarning("Cannot open log file %s: %s",qPrintable(fileName),qPrintable(file->errorString())); qWarning("Cannot open log file %s: %s",qPrintable(fileName),qPrintable(file->errorString()));
file=0; file=0;
} }
@ -112,8 +124,10 @@ void FileLogger::open() {
} }
void FileLogger::close() { void FileLogger::close()
if (file) { {
if (file)
{
file->close(); file->close();
delete file; delete file;
file=0; file=0;
@ -123,18 +137,22 @@ void FileLogger::close() {
void FileLogger::rotate() { void FileLogger::rotate() {
// count current number of existing backup files // count current number of existing backup files
int count=0; int count=0;
forever { forever
{
QFile bakFile(QString("%1.%2").arg(fileName).arg(count+1)); QFile bakFile(QString("%1.%2").arg(fileName).arg(count+1));
if (bakFile.exists()) { if (bakFile.exists())
{
++count; ++count;
} }
else { else
{
break; break;
} }
} }
// Remove all old backup files that exceed the maximum number // Remove all old backup files that exceed the maximum number
while (maxBackups>0 && count>=maxBackups) { while (maxBackups>0 && count>=maxBackups)
{
QFile::remove(QString("%1.%2").arg(fileName).arg(count)); QFile::remove(QString("%1.%2").arg(fileName).arg(count));
--count; --count;
} }
@ -149,21 +167,26 @@ void FileLogger::rotate() {
} }
void FileLogger::timerEvent(QTimerEvent* event) { void FileLogger::timerEvent(QTimerEvent* event)
if (!event) { {
if (!event)
{
return; return;
} }
else if (event->timerId()==refreshTimer.timerId()) { else if (event->timerId()==refreshTimer.timerId())
{
refreshSettings(); refreshSettings();
} }
else if (event->timerId()==flushTimer.timerId() && file) { else if (event->timerId()==flushTimer.timerId() && file)
{
mutex.lock(); mutex.lock();
// Flush the I/O buffer // Flush the I/O buffer
file->flush(); file->flush();
// Rotate the file if it is too large // Rotate the file if it is too large
if (maxSize>0 && file->size()>=maxSize) { if (maxSize>0 && file->size()>=maxSize)
{
close(); close();
rotate(); rotate();
open(); open();

View File

@ -11,6 +11,7 @@
#include <QFile> #include <QFile>
#include <QMutex> #include <QMutex>
#include <QBasicTimer> #include <QBasicTimer>
#include "logglobal.h"
#include "logger.h" #include "logger.h"
/** /**
@ -45,7 +46,7 @@
@see Logger for a descrition of the buffer. @see Logger for a descrition of the buffer.
*/ */
class FileLogger : public Logger { class DECLSPEC FileLogger : public Logger {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(FileLogger) Q_DISABLE_COPY(FileLogger)
public: public:

View File

@ -9,6 +9,7 @@
#include <QMutex> #include <QMutex>
#include <QDateTime> #include <QDateTime>
#include <QThread> #include <QThread>
#include <QObject>
Logger* Logger::defaultLogger=0; Logger* Logger::defaultLogger=0;
@ -16,9 +17,6 @@ Logger* Logger::defaultLogger=0;
QThreadStorage<QHash<QString,QString>*> Logger::logVars; QThreadStorage<QHash<QString,QString>*> Logger::logVars;
QThreadStorage<QList<LogMessage*>*> Logger::buffers;
QMutex Logger::mutex; QMutex Logger::mutex;
@ -32,7 +30,8 @@ Logger::Logger(QObject* parent)
Logger::Logger(const QString msgFormat, const QString timestampFormat, const QtMsgType minLevel, const int bufferSize, QObject* parent) Logger::Logger(const QString msgFormat, const QString timestampFormat, const QtMsgType minLevel, const int bufferSize, QObject* parent)
:QObject(parent) { :QObject(parent)
{
this->msgFormat=msgFormat; this->msgFormat=msgFormat;
this->timestampFormat=timestampFormat; this->timestampFormat=timestampFormat;
this->minLevel=minLevel; this->minLevel=minLevel;
@ -40,7 +39,8 @@ Logger::Logger(const QString msgFormat, const QString timestampFormat, const QtM
} }
void Logger::msgHandler(const QtMsgType type, const QString &message, const QString &file, const QString &function, const int line) { 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 recursiveMutex(QMutex::Recursive);
static QMutex nonRecursiveMutex(QMutex::NonRecursive); static QMutex nonRecursiveMutex(QMutex::NonRecursive);
@ -50,11 +50,13 @@ void Logger::msgHandler(const QtMsgType type, const QString &message, const QStr
recursiveMutex.lock(); recursiveMutex.lock();
// Fall back to stderr when this method has been called recursively. // Fall back to stderr when this method has been called recursively.
if (defaultLogger && nonRecursiveMutex.tryLock()) { if (defaultLogger && nonRecursiveMutex.tryLock())
{
defaultLogger->log(type, message, file, function, line); defaultLogger->log(type, message, file, function, line);
nonRecursiveMutex.unlock(); nonRecursiveMutex.unlock();
} }
else { else
{
fputs(qPrintable(message),stderr); fputs(qPrintable(message),stderr);
fflush(stderr); fflush(stderr);
} }
@ -69,19 +71,23 @@ void Logger::msgHandler(const QtMsgType type, const QString &message, const QStr
#if QT_VERSION >= 0x050000 #if QT_VERSION >= 0x050000
void Logger::msgHandler5(const QtMsgType type, const QMessageLogContext &context, const QString &message) { void Logger::msgHandler5(const QtMsgType type, const QMessageLogContext &context, const QString &message)
{
(void)(context); // suppress "unused parameter" warning (void)(context); // suppress "unused parameter" warning
msgHandler(type,message,context.file,context.function,context.line); msgHandler(type,message,context.file,context.function,context.line);
} }
#else #else
void Logger::msgHandler4(const QtMsgType type, const char* message) { void Logger::msgHandler4(const QtMsgType type, const char* message)
{
msgHandler(type,message); msgHandler(type,message);
} }
#endif #endif
Logger::~Logger() { Logger::~Logger()
if (defaultLogger==this) { {
if (defaultLogger==this)
{
#if QT_VERSION >= 0x050000 #if QT_VERSION >= 0x050000
qInstallMessageHandler(0); qInstallMessageHandler(0);
#else #else
@ -92,13 +98,15 @@ Logger::~Logger() {
} }
void Logger::write(const LogMessage* logMessage) { void Logger::write(const LogMessage* logMessage)
{
fputs(qPrintable(logMessage->toString(msgFormat,timestampFormat)),stderr); fputs(qPrintable(logMessage->toString(msgFormat,timestampFormat)),stderr);
fflush(stderr); fflush(stderr);
} }
void Logger::installMsgHandler() { void Logger::installMsgHandler()
{
defaultLogger=this; defaultLogger=this;
#if QT_VERSION >= 0x050000 #if QT_VERSION >= 0x050000
qInstallMessageHandler(msgHandler5); qInstallMessageHandler(msgHandler5);
@ -108,9 +116,11 @@ void Logger::installMsgHandler() {
} }
void Logger::set(const QString& name, const QString& value) { void Logger::set(const QString& name, const QString& value)
{
mutex.lock(); mutex.lock();
if (!logVars.hasLocalData()) { if (!logVars.hasLocalData())
{
logVars.setLocalData(new QHash<QString,QString>); logVars.setLocalData(new QHash<QString,QString>);
} }
logVars.localData()->insert(name,value); logVars.localData()->insert(name,value);
@ -118,23 +128,27 @@ void Logger::set(const QString& name, const QString& value) {
} }
void Logger::clear(const bool buffer, const bool variables) { void Logger::clear(const bool buffer, const bool variables)
{
mutex.lock(); mutex.lock();
if (buffer && buffers.hasLocalData()) { if (buffer && buffers.hasLocalData())
{
QList<LogMessage*>* buffer=buffers.localData(); QList<LogMessage*>* buffer=buffers.localData();
while (buffer && !buffer->isEmpty()) { while (buffer && !buffer->isEmpty()) {
LogMessage* logMessage=buffer->takeLast(); LogMessage* logMessage=buffer->takeLast();
delete logMessage; delete logMessage;
} }
} }
if (variables && logVars.hasLocalData()) { if (variables && logVars.hasLocalData())
{
logVars.localData()->clear(); logVars.localData()->clear();
} }
mutex.unlock(); mutex.unlock();
} }
void Logger::log(const QtMsgType type, const QString& message, const QString &file, const QString &function, const int line) { void Logger::log(const QtMsgType type, const QString& message, const QString &file, const QString &function, const int line)
{
mutex.lock(); mutex.lock();
// If the buffer is enabled, write the message into it // If the buffer is enabled, write the message into it
@ -148,12 +162,14 @@ void Logger::log(const QtMsgType type, const QString& message, const QString &fi
LogMessage* logMessage=new LogMessage(type,message,logVars.localData(),file,function,line); LogMessage* logMessage=new LogMessage(type,message,logVars.localData(),file,function,line);
buffer->append(logMessage); buffer->append(logMessage);
// Delete oldest message if the buffer became too large // Delete oldest message if the buffer became too large
if (buffer->size()>bufferSize) { if (buffer->size()>bufferSize)
{
delete buffer->takeFirst(); delete buffer->takeFirst();
} }
// If the type of the message is high enough, print the whole buffer // If the type of the message is high enough, print the whole buffer
if (type>=minLevel) { if (type>=minLevel) {
while (!buffer->isEmpty()) { while (!buffer->isEmpty())
{
LogMessage* logMessage=buffer->takeFirst(); LogMessage* logMessage=buffer->takeFirst();
write(logMessage); write(logMessage);
delete logMessage; delete logMessage;
@ -163,7 +179,8 @@ void Logger::log(const QtMsgType type, const QString& message, const QString &fi
// Buffer is disabled, print the message if the type is high enough // Buffer is disabled, print the message if the type is high enough
else { else {
if (type>=minLevel) { if (type>=minLevel)
{
LogMessage logMessage(type,message,logVars.localData(),file,function,line); LogMessage logMessage(type,message,logVars.localData(),file,function,line);
write(&logMessage); write(&logMessage);
} }

View File

@ -6,13 +6,13 @@
#ifndef LOGGER_H #ifndef LOGGER_H
#define LOGGER_H #define LOGGER_H
#include <QObject>
#include <QtGlobal> #include <QtGlobal>
#include <QThreadStorage> #include <QThreadStorage>
#include <QHash> #include <QHash>
#include <QStringList> #include <QStringList>
#include <QMutex> #include <QMutex>
#include <QObject>
#include "logglobal.h"
#include "logmessage.h" #include "logmessage.h"
/** /**
@ -45,7 +45,7 @@
because logging to the console is less useful. because logging to the console is less useful.
*/ */
class Logger : public QObject { class DECLSPEC Logger : public QObject {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(Logger) Q_DISABLE_COPY(Logger)
public: public:
@ -100,10 +100,11 @@ public:
/** /**
Clear the thread-local data of the current thread. Clear the thread-local data of the current thread.
This method is thread safe.
@param buffer Whether to clear the backtrace buffer @param buffer Whether to clear the backtrace buffer
@param variables Whether to clear the log variables @param variables Whether to clear the log variables
*/ */
static void clear(const bool buffer=true, const bool variables=true); virtual void clear(const bool buffer=true, const bool variables=true);
protected: protected:
@ -119,7 +120,7 @@ protected:
/** Size of backtrace buffer, number of messages per thread. 0=disabled */ /** Size of backtrace buffer, number of messages per thread. 0=disabled */
int bufferSize; int bufferSize;
/** Used to synchronize access to the static members */ /** Used to synchronize access of concurrent threads */
static QMutex mutex; static QMutex mutex;
/** /**
@ -176,7 +177,7 @@ private:
static QThreadStorage<QHash<QString,QString>*> logVars; static QThreadStorage<QHash<QString,QString>*> logVars;
/** Thread local backtrace buffers */ /** Thread local backtrace buffers */
static QThreadStorage<QList<LogMessage*>*> buffers; QThreadStorage<QList<LogMessage*>*> buffers;
}; };

View File

@ -1,5 +1,6 @@
INCLUDEPATH += $$PWD INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD DEPENDPATH += $$PWD
HEADERS += $$PWD/logmessage.h $$PWD/logger.h $$PWD/filelogger.h $$PWD/dualfilelogger.h HEADERS += $$PWD/logglobal.h $$PWD/logmessage.h $$PWD/logger.h $$PWD/filelogger.h $$PWD/dualfilelogger.h
SOURCES += $$PWD/logmessage.cpp $$PWD/logger.cpp $$PWD/filelogger.cpp $$PWD/dualfilelogger.cpp
SOURCES += $$PWD/logmessage.cpp $$PWD/logger.cpp $$PWD/filelogger.cpp $$PWD/dualfilelogger.cpp

View File

@ -6,7 +6,8 @@
#include "logmessage.h" #include "logmessage.h"
#include <QThread> #include <QThread>
LogMessage::LogMessage(const QtMsgType type, const QString& message, QHash<QString, QString>* logVars, const QString &file, const QString &function, const int line) { LogMessage::LogMessage(const QtMsgType type, const QString& message, QHash<QString, QString>* logVars, const QString &file, const QString &function, const int line)
{
this->type=type; this->type=type;
this->message=message; this->message=message;
this->file=file; this->file=file;
@ -17,16 +18,19 @@ LogMessage::LogMessage(const QtMsgType type, const QString& message, QHash<QStri
// Copy the logVars if not null, // Copy the logVars if not null,
// so that later changes in the original do not affect the copy // so that later changes in the original do not affect the copy
if (logVars) { if (logVars)
{
this->logVars=*logVars; this->logVars=*logVars;
} }
} }
QString LogMessage::toString(const QString& msgFormat, const QString& timestampFormat) const { QString LogMessage::toString(const QString& msgFormat, const QString& timestampFormat) const
{
QString decorated=msgFormat+"\n"; QString decorated=msgFormat+"\n";
decorated.replace("{msg}",message); decorated.replace("{msg}",message);
if (decorated.contains("{timestamp}")) { if (decorated.contains("{timestamp}"))
{
decorated.replace("{timestamp}",timestamp.toString(timestampFormat)); decorated.replace("{timestamp}",timestamp.toString(timestampFormat));
} }
@ -34,21 +38,22 @@ QString LogMessage::toString(const QString& msgFormat, const QString& timestampF
typeNr.setNum(type); typeNr.setNum(type);
decorated.replace("{typeNr}",typeNr); decorated.replace("{typeNr}",typeNr);
switch (type) { switch (type)
case QtDebugMsg: {
decorated.replace("{type}","DEBUG"); case QtDebugMsg:
break; decorated.replace("{type}","DEBUG");
case QtWarningMsg: break;
decorated.replace("{type}","WARNING"); case QtWarningMsg:
break; decorated.replace("{type}","WARNING");
case QtCriticalMsg: break;
decorated.replace("{type}","CRITICAL"); case QtCriticalMsg:
break; decorated.replace("{type}","CRITICAL");
case QtFatalMsg: break;
decorated.replace("{type}","FATAL"); case QtFatalMsg:
break; decorated.replace("{type}","FATAL");
default: break;
decorated.replace("{type}",typeNr); default:
decorated.replace("{type}",typeNr);
} }
decorated.replace("{file}",file); decorated.replace("{file}",file);
@ -60,9 +65,11 @@ QString LogMessage::toString(const QString& msgFormat, const QString& timestampF
decorated.replace("{thread}",threadId); decorated.replace("{thread}",threadId);
// Fill in variables // Fill in variables
if (decorated.contains("{") && !logVars.isEmpty()) { if (decorated.contains("{") && !logVars.isEmpty())
{
QList<QString> keys=logVars.keys(); QList<QString> keys=logVars.keys();
foreach (QString key, keys) { foreach (QString key, keys)
{
decorated.replace("{"+key+"}",logVars.value(key)); decorated.replace("{"+key+"}",logVars.value(key));
} }
} }
@ -70,6 +77,7 @@ QString LogMessage::toString(const QString& msgFormat, const QString& timestampF
return decorated; return decorated;
} }
QtMsgType LogMessage::getType() const { QtMsgType LogMessage::getType() const
{
return type; return type;
} }

View File

@ -9,6 +9,7 @@
#include <QtGlobal> #include <QtGlobal>
#include <QDateTime> #include <QDateTime>
#include <QHash> #include <QHash>
#include "logglobal.h"
/** /**
Represents a single log message together with some data Represents a single log message together with some data
@ -20,16 +21,17 @@
- {typeNr} Type of the message in numeric format (0-3) - {typeNr} Type of the message in numeric format (0-3)
- {type} Type of the message in string format (DEBUG, WARNING, CRITICAL, FATAL) - {type} Type of the message in string format (DEBUG, WARNING, CRITICAL, FATAL)
- {thread} ID number of the thread - {thread} ID number of the thread
- {msg} Message text (only useable in msgFormat) - {msg} Message text
- {file} Filename where the message was generated #
- {function} Function where the message was generated #
- {line} Line number where the message was generated #
- {xxx} For any user-defined logger variable - {xxx} For any user-defined logger variable
# The macros qDebug()...qFatal() dont fill these variable in case of QT versions before 5.0. Plus some new variables since QT 5.0, only filled when compiled in debug mode:
- {file} Filename where the message was generated
- {function} Function where the message was generated
- {line} Line number where the message was generated
*/ */
class LogMessage class DECLSPEC LogMessage
{ {
Q_DISABLE_COPY(LogMessage) Q_DISABLE_COPY(LogMessage)
public: public: