A?adido el uso 7z.dll en lugar de 7z.exe en el visor

This commit is contained in:
Luis Ángel San Martín
2013-07-14 17:43:38 +02:00
commit ff17d8ef1f
634 changed files with 50442 additions and 0 deletions

View File

@ -0,0 +1,7 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$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
OTHER_FILES += $$PWD/../doc/readme.txt

View File

@ -0,0 +1,20 @@
/**
@file
@author Stefan Frings
*/
#include "dualfilelogger.h"
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) {
firstLogger->log(type, message);
secondLogger->log(type, message);
}

View File

@ -0,0 +1,60 @@
/**
@file
@author Stefan Frings
*/
#ifndef DUALFILELOGGER_H
#define DUALFILELOGGER_H
#include "logger.h"
#include "filelogger.h"
#include <QString>
#include <QSettings>
#include <QtGlobal>
/**
Logs messages into two log files. This is specially useful to get one less detailed
logfile for normal operation plus one more detailed file for debugging.
@see FileLogger for a description of the required config settings.
@see set() describes how to set logger variables
@see LogMessage for a description of the message decoration.
*/
class 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 the 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 a message.
This method is thread safe.
@param type Message type (level)
@param message Message text
@see LogMessage for a description of the message decoration.
*/
virtual void log(const QtMsgType type, const QString& message);
private:
/** First logger */
FileLogger* firstLogger;
/** Second logger */
FileLogger* secondLogger;
};
#endif // DUALFILELOGGER_H

View File

@ -0,0 +1,178 @@
/**
@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>
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","./server/logs/log.log").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",128000).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();
disabled=settings->value("disabled",false).toBool();
// 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) {
// Write to the file
if (!disabled) {
// 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(QDir::cleanPath(fileName));
if (!file->open(QIODevice::WriteOnly | 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
if(maxBackups>0)
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();
}
}

View File

@ -0,0 +1,131 @@
/**
@file
@author Stefan Frings
*/
#ifndef FILELOGGER_H
#define FILELOGGER_H
#include <QtGlobal>
#include <QSettings>
#include <QFile>
#include <QMutex>
#include <QBasicTimer>
#include "logger.h"
/**
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.
They are copied to private fields in regular intervals for permance reason.
<p>
Example for the required configuration settings:
<code><pre>
disabled=false
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. 0=unlimited.
- maxBackups defines the number of backup files to keep. 0=unlimited.
- minLevel defines the minimum level of message types to be written into the file.
- msgFormat defines the decoration of log messages.
- timestampFormat defines the format of timestamps.
- buffersize defines the size of the backtrace buffer. 0=disabled.
The buffer stores log messages of any level from the time before an error occurs.
It can be used to provide detailed debug information when an error occurs, while keeping
the logfile clean as long no error occurs. Using this buffer may reduce performance
significantly.
@see set() describes how to set logger variables
@see LogMessage for a description of the message decoration.
@see Logger for a descrition of the backtrace buffer
*/
class 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 the 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;
/** Whether this logger is disabled */
bool disabled;
/** 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();
};
#endif // FILELOGGER_H

View File

@ -0,0 +1,154 @@
/**
@file
@author Stefan Frings
*/
#include "logger.h"
#include <stdio.h>
#include <stdlib.h>
#include <QMutex>
#include <QDateTime>
#include <QThread>
Logger* Logger::defaultLogger=0;
QThreadStorage<QHash<QString,QString>*> Logger::logVars;
QThreadStorage<QList<LogMessage*>*> Logger::buffers;
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 char* message) {
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);
nonRecursiveMutex.unlock();
}
else {
fputs(message,stderr);
fflush(stderr);
}
// Abort the program after logging a fatal message
if (type>=QtFatalMsg) {
//abort();
}
recursiveMutex.unlock();
}
Logger::~Logger() {
if (defaultLogger==this) {
qInstallMsgHandler(0);
defaultLogger=0;
}
}
void Logger::write(const LogMessage* logMessage) {
fputs(qPrintable(logMessage->toString(msgFormat,timestampFormat)),stderr);
fflush(stderr);
}
void Logger::installMsgHandler() {
defaultLogger=this;
qInstallMsgHandler(msgHandler);
}
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) {
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());
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());
write(&logMessage);
}
}
mutex.unlock();
}

View File

@ -0,0 +1,144 @@
/**
@file
@author Stefan Frings
*/
#ifndef LOGGER_H
#define LOGGER_H
#include <QtGlobal>
#include <QThreadStorage>
#include <QHash>
#include <QStringList>
#include <QMutex>
#include "logmessage.h"
/**
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 buffer stores log messages of any level from the time before an error occurs.
It can be used to provide detailed debug information when an error occurs, while
keeping the logfile clean as long no error occurs. Using this buffer may
reduce performance significantly.
<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 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 type of messages that are written out.
@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
@see LogMessage for a description of the message decoration.
*/
virtual void log(const QtMsgType type, const QString& message);
/**
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.
@param buffer Whether to clear the backtrace buffer
@param variables Whether to clear the log variables
*/
static 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 to the static members */
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
*/
static void msgHandler(const QtMsgType type, const char* message);
/** Thread local variables to be used in log messages */
static QThreadStorage<QHash<QString,QString>*> logVars;
/** Thread local backtrace buffers */
static QThreadStorage<QList<LogMessage*>*> buffers;
};
#endif // LOGGER_H

View File

@ -0,0 +1,68 @@
/**
@file
@author Stefan Frings
*/
#include "logmessage.h"
#include <QThread>
LogMessage::LogMessage(const QtMsgType type, const QString& message, QHash<QString,QString>* logVars) {
this->type=type;
this->message=message;
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}",QDateTime::currentDateTime().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;
default:
decorated.replace("{type}",typeNr);
}
QString threadId;
threadId.setNum((quint64)QThread::currentThreadId()); //CAMBIADo unsigned int por quint64, evita error de compilaci<63>n en m<>quinas de 64bit
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;
}

View File

@ -0,0 +1,74 @@
/**
@file
@author Stefan Frings
*/
#ifndef LOGMESSAGE_H
#define LOGMESSAGE_H
#include <QtGlobal>
#include <QDateTime>
#include <QHash>
/**
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 (only useable in msgFormat)
- {xxx} For any user-defined logger variable
*/
class 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
*/
LogMessage(const QtMsgType type, const QString& message, QHash<QString,QString>* logVars);
/**
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 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;
};
#endif // LOGMESSAGE_H