mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-25 09:18:54 -05:00
Imported Stefan Frings' logging library from QtWebApp and use it in main window
This commit is contained in:
parent
be77fa82a3
commit
5f22045abb
@ -243,6 +243,7 @@ if (BUILD_DEBIAN)
|
|||||||
endif (BUILD_DEBIAN)
|
endif (BUILD_DEBIAN)
|
||||||
|
|
||||||
add_subdirectory(httpserver)
|
add_subdirectory(httpserver)
|
||||||
|
add_subdirectory(logging)
|
||||||
add_subdirectory(devices)
|
add_subdirectory(devices)
|
||||||
add_subdirectory(plugins)
|
add_subdirectory(plugins)
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ This is the httpserver part of QtWebApp from Stefan Frings
|
|||||||
|
|
||||||
- [Link to the main page](http://stefanfrings.de/qtwebapp/index-en.html)
|
- [Link to the main page](http://stefanfrings.de/qtwebapp/index-en.html)
|
||||||
- [Link to API documentation](http://stefanfrings.de/qtwebapp/api/index.html)
|
- [Link to API documentation](http://stefanfrings.de/qtwebapp/api/index.html)
|
||||||
|
- [Link to tutorial](http://stefanfrings.de/qtwebapp/tutorial/index.html)
|
||||||
|
|
||||||
Files copied over from the original 'doc' folder:
|
Files copied over from the original 'doc' folder:
|
||||||
|
|
||||||
|
38
logging/CMakeLists.txt
Normal file
38
logging/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
project(logging)
|
||||||
|
|
||||||
|
set(logging_SOURCES
|
||||||
|
dualfilelogger.cpp
|
||||||
|
filelogger.cpp
|
||||||
|
logger.cpp
|
||||||
|
logmessage.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(httpserver_HEADERS
|
||||||
|
dualfilelogger.h
|
||||||
|
filelogger.h
|
||||||
|
logger.h
|
||||||
|
logmessage.h
|
||||||
|
logglobal.h
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
.
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
#include(${QT_USE_FILE})
|
||||||
|
add_definitions(${QT_DEFINITIONS})
|
||||||
|
add_definitions(-DQT_SHARED)
|
||||||
|
|
||||||
|
add_library(logging SHARED
|
||||||
|
${logging_SOURCES}
|
||||||
|
${logging_HEADERS_MOC}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(logging
|
||||||
|
${QT_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
qt5_use_modules(logging Core Network)
|
||||||
|
|
||||||
|
install(TARGETS logging DESTINATION lib)
|
27
logging/dualfilelogger.cpp
Normal file
27
logging/dualfilelogger.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@author Stefan Frings
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dualfilelogger.h"
|
||||||
|
|
||||||
|
using namespace qtwebapp;
|
||||||
|
|
||||||
|
DualFileLogger::DualFileLogger(QSettings* firstSettings, QSettings* secondSettings, const int refreshInterval, QObject* parent)
|
||||||
|
:Logger(parent)
|
||||||
|
{
|
||||||
|
firstLogger=new FileLogger(firstSettings, 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)
|
||||||
|
{
|
||||||
|
firstLogger->log(type,message,file,function,line);
|
||||||
|
secondLogger->log(type,message,file,function,line);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DualFileLogger::clear(const bool buffer, const bool variables)
|
||||||
|
{
|
||||||
|
firstLogger->clear(buffer,variables);
|
||||||
|
secondLogger->clear(buffer,variables);
|
||||||
|
}
|
74
logging/dualfilelogger.h
Normal file
74
logging/dualfilelogger.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@author Stefan Frings
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DUALFILELOGGER_H
|
||||||
|
#define DUALFILELOGGER_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include "logglobal.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "filelogger.h"
|
||||||
|
|
||||||
|
namespace qtwebapp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Logs messages into two log files simultaneously.
|
||||||
|
May be used to create two logfiles with different configuration settings.
|
||||||
|
@see FileLogger for a description of the two underlying loggers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DECLSPEC DualFileLogger : public Logger {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY(DualFileLogger)
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor.
|
||||||
|
@param firstSettings Configuration settings for the first log file, usually stored in an INI file.
|
||||||
|
Must not be 0.
|
||||||
|
Settings are read from the current group, so the caller must have called settings->beginGroup().
|
||||||
|
Because the group must not change during runtime, it is recommended to provide a
|
||||||
|
separate QSettings instance to the logger that is not used by other parts of the program.
|
||||||
|
@param secondSettings Same as firstSettings, but for the second log file.
|
||||||
|
@param refreshInterval Interval of checking for changed config settings in msec, or 0=disabled
|
||||||
|
@param parent Parent object.
|
||||||
|
*/
|
||||||
|
DualFileLogger(QSettings* firstSettings, QSettings* secondSettings, const int refreshInterval=10000, QObject *parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Decorate and log the message, if type>=minLevel.
|
||||||
|
This method is thread safe.
|
||||||
|
@param type Message type (level)
|
||||||
|
@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.
|
||||||
|
*/
|
||||||
|
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:
|
||||||
|
|
||||||
|
/** First logger */
|
||||||
|
FileLogger* firstLogger;
|
||||||
|
|
||||||
|
/** Second logger */
|
||||||
|
FileLogger* secondLogger;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace
|
||||||
|
|
||||||
|
#endif // DUALFILELOGGER_H
|
198
logging/filelogger.cpp
Normal file
198
logging/filelogger.cpp
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@author Stefan Frings
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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();
|
||||||
|
// Save old file name for later comparision with new settings
|
||||||
|
QString oldFileName=fileName;
|
||||||
|
|
||||||
|
// Load new config settings
|
||||||
|
settings->sync();
|
||||||
|
fileName=settings->value("fileName").toString();
|
||||||
|
// 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());
|
||||||
|
fileName=QFileInfo(configFile.absolutePath(),fileName).absoluteFilePath();
|
||||||
|
}
|
||||||
|
maxSize=settings->value("maxSize",0).toLongLong();
|
||||||
|
maxBackups=settings->value("maxBackups",0).toInt();
|
||||||
|
msgFormat=settings->value("msgFormat","{timestamp} {type} {msg}").toString();
|
||||||
|
timestampFormat=settings->value("timestampFormat","yyyy-MM-dd hh:mm:ss.zzz").toString();
|
||||||
|
minLevel=static_cast<QtMsgType>(settings->value("minLevel",0).toInt());
|
||||||
|
bufferSize=settings->value("bufferSize",0).toInt();
|
||||||
|
|
||||||
|
// Create new file if the filename has been changed
|
||||||
|
if (oldFileName!=fileName)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Logging to %s\n",qPrintable(fileName));
|
||||||
|
close();
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileLogger::FileLogger(QSettings* settings, const int refreshInterval, QObject* parent)
|
||||||
|
: Logger(parent)
|
||||||
|
{
|
||||||
|
Q_ASSERT(settings!=0);
|
||||||
|
Q_ASSERT(refreshInterval>=0);
|
||||||
|
this->settings=settings;
|
||||||
|
file=0;
|
||||||
|
if (refreshInterval>0)
|
||||||
|
{
|
||||||
|
refreshTimer.start(refreshInterval,this);
|
||||||
|
}
|
||||||
|
flushTimer.start(1000,this);
|
||||||
|
refreshSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileLogger::~FileLogger()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FileLogger::write(const LogMessage* logMessage)
|
||||||
|
{
|
||||||
|
// Try to write to the file
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Write the message
|
||||||
|
file->write(qPrintable(logMessage->toString(msgFormat,timestampFormat)));
|
||||||
|
|
||||||
|
// Flush error messages immediately, to ensure that no important message
|
||||||
|
// gets lost when the program terinates abnormally.
|
||||||
|
if (logMessage->getType()>=QtCriticalMsg)
|
||||||
|
{
|
||||||
|
file->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for success
|
||||||
|
if (file->error())
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
qWarning("Cannot write to log file %s: %s",qPrintable(fileName),qPrintable(file->errorString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall-back to the super class method, if writing failed
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
Logger::write(logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileLogger::open()
|
||||||
|
{
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
{
|
||||||
|
qWarning("Name of logFile is empty");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
file=new QFile(fileName);
|
||||||
|
if (!file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
|
||||||
|
{
|
||||||
|
qWarning("Cannot open log file %s: %s",qPrintable(fileName),qPrintable(file->errorString()));
|
||||||
|
file=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FileLogger::close()
|
||||||
|
{
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
file->close();
|
||||||
|
delete file;
|
||||||
|
file=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileLogger::rotate() {
|
||||||
|
// count current number of existing backup files
|
||||||
|
int count=0;
|
||||||
|
forever
|
||||||
|
{
|
||||||
|
QFile bakFile(QString("%1.%2").arg(fileName).arg(count+1));
|
||||||
|
if (bakFile.exists())
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all old backup files that exceed the maximum number
|
||||||
|
while (maxBackups>0 && count>=maxBackups)
|
||||||
|
{
|
||||||
|
QFile::remove(QString("%1.%2").arg(fileName).arg(count));
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate backup files
|
||||||
|
for (int i=count; i>0; --i) {
|
||||||
|
QFile::rename(QString("%1.%2").arg(fileName).arg(i),QString("%1.%2").arg(fileName).arg(i+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup the current logfile
|
||||||
|
QFile::rename(fileName,fileName+".1");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FileLogger::timerEvent(QTimerEvent* event)
|
||||||
|
{
|
||||||
|
if (!event)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (event->timerId()==refreshTimer.timerId())
|
||||||
|
{
|
||||||
|
refreshSettings();
|
||||||
|
}
|
||||||
|
else if (event->timerId()==flushTimer.timerId() && file)
|
||||||
|
{
|
||||||
|
mutex.lock();
|
||||||
|
|
||||||
|
// Flush the I/O buffer
|
||||||
|
file->flush();
|
||||||
|
|
||||||
|
// Rotate the file if it is too large
|
||||||
|
if (maxSize>0 && file->size()>=maxSize)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
rotate();
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
}
|
127
logging/filelogger.h
Normal file
127
logging/filelogger.h
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@author Stefan Frings
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FILELOGGER_H
|
||||||
|
#define FILELOGGER_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QBasicTimer>
|
||||||
|
#include "logglobal.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
namespace qtwebapp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Logger that uses a text file for output. Settings are read from a
|
||||||
|
config file using a QSettings object. Config settings can be changed at runtime.
|
||||||
|
<p>
|
||||||
|
Example for the configuration settings:
|
||||||
|
<code><pre>
|
||||||
|
fileName=logs/QtWebApp.log
|
||||||
|
maxSize=1000000
|
||||||
|
maxBackups=2
|
||||||
|
minLevel=0
|
||||||
|
msgformat={timestamp} {typeNr} {type} thread={thread}: {msg}
|
||||||
|
timestampFormat=dd.MM.yyyy hh:mm:ss.zzz
|
||||||
|
bufferSize=0
|
||||||
|
</pre></code>
|
||||||
|
|
||||||
|
- fileName is the name of the log file, relative to the directory of the settings file.
|
||||||
|
In case of windows, if the settings are in the registry, the path is relative to the current
|
||||||
|
working directory.
|
||||||
|
- maxSize is the maximum size of that file in bytes. The file will be backed up and
|
||||||
|
replaced by a new file if it becomes larger than this limit. Please note that
|
||||||
|
the actual file size may become a little bit larger than this limit. Default is 0=unlimited.
|
||||||
|
- maxBackups defines the number of backup files to keep. Default is 0=unlimited.
|
||||||
|
- minLevel defines the minimum type of messages that are written (together with buffered messages) into the file. Defaults is 0=debug.
|
||||||
|
- msgFormat defines the decoration of log messages, see LogMessage class. Default is "{timestamp} {type} {msg}".
|
||||||
|
- timestampFormat defines the format of timestamps, see QDateTime::toString(). Default is "yyyy-MM-dd hh:mm:ss.zzz".
|
||||||
|
- bufferSize defines the size of the buffer. Default is 0=disabled.
|
||||||
|
|
||||||
|
@see set() describes how to set logger variables
|
||||||
|
@see LogMessage for a description of the message decoration.
|
||||||
|
@see Logger for a descrition of the buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DECLSPEC FileLogger : public Logger {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY(FileLogger)
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor.
|
||||||
|
@param settings Configuration settings, usually stored in an INI file. Must not be 0.
|
||||||
|
Settings are read from the current group, so the caller must have called settings->beginGroup().
|
||||||
|
Because the group must not change during runtime, it is recommended to provide a
|
||||||
|
separate QSettings instance to the logger that is not used by other parts of the program.
|
||||||
|
@param refreshInterval Interval of checking for changed config settings in msec, or 0=disabled
|
||||||
|
@param parent Parent object
|
||||||
|
*/
|
||||||
|
FileLogger(QSettings* settings, const int refreshInterval=10000, QObject* parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Destructor. Closes the file.
|
||||||
|
*/
|
||||||
|
virtual ~FileLogger();
|
||||||
|
|
||||||
|
/** Write a message to the log file */
|
||||||
|
virtual void write(const LogMessage* logMessage);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
Handler for timer events.
|
||||||
|
Refreshes config settings or synchronizes I/O buffer, depending on the event.
|
||||||
|
This method is thread-safe.
|
||||||
|
@param event used to distinguish between the two timers.
|
||||||
|
*/
|
||||||
|
void timerEvent(QTimerEvent* event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** Configured name of the log file */
|
||||||
|
QString fileName;
|
||||||
|
|
||||||
|
/** Configured maximum size of the file in bytes, or 0=unlimited */
|
||||||
|
long maxSize;
|
||||||
|
|
||||||
|
/** Configured maximum number of backup files, or 0=unlimited */
|
||||||
|
int maxBackups;
|
||||||
|
|
||||||
|
/** Pointer to the configuration settings */
|
||||||
|
QSettings* settings;
|
||||||
|
|
||||||
|
/** Output file, or 0=disabled */
|
||||||
|
QFile* file;
|
||||||
|
|
||||||
|
/** Timer for refreshing configuration settings */
|
||||||
|
QBasicTimer refreshTimer;
|
||||||
|
|
||||||
|
/** Timer for flushing the file I/O buffer */
|
||||||
|
QBasicTimer flushTimer;
|
||||||
|
|
||||||
|
/** Open the output file */
|
||||||
|
void open();
|
||||||
|
|
||||||
|
/** Close the output file */
|
||||||
|
void close();
|
||||||
|
|
||||||
|
/** Rotate files and delete some backups if there are too many */
|
||||||
|
void rotate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Refreshes the configuration settings.
|
||||||
|
This method is thread-safe.
|
||||||
|
*/
|
||||||
|
void refreshSettings();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace
|
||||||
|
|
||||||
|
#endif // FILELOGGER_H
|
192
logging/logger.cpp
Normal file
192
logging/logger.cpp
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/**
|
||||||
|
@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}"),
|
||||||
|
timestampFormat("dd.MM.yyyy hh:mm:ss.zzz"),
|
||||||
|
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();
|
||||||
|
}
|
188
logging/logger.h
Normal file
188
logging/logger.h
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@author Stefan Frings
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOGGER_H
|
||||||
|
#define LOGGER_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QThreadStorage>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QObject>
|
||||||
|
#include "logglobal.h"
|
||||||
|
#include "logmessage.h"
|
||||||
|
|
||||||
|
namespace qtwebapp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Decorates and writes log messages to the console, stderr.
|
||||||
|
<p>
|
||||||
|
The decorator uses a predefined msgFormat string to enrich log messages
|
||||||
|
with additional information (e.g. timestamp).
|
||||||
|
<p>
|
||||||
|
The msgFormat string and also the message text may contain additional
|
||||||
|
variable names in the form <i>{name}</i> that are filled by values
|
||||||
|
taken from a static thread local dictionary.
|
||||||
|
<p>
|
||||||
|
The logger keeps a configurable number of messages in a ring-buffer.
|
||||||
|
A log message with a severity >= minLevel flushes the buffer,
|
||||||
|
so the stored messages get written out. If the buffer is disabled, then
|
||||||
|
only messages with severity >= minLevel are written out.
|
||||||
|
<p>
|
||||||
|
If you enable the buffer and use minLevel=2, then the application logs
|
||||||
|
only errors together with some buffered debug messages. But as long no
|
||||||
|
error occurs, nothing gets written out.
|
||||||
|
<p>
|
||||||
|
Each thread has it's own buffer.
|
||||||
|
<p>
|
||||||
|
The logger can be registered to handle messages from
|
||||||
|
the static global functions qDebug(), qWarning(), qCritical() and qFatal().
|
||||||
|
|
||||||
|
@see set() describes how to set logger variables
|
||||||
|
@see LogMessage for a description of the message decoration.
|
||||||
|
@warning You should prefer a derived class, for example FileLogger,
|
||||||
|
because logging to the console is less useful.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DECLSPEC Logger : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY(Logger)
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor.
|
||||||
|
Uses the same defaults as the other constructor.
|
||||||
|
@param parent Parent object
|
||||||
|
*/
|
||||||
|
Logger(QObject* parent);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor.
|
||||||
|
@param msgFormat Format of the decoration, e.g. "{timestamp} {type} thread={thread}: {msg}"
|
||||||
|
@param timestampFormat Format of timestamp, e.g. "dd.MM.yyyy hh:mm:ss.zzz"
|
||||||
|
@param minLevel Minimum severity that genertes an output (0=debug, 1=warning, 2=critical, 3=fatal).
|
||||||
|
@param bufferSize Size of the backtrace buffer, number of messages per thread. 0=disabled.
|
||||||
|
@param parent Parent object
|
||||||
|
@see LogMessage for a description of the message decoration.
|
||||||
|
*/
|
||||||
|
Logger(const QString msgFormat="{timestamp} {type} {msg}", const QString timestampFormat="dd.MM.yyyy hh:mm:ss.zzz", const QtMsgType minLevel=QtDebugMsg, const int bufferSize=0, QObject* parent = 0);
|
||||||
|
|
||||||
|
/** Destructor */
|
||||||
|
virtual ~Logger();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Decorate and log the message, if type>=minLevel.
|
||||||
|
This method is thread safe.
|
||||||
|
@param type Message type (level)
|
||||||
|
@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.
|
||||||
|
*/
|
||||||
|
virtual void log(const QtMsgType type, const QString& message, const QString &file="", const QString &function="", const int line=0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Installs this logger as the default message handler, so it
|
||||||
|
can be used through the global static logging functions (e.g. qDebug()).
|
||||||
|
*/
|
||||||
|
void installMsgHandler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets a thread-local variable that may be used to decorate log messages.
|
||||||
|
This method is thread safe.
|
||||||
|
@param name Name of the variable
|
||||||
|
@param value Value of the variable
|
||||||
|
*/
|
||||||
|
static void set(const QString& name, const QString& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
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);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** Format string for message decoration */
|
||||||
|
QString msgFormat;
|
||||||
|
|
||||||
|
/** Format string of timestamps */
|
||||||
|
QString timestampFormat;
|
||||||
|
|
||||||
|
/** Minimum level of message types that are written out */
|
||||||
|
QtMsgType minLevel;
|
||||||
|
|
||||||
|
/** Size of backtrace buffer, number of messages per thread. 0=disabled */
|
||||||
|
int bufferSize;
|
||||||
|
|
||||||
|
/** Used to synchronize access of concurrent threads */
|
||||||
|
static QMutex mutex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Decorate and write a log message to stderr. Override this method
|
||||||
|
to provide a different output medium.
|
||||||
|
*/
|
||||||
|
virtual void write(const LogMessage* logMessage);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** Pointer to the default logger, used by msgHandler() */
|
||||||
|
static Logger* defaultLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Message Handler for the global static logging functions (e.g. qDebug()).
|
||||||
|
Forward calls to the default logger.
|
||||||
|
<p>
|
||||||
|
In case of a fatal message, the program will abort.
|
||||||
|
Variables in the in the message are replaced by their values.
|
||||||
|
This method is thread safe.
|
||||||
|
@param type Message type (level)
|
||||||
|
@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__)
|
||||||
|
*/
|
||||||
|
static void msgHandler(const QtMsgType type, const QString &message, const QString &file="", const QString &function="", const int line=0);
|
||||||
|
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
|
||||||
|
/**
|
||||||
|
Wrapper for QT version 5.
|
||||||
|
@param type Message type (level)
|
||||||
|
@param context Message context
|
||||||
|
@param message Message text
|
||||||
|
@see msgHandler()
|
||||||
|
*/
|
||||||
|
static void msgHandler5(const QtMsgType type, const QMessageLogContext& context, const QString &message);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/**
|
||||||
|
Wrapper for QT version 4.
|
||||||
|
@param type Message type (level)
|
||||||
|
@param message Message text
|
||||||
|
@see msgHandler()
|
||||||
|
*/
|
||||||
|
static void msgHandler4(const QtMsgType type, const char * message);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Thread local variables to be used in log messages */
|
||||||
|
static QThreadStorage<QHash<QString,QString>*> logVars;
|
||||||
|
|
||||||
|
/** Thread local backtrace buffers */
|
||||||
|
QThreadStorage<QList<LogMessage*>*> buffers;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace
|
||||||
|
|
||||||
|
#endif // LOGGER_H
|
6
logging/logging.pri
Normal file
6
logging/logging.pri
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
DEPENDPATH += $$PWD
|
||||||
|
|
||||||
|
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
|
24
logging/logglobal.h
Normal file
24
logging/logglobal.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@author Stefan Frings
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOGGLOBAL_H
|
||||||
|
#define LOGGLOBAL_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
// This is specific to Windows dll's
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
#if defined(QTWEBAPPLIB_EXPORT)
|
||||||
|
#define DECLSPEC Q_DECL_EXPORT
|
||||||
|
#elif defined(QTWEBAPPLIB_IMPORT)
|
||||||
|
#define DECLSPEC Q_DECL_IMPORT
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if !defined(DECLSPEC)
|
||||||
|
#define DECLSPEC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // LOGGLOBAL_H
|
||||||
|
|
90
logging/logmessage.cpp
Normal file
90
logging/logmessage.cpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@author Stefan Frings
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "logmessage.h"
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
using namespace qtwebapp;
|
||||||
|
|
||||||
|
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->message=message;
|
||||||
|
this->file=file;
|
||||||
|
this->function=function;
|
||||||
|
this->line=line;
|
||||||
|
timestamp=QDateTime::currentDateTime();
|
||||||
|
threadId=QThread::currentThreadId();
|
||||||
|
|
||||||
|
// Copy the logVars if not null,
|
||||||
|
// so that later changes in the original do not affect the copy
|
||||||
|
if (logVars)
|
||||||
|
{
|
||||||
|
this->logVars=*logVars;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LogMessage::toString(const QString& msgFormat, const QString& timestampFormat) const
|
||||||
|
{
|
||||||
|
QString decorated=msgFormat+"\n";
|
||||||
|
decorated.replace("{msg}",message);
|
||||||
|
|
||||||
|
if (decorated.contains("{timestamp}"))
|
||||||
|
{
|
||||||
|
decorated.replace("{timestamp}",timestamp.toString(timestampFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString typeNr;
|
||||||
|
typeNr.setNum(type);
|
||||||
|
decorated.replace("{typeNr}",typeNr);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case QtDebugMsg:
|
||||||
|
decorated.replace("{type}","DEBUG ");
|
||||||
|
break;
|
||||||
|
case QtWarningMsg:
|
||||||
|
decorated.replace("{type}","WARNING ");
|
||||||
|
break;
|
||||||
|
case QtCriticalMsg:
|
||||||
|
decorated.replace("{type}","CRITICAL");
|
||||||
|
break;
|
||||||
|
case QtFatalMsg:
|
||||||
|
decorated.replace("{type}","FATAL ");
|
||||||
|
break;
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
|
||||||
|
case QtInfoMsg:
|
||||||
|
decorated.replace("{type}","INFO ");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
decorated.replace("{type}",typeNr);
|
||||||
|
}
|
||||||
|
|
||||||
|
decorated.replace("{file}",file);
|
||||||
|
decorated.replace("{function}",function);
|
||||||
|
decorated.replace("{line}",QString::number(line));
|
||||||
|
|
||||||
|
QString threadId;
|
||||||
|
threadId.setNum((unsigned long)QThread::currentThreadId());
|
||||||
|
decorated.replace("{thread}",threadId);
|
||||||
|
|
||||||
|
// Fill in variables
|
||||||
|
if (decorated.contains("{") && !logVars.isEmpty())
|
||||||
|
{
|
||||||
|
QList<QString> keys=logVars.keys();
|
||||||
|
foreach (QString key, keys)
|
||||||
|
{
|
||||||
|
decorated.replace("{"+key+"}",logVars.value(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decorated;
|
||||||
|
}
|
||||||
|
|
||||||
|
QtMsgType LogMessage::getType() const
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
97
logging/logmessage.h
Normal file
97
logging/logmessage.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@author Stefan Frings
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOGMESSAGE_H
|
||||||
|
#define LOGMESSAGE_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QHash>
|
||||||
|
#include "logglobal.h"
|
||||||
|
|
||||||
|
namespace qtwebapp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Represents a single log message together with some data
|
||||||
|
that are used to decorate the log message.
|
||||||
|
|
||||||
|
The following variables may be used in the message and in msgFormat:
|
||||||
|
|
||||||
|
- {timestamp} Date and time of creation
|
||||||
|
- {typeNr} Type of the message in numeric format (0-3)
|
||||||
|
- {type} Type of the message in string format (DEBUG, WARNING, CRITICAL, FATAL)
|
||||||
|
- {thread} ID number of the thread
|
||||||
|
- {msg} Message text
|
||||||
|
- {xxx} For any user-defined logger variable
|
||||||
|
|
||||||
|
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 DECLSPEC LogMessage
|
||||||
|
{
|
||||||
|
Q_DISABLE_COPY(LogMessage)
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor. All parameters are copied, so that later changes to them do not
|
||||||
|
affect this object.
|
||||||
|
@param type Type of the message
|
||||||
|
@param message Message text
|
||||||
|
@param logVars Logger variables, 0 is allowed
|
||||||
|
@param file Name of the source file where the message was generated
|
||||||
|
@param function Name of the function where the message was generated
|
||||||
|
@param line Line Number of the source file, where the message was generated
|
||||||
|
*/
|
||||||
|
LogMessage(const QtMsgType type, const QString& message, QHash<QString,QString>* logVars, const QString &file, const QString &function, const int line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the log message as decorated string.
|
||||||
|
@param msgFormat Format of the decoration. May contain variables and static text,
|
||||||
|
e.g. "{timestamp} {type} thread={thread}: {msg}".
|
||||||
|
@param timestampFormat Format of timestamp, e.g. "dd.MM.yyyy hh:mm:ss.zzz", see QDateTime::toString().
|
||||||
|
@see QDatetime for a description of the timestamp format pattern
|
||||||
|
*/
|
||||||
|
QString toString(const QString& msgFormat, const QString& timestampFormat) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the message type.
|
||||||
|
*/
|
||||||
|
QtMsgType getType() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** Logger variables */
|
||||||
|
QHash<QString,QString> logVars;
|
||||||
|
|
||||||
|
/** Date and time of creation */
|
||||||
|
QDateTime timestamp;
|
||||||
|
|
||||||
|
/** Type of the message */
|
||||||
|
QtMsgType type;
|
||||||
|
|
||||||
|
/** ID number of the thread */
|
||||||
|
Qt::HANDLE threadId;
|
||||||
|
|
||||||
|
/** Message text */
|
||||||
|
QString message;
|
||||||
|
|
||||||
|
/** Filename where the message was generated */
|
||||||
|
QString file;
|
||||||
|
|
||||||
|
/** Function name where the message was generated */
|
||||||
|
QString function;
|
||||||
|
|
||||||
|
/** Line number where the message was generated */
|
||||||
|
int line;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace
|
||||||
|
|
||||||
|
#endif // LOGMESSAGE_H
|
9
logging/readme.md
Normal file
9
logging/readme.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
## QtWebApp logger ##
|
||||||
|
|
||||||
|
This is based on the logging part of QtWebApp from Stefan Frings
|
||||||
|
|
||||||
|
- [Link to the main page](http://stefanfrings.de/qtwebapp/index-en.html)
|
||||||
|
- [Link to API documentation](http://stefanfrings.de/qtwebapp/api/index.html)
|
||||||
|
- [Link to tutorial](http://stefanfrings.de/qtwebapp/tutorial/index.html)
|
||||||
|
|
||||||
|
Some changes have been made to support the option of having a console logging plus optional file logging
|
@ -23,6 +23,7 @@ SUBDIRS += devices
|
|||||||
SUBDIRS += mbelib
|
SUBDIRS += mbelib
|
||||||
SUBDIRS += dsdcc
|
SUBDIRS += dsdcc
|
||||||
SUBDIRS += httpserver
|
SUBDIRS += httpserver
|
||||||
|
SUBDIRS += logging
|
||||||
CONFIG(MINGW64)SUBDIRS += cm256cc
|
CONFIG(MINGW64)SUBDIRS += cm256cc
|
||||||
SUBDIRS += plugins/samplesource/filesource
|
SUBDIRS += plugins/samplesource/filesource
|
||||||
CONFIG(MINGW64)SUBDIRS += plugins/samplesource/sdrdaemonsource
|
CONFIG(MINGW64)SUBDIRS += plugins/samplesource/sdrdaemonsource
|
||||||
|
@ -147,6 +147,7 @@ add_library(sdrgui SHARED
|
|||||||
include_directories(
|
include_directories(
|
||||||
.
|
.
|
||||||
${CMAKE_SOURCE_DIR}/sdrbase
|
${CMAKE_SOURCE_DIR}/sdrbase
|
||||||
|
${CMAKE_SOURCE_DIR}/logging
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
${OPENGL_INCLUDE_DIR}
|
${OPENGL_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
@ -155,6 +156,7 @@ target_link_libraries(sdrgui
|
|||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
${OPENGL_LIBRARIES}
|
${OPENGL_LIBRARIES}
|
||||||
sdrbase
|
sdrbase
|
||||||
|
logging
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(sdrgui PROPERTIES DEFINE_SYMBOL "sdrangel_EXPORTS")
|
set_target_properties(sdrgui PROPERTIES DEFINE_SYMBOL "sdrangel_EXPORTS")
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
#include "gui/glspectrum.h"
|
#include "gui/glspectrum.h"
|
||||||
#include "gui/glspectrumgui.h"
|
#include "gui/glspectrumgui.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
@ -71,6 +72,9 @@ MainWindow::MainWindow(QWidget* parent) :
|
|||||||
m_centerFrequency(0),
|
m_centerFrequency(0),
|
||||||
m_sampleFileName(std::string("./test.sdriq"))
|
m_sampleFileName(std::string("./test.sdriq"))
|
||||||
{
|
{
|
||||||
|
m_logger = new qtwebapp::Logger(this);
|
||||||
|
m_logger->installMsgHandler();
|
||||||
|
|
||||||
qDebug() << "MainWindow::MainWindow: start";
|
qDebug() << "MainWindow::MainWindow: start";
|
||||||
|
|
||||||
m_instance = this;
|
m_instance = this;
|
||||||
@ -202,6 +206,9 @@ MainWindow::~MainWindow()
|
|||||||
delete m_showSystemWidget;
|
delete m_showSystemWidget;
|
||||||
|
|
||||||
delete ui;
|
delete ui;
|
||||||
|
|
||||||
|
qDebug() << "MainWindow::~MainWindow: end";
|
||||||
|
delete m_logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::addSourceDevice()
|
void MainWindow::addSourceDevice()
|
||||||
|
@ -50,6 +50,10 @@ class DeviceUISet;
|
|||||||
class PluginInterface;
|
class PluginInterface;
|
||||||
class QWidget;
|
class QWidget;
|
||||||
|
|
||||||
|
namespace qtwebapp {
|
||||||
|
class Logger;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
}
|
}
|
||||||
@ -110,6 +114,8 @@ private:
|
|||||||
quint64 m_centerFrequency;
|
quint64 m_centerFrequency;
|
||||||
std::string m_sampleFileName;
|
std::string m_sampleFileName;
|
||||||
|
|
||||||
|
qtwebapp::Logger *m_logger;
|
||||||
|
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
void loadPresetSettings(const Preset* preset, int tabIndex);
|
void loadPresetSettings(const Preset* preset, int tabIndex);
|
||||||
void savePresetSettings(Preset* preset, int tabIndex);
|
void savePresetSettings(Preset* preset, int tabIndex);
|
||||||
|
Loading…
Reference in New Issue
Block a user