fixed LibraryServer in Qt5

moved server_log to standardPath
This commit is contained in:
Luis Ángel San Martín 2013-11-20 19:34:06 +01:00
parent 52f8a6e56a
commit 2b2c1de277
17 changed files with 184 additions and 118 deletions

View File

@ -29,6 +29,12 @@
@see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize @see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize
*/ */
#if QT_VERSION >= 0x050000
typedef qintptr tSocketDescriptor;
#else
typedef int tSocketDescriptor;
#endif
class HttpConnectionHandler : public QThread { class HttpConnectionHandler : public QThread {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(HttpConnectionHandler) Q_DISABLE_COPY(HttpConnectionHandler)
@ -79,7 +85,7 @@ public slots:
Received from from the listener, when the handler shall start processing a new connection. Received from from the listener, when the handler shall start processing a new connection.
@param socketDescriptor references the accepted connection. @param socketDescriptor references the accepted connection.
*/ */
void handleConnection(int socketDescriptor); void handleConnection(tSocketDescriptor socketDescriptor);
private slots: private slots:

View File

@ -12,6 +12,9 @@ HttpListener::HttpListener(QSettings* settings, HttpRequestHandler* requestHandl
: QTcpServer(parent) : QTcpServer(parent)
{ {
Q_ASSERT(settings!=0); Q_ASSERT(settings!=0);
// Reqister type of socketDescriptor for signal/slot handling
qRegisterMetaType<tSocketDescriptor>("tSocketDescriptor");
// Create connection handler pool
this->settings=settings; this->settings=settings;
pool=new HttpConnectionHandlerPool(settings,requestHandler); pool=new HttpConnectionHandlerPool(settings,requestHandler);
// Start listening // Start listening
@ -39,8 +42,7 @@ HttpListener::~HttpListener() {
qDebug("HttpListener: destroyed"); qDebug("HttpListener: destroyed");
} }
void HttpListener::incomingConnection(tSocketDescriptor socketDescriptor) {
void HttpListener::incomingConnection(int socketDescriptor) {
#ifdef SUPERVERBOSE #ifdef SUPERVERBOSE
qDebug("HttpListener: New connection"); qDebug("HttpListener: New connection");
#endif #endif
@ -50,9 +52,9 @@ void HttpListener::incomingConnection(int socketDescriptor) {
if (freeHandler) { if (freeHandler) {
// The descriptor is passed via signal/slot because the handler lives in another // The descriptor is passed via signal/slot because the handler lives in another
// thread and cannot open the socket when called by another thread. // thread and cannot open the socket when called by another thread.
connect(this,SIGNAL(handleConnection(int)),freeHandler,SLOT(handleConnection(int))); connect(this,SIGNAL(handleConnection(tSocketDescriptor)),freeHandler,SLOT(handleConnection(tSocketDescriptor)));
emit handleConnection(socketDescriptor); emit handleConnection(socketDescriptor);
disconnect(this,SIGNAL(handleConnection(int)),freeHandler,SLOT(handleConnection(int))); disconnect(this,SIGNAL(handleConnection(tSocketDescriptor)),freeHandler,SLOT(handleConnection(tSocketDescriptor)));
} }
else { else {
// Reject the connection // Reject the connection

View File

@ -14,9 +14,8 @@
#include "httprequesthandler.h" #include "httprequesthandler.h"
/** /**
Listens for incoming TCP connections and passes control to Listens for incoming TCP connections and and passes all incoming HTTP requests to your implementation of HttpRequestHandler,
one of the pooled connection handlers. This class is also which processes the request and generates the response (usually a HTML document).
responsible for managing the pool.
<p> <p>
Example for the required settings in the config file: Example for the required settings in the config file:
<code><pre> <code><pre>
@ -43,7 +42,7 @@ public:
Constructor. Constructor.
@param settings Configuration settings for the HTTP server. Must not be 0. @param settings Configuration settings for the HTTP server. Must not be 0.
@param requestHandler Processes each received HTTP request, usually by dispatching to controller classes. @param requestHandler Processes each received HTTP request, usually by dispatching to controller classes.
@param parent Parent object @param parent Parent object.
*/ */
HttpListener(QSettings* settings, HttpRequestHandler* requestHandler, QObject* parent = 0); HttpListener(QSettings* settings, HttpRequestHandler* requestHandler, QObject* parent = 0);
@ -53,7 +52,7 @@ public:
protected: protected:
/** Serves new incoming connection requests */ /** Serves new incoming connection requests */
void incomingConnection(int socketDescriptor); void incomingConnection(tSocketDescriptor socketDescriptor);
private: private:
@ -69,7 +68,8 @@ signals:
Emitted when the connection handler shall process a new incoming onnection. Emitted when the connection handler shall process a new incoming onnection.
@param socketDescriptor references the accepted connection. @param socketDescriptor references the accepted connection.
*/ */
void handleConnection(int socketDescriptor);
void handleConnection(tSocketDescriptor socketDescriptor);
}; };

View File

@ -16,15 +16,15 @@
<p> <p>
Example code for proper response generation: Example code for proper response generation:
<code><pre> <code><pre>
response.setStatus(200,"OK"); // optional, because this is the default response.setStatus(200,"OK"); // optional, because this is the default
response.writeBody("Hello"); response.writeBody("Hello");
response.writeBody("World!",true); response.writeBody("World!",true);
</pre></code> </pre></code>
<p> <p>
Example how to return an error: Example how to return an error:
<code><pre> <code><pre>
response.setStatus(500,"server error"); response.setStatus(500,"server error");
response.write("The request cannot be processed because the servers is broken",true); response.write("The request cannot be processed because the servers is broken",true);
</pre></code> </pre></code>
<p> <p>
For performance reason, writing a single or few large packets is better than writing For performance reason, writing a single or few large packets is better than writing
@ -34,7 +34,7 @@
*/ */
class HttpResponse { class HttpResponse {
Q_DISABLE_COPY(HttpResponse) Q_DISABLE_COPY(HttpResponse)
public: public:
/** /**

View File

@ -9,6 +9,7 @@
#include <QDateTime> #include <QDateTime>
#include "httpsession.h" #include "httpsession.h"
#include "static.h" #include "static.h"
#include <QApplication>
StaticFileController::StaticFileController(QSettings* settings, QObject* parent) StaticFileController::StaticFileController(QSettings* settings, QObject* parent)
:HttpRequestHandler(parent) :HttpRequestHandler(parent)
@ -23,8 +24,8 @@ StaticFileController::StaticFileController(QSettings* settings, QObject* parent)
if (QDir::isRelativePath(docroot)) if (QDir::isRelativePath(docroot))
#endif #endif
{ {
QFileInfo configFile(settings->fileName()); QFileInfo configFile(QApplication::applicationDirPath());
docroot=QFileInfo(configFile.absolutePath(),docroot).absoluteFilePath(); docroot=QFileInfo(QApplication::applicationDirPath(),docroot).absoluteFilePath();
} }
qDebug("StaticFileController: docroot=%s, encoding=%s, maxAge=%i",qPrintable(docroot),qPrintable(encoding),maxAge); qDebug("StaticFileController: docroot=%s, encoding=%s, maxAge=%i",qPrintable(docroot),qPrintable(encoding),maxAge);
maxCachedFileSize=settings->value("maxCachedFileSize","65536").toInt(); maxCachedFileSize=settings->value("maxCachedFileSize","65536").toInt();
@ -202,4 +203,4 @@ QString StaticFileController::getDeviceAwareFileName(QString fileName, QString d
return completeFileName; //existe un archivo específico para este dispositivo y locales return completeFileName; //existe un archivo específico para este dispositivo y locales
else else
return getLocalizedFileName(fileName,locales,path); //no hay archivo específico para el dispositivo, pero puede haberlo para estas locales return getLocalizedFileName(fileName,locales,path); //no hay archivo específico para el dispositivo, pero puede haberlo para estas locales
} }

View File

@ -3,5 +3,3 @@ DEPENDPATH += $$PWD
HEADERS += $$PWD/logmessage.h $$PWD/logger.h $$PWD/filelogger.h $$PWD/dualfilelogger.h 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 SOURCES += $$PWD/logmessage.cpp $$PWD/logger.cpp $$PWD/filelogger.cpp $$PWD/dualfilelogger.cpp
OTHER_FILES += $$PWD/../doc/readme.txt

View File

@ -13,11 +13,9 @@
#include <QtGlobal> #include <QtGlobal>
/** /**
Logs messages into two log files. This is specially useful to get one less detailed Logs messages into two log files simultaneously.
logfile for normal operation plus one more detailed file for debugging. May be used to create two logfiles with different configuration settings.
@see FileLogger for a description of the required config settings. @see FileLogger for a description of the two underlying loggers.
@see set() describes how to set logger variables
@see LogMessage for a description of the message decoration.
*/ */
class DualFileLogger : public Logger { class DualFileLogger : public Logger {
@ -33,8 +31,8 @@ public:
Because the group must not change during runtime, it is recommended to provide a 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. 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 secondSettings Same as firstSettings, but for the second log file.
@param refreshInterval Interval of checking the config settings in msec, or 0=disabled @param refreshInterval Interval of checking for changed config settings in msec, or 0=disabled
@param parent Parent object @param parent Parent object.
*/ */
DualFileLogger(QSettings* firstSettings, QSettings* secondSettings, const int refreshInterval=10000, QObject *parent = 0); DualFileLogger(QSettings* firstSettings, QSettings* secondSettings, const int refreshInterval=10000, QObject *parent = 0);

View File

@ -13,6 +13,7 @@
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <stdio.h> #include <stdio.h>
#include "yacreader_global.h"
void FileLogger::refreshSettings() { void FileLogger::refreshSettings() {
mutex.lock(); mutex.lock();
@ -21,7 +22,7 @@ void FileLogger::refreshSettings() {
// Load new config settings // Load new config settings
settings->sync(); settings->sync();
fileName=settings->value("fileName","./server/logs/log.log").toString(); fileName=settings->value("fileName","server_log.log").toString();
// Convert relative fileName to absolute, based on the directory of the config file. // Convert relative fileName to absolute, based on the directory of the config file.
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
if (QDir::isRelativePath(fileName) && settings->format()!=QSettings::NativeFormat) if (QDir::isRelativePath(fileName) && settings->format()!=QSettings::NativeFormat)
@ -29,16 +30,15 @@ void FileLogger::refreshSettings() {
if (QDir::isRelativePath(fileName)) if (QDir::isRelativePath(fileName))
#endif #endif
{ {
QFileInfo configFile(settings->fileName()); QFileInfo configFile(YACReader::getSettingsPath());
fileName=QFileInfo(configFile.absolutePath(),fileName).absoluteFilePath(); fileName=QFileInfo(YACReader::getSettingsPath(),fileName).absoluteFilePath();
} }
maxSize=settings->value("maxSize",128000).toLongLong(); maxSize=settings->value("maxSize",0).toLongLong();
maxBackups=settings->value("maxBackups",0).toInt(); maxBackups=settings->value("maxBackups",0).toInt();
msgFormat=settings->value("msgFormat","{timestamp} {type} {msg}").toString(); msgFormat=settings->value("msgFormat","{timestamp} {type} {msg}").toString();
timestampFormat=settings->value("timestampFormat","{yyyy-MM-dd hh:mm:ss.zzz}").toString(); timestampFormat=settings->value("timestampFormat","yyyy-MM-dd hh:mm:ss.zzz").toString();
minLevel=static_cast<QtMsgType>(settings->value("minLevel",0).toInt()); minLevel=static_cast<QtMsgType>(settings->value("minLevel",0).toInt());
bufferSize=settings->value("bufferSize",0).toInt(); bufferSize=settings->value("bufferSize",0).toInt();
disabled=settings->value("disabled",false).toBool();
// Create new file if the filename has been changed // Create new file if the filename has been changed
if (oldFileName!=fileName) { if (oldFileName!=fileName) {
@ -53,12 +53,13 @@ void FileLogger::refreshSettings() {
FileLogger::FileLogger(QSettings* settings, const int refreshInterval, QObject* parent) FileLogger::FileLogger(QSettings* settings, const int refreshInterval, QObject* parent)
: Logger(parent) : Logger(parent)
{ {
//Q_ASSERT(settings!=0); Q_ASSERT(settings!=0);
//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);
refreshSettings(); refreshSettings();
} }
@ -70,32 +71,29 @@ FileLogger::~FileLogger() {
void FileLogger::write(const LogMessage* logMessage) { void FileLogger::write(const LogMessage* logMessage) {
// Write to the file // Try to write to the file
if (!disabled) { if (file) {
// Try to write to the 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
// 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()));
}
// Flush error messages immediately, to ensure that no important message
// gets lost when the program terinates abnormally.
if (logMessage->getType()>=QtCriticalMsg) {
file->flush();
} }
// Fall-back to the super class method, if writing failed // Check for success
if (!file) { if (file->error()) {
Logger::write(logMessage); 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);
} }
} }
@ -105,8 +103,8 @@ void FileLogger::open() {
qWarning("Name of logFile is empty"); qWarning("Name of logFile is empty");
} }
else { else {
file=new QFile(QDir::cleanPath(fileName)); file=new QFile(fileName);
if (!file->open(QIODevice::WriteOnly | 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;
} }
@ -147,8 +145,7 @@ void FileLogger::rotate() {
} }
// Backup the current logfile // Backup the current logfile
if(maxBackups>0) QFile::rename(fileName,fileName+".1");
QFile::rename(fileName,fileName+".1");
} }
@ -167,8 +164,7 @@ void FileLogger::timerEvent(QTimerEvent* event) {
// 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

@ -15,12 +15,10 @@
/** /**
Logger that uses a text file for output. Settings are read from a 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. 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> <p>
Example for the required configuration settings: Example for the configuration settings:
<code><pre> <code><pre>
disabled=false
fileName=logs/QtWebApp.log fileName=logs/QtWebApp.log
maxSize=1000000 maxSize=1000000
maxBackups=2 maxBackups=2
@ -35,20 +33,16 @@
working directory. working directory.
- maxSize is the maximum size of that file in bytes. The file will be backed up and - 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 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. 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. 0=unlimited. - maxBackups defines the number of backup files to keep. Default is 0=unlimited.
- minLevel defines the minimum level of message types to be written into the file. - 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. - msgFormat defines the decoration of log messages, see LogMessage class. Default is "{timestamp} {type} {msg}".
- timestampFormat defines the format of timestamps. - timestampFormat defines the format of timestamps, see QDateTime::toString(). Default is "yyyy-MM-dd hh:mm:ss.zzz".
- buffersize defines the size of the backtrace buffer. 0=disabled. - bufferSize defines the size of the buffer. Default is 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 set() describes how to set logger variables
@see LogMessage for a description of the message decoration. @see LogMessage for a description of the message decoration.
@see Logger for a descrition of the backtrace buffer @see Logger for a descrition of the buffer.
*/ */
class FileLogger : public Logger { class FileLogger : public Logger {
@ -62,7 +56,7 @@ public:
Settings are read from the current group, so the caller must have called settings->beginGroup(). 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 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. 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 refreshInterval Interval of checking for changed config settings in msec, or 0=disabled
@param parent Parent object @param parent Parent object
*/ */
FileLogger(QSettings* settings, const int refreshInterval=10000, QObject* parent = 0); FileLogger(QSettings* settings, const int refreshInterval=10000, QObject* parent = 0);
@ -96,9 +90,6 @@ private:
/** Configured maximum number of backup files, or 0=unlimited */ /** Configured maximum number of backup files, or 0=unlimited */
int maxBackups; int maxBackups;
/** Whether this logger is disabled */
bool disabled;
/** Pointer to the configuration settings */ /** Pointer to the configuration settings */
QSettings* settings; QSettings* settings;

View File

@ -9,7 +9,6 @@
#include <QMutex> #include <QMutex>
#include <QDateTime> #include <QDateTime>
#include <QThread> #include <QThread>
#include <QtGlobal>
Logger* Logger::defaultLogger=0; Logger* Logger::defaultLogger=0;
@ -41,7 +40,7 @@ Logger::Logger(const QString msgFormat, const QString timestampFormat, const QtM
} }
void Logger::msgHandler(const QtMsgType type, const char* message) { 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);
@ -52,33 +51,42 @@ void Logger::msgHandler(const QtMsgType type, const char* message) {
// 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); defaultLogger->log(type, message, file, function, line);
nonRecursiveMutex.unlock(); nonRecursiveMutex.unlock();
} }
else { else {
fputs(message,stderr); fputs(qPrintable(message),stderr);
fflush(stderr); fflush(stderr);
} }
// Abort the program after logging a fatal message // Abort the program after logging a fatal message
if (type>=QtFatalMsg) { if (type>=QtFatalMsg) {
//abort(); //abort();
} }
recursiveMutex.unlock(); 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() { Logger::~Logger() {
if (defaultLogger==this) { if (defaultLogger==this) {
#if QT_VERSION >= 0x050000 #if QT_VERSION >= 0x050000
qInstallMessageHandler(0); qInstallMessageHandler(0);
#else #else
qInstallMsgHandler(0); qInstallMsgHandler(0);
#endif #endif
defaultLogger=0; defaultLogger=0;
} }
} }
@ -93,9 +101,9 @@ void Logger::write(const LogMessage* logMessage) {
void Logger::installMsgHandler() { void Logger::installMsgHandler() {
defaultLogger=this; defaultLogger=this;
#if QT_VERSION >= 0x050000 #if QT_VERSION >= 0x050000
//qInstallMessageHandler(msgHandler); TODO Qt5 qInstallMessageHandler(msgHandler5);
#else #else
qInstallMsgHandler(msgHandler); qInstallMsgHandler(msgHandler4);
#endif #endif
} }
@ -126,7 +134,7 @@ void Logger::clear(const bool buffer, const bool variables) {
} }
void Logger::log(const QtMsgType type, const QString& message) { 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
@ -137,7 +145,7 @@ void Logger::log(const QtMsgType type, const QString& message) {
} }
QList<LogMessage*>* buffer=buffers.localData(); QList<LogMessage*>* buffer=buffers.localData();
// Append the decorated log message // Append the decorated log message
LogMessage* logMessage=new LogMessage(type,message,logVars.localData()); 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) {
@ -156,7 +164,7 @@ void Logger::log(const QtMsgType type, const QString& message) {
// 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()); LogMessage logMessage(type,message,logVars.localData(),file,function,line);
write(&logMessage); write(&logMessage);
} }
} }

View File

@ -23,13 +23,20 @@
variable names in the form <i>{name}</i> that are filled by values variable names in the form <i>{name}</i> that are filled by values
taken from a static thread local dictionary. taken from a static thread local dictionary.
<p> <p>
The buffer stores log messages of any level from the time before an error occurs. The logger keeps a configurable number of messages in a ring-buffer.
It can be used to provide detailed debug information when an error occurs, while A log message with a severity >= minLevel flushes the buffer,
keeping the logfile clean as long no error occurs. Using this buffer may so the stored messages get written out. If the buffer is disabled, then
reduce performance significantly. 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> <p>
The logger can be registered to handle messages from The logger can be registered to handle messages from
the static global functions qDebug(), qWarning(), qCritical() and qFatal(). the static global functions qDebug(), qWarning(), qCritical() and qFatal().
@see set() describes how to set logger variables @see set() describes how to set logger variables
@see LogMessage for a description of the message decoration. @see LogMessage for a description of the message decoration.
@warning You should prefer a derived class, for example FileLogger, @warning You should prefer a derived class, for example FileLogger,
@ -53,7 +60,7 @@ public:
Constructor. Constructor.
@param msgFormat Format of the decoration, e.g. "{timestamp} {type} thread={thread}: {msg}" @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 timestampFormat Format of timestamp, e.g. "dd.MM.yyyy hh:mm:ss.zzz"
@param minLevel Minimum type of messages that are written out. @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 bufferSize Size of the backtrace buffer, number of messages per thread. 0=disabled.
@param parent Parent object @param parent Parent object
@see LogMessage for a description of the message decoration. @see LogMessage for a description of the message decoration.
@ -68,9 +75,12 @@ public:
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);
/** /**
Installs this logger as the default message handler, so it Installs this logger as the default message handler, so it
@ -130,8 +140,35 @@ private:
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__)
*/ */
static void msgHandler(const QtMsgType type, const char* message); 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 */ /** Thread local variables to be used in log messages */
static QThreadStorage<QHash<QString,QString>*> logVars; static QThreadStorage<QHash<QString,QString>*> logVars;

View File

@ -6,9 +6,12 @@
#include "logmessage.h" #include "logmessage.h"
#include <QThread> #include <QThread>
LogMessage::LogMessage(const QtMsgType type, const QString& message, QHash<QString,QString>* logVars) { 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->function=function;
this->line=line;
timestamp=QDateTime::currentDateTime(); timestamp=QDateTime::currentDateTime();
threadId=QThread::currentThreadId(); threadId=QThread::currentThreadId();
@ -24,7 +27,7 @@ QString LogMessage::toString(const QString& msgFormat, const QString& timestampF
decorated.replace("{msg}",message); decorated.replace("{msg}",message);
if (decorated.contains("{timestamp}")) { if (decorated.contains("{timestamp}")) {
decorated.replace("{timestamp}",QDateTime::currentDateTime().toString(timestampFormat)); decorated.replace("{timestamp}",timestamp.toString(timestampFormat));
} }
QString typeNr; QString typeNr;
@ -48,8 +51,12 @@ QString LogMessage::toString(const QString& msgFormat, const QString& timestampF
decorated.replace("{type}",typeNr); decorated.replace("{type}",typeNr);
} }
decorated.replace("{file}",file);
decorated.replace("{function}",function);
decorated.replace("{line}",QString::number(line));
QString threadId; QString threadId;
threadId.setNum((quint64)QThread::currentThreadId()); //CAMBIADo unsigned int por quint64, evita error de compilación en máquinas de 64bit threadId.setNum((unsigned int)QThread::currentThreadId()); // change to (qint64) for 64bit Mac OS
decorated.replace("{thread}",threadId); decorated.replace("{thread}",threadId);
// Fill in variables // Fill in variables

View File

@ -21,7 +21,12 @@
- {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 (only useable in msgFormat)
- {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.
*/ */
class LogMessage class LogMessage
@ -35,14 +40,17 @@ public:
@param type Type of the message @param type Type of the message
@param message Message text @param message Message text
@param logVars Logger variables, 0 is allowed @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); 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. Returns the log message as decorated string.
@param msgFormat Format of the decoration. May contain variables and static text, @param msgFormat Format of the decoration. May contain variables and static text,
e.g. "{timestamp} {type} thread={thread}: {msg}" e.g. "{timestamp} {type} thread={thread}: {msg}".
@param timestampFormat Format of timestamp, e.g. "dd.MM.yyyy hh:mm:ss.zzz" @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 @see QDatetime for a description of the timestamp format pattern
*/ */
QString toString(const QString& msgFormat, const QString& timestampFormat) const; QString toString(const QString& msgFormat, const QString& timestampFormat) const;
@ -69,6 +77,15 @@ private:
/** Message text */ /** Message text */
QString message; 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;
}; };
#endif // LOGMESSAGE_H #endif // LOGMESSAGE_H

View File

@ -13,6 +13,7 @@ Template::Template(QString source, QString sourceName)
} }
Template::Template(QFile& file, QTextCodec* textCodec) { Template::Template(QFile& file, QTextCodec* textCodec) {
this->warnings=false;
sourceName=QFileInfo(file.fileName()).baseName(); sourceName=QFileInfo(file.fileName()).baseName();
if (!file.isOpen()) { if (!file.isOpen()) {
file.open(QFile::ReadOnly | QFile::Text); file.open(QFile::ReadOnly | QFile::Text);

View File

@ -9,6 +9,7 @@
#include <QStringList> #include <QStringList>
#include <QDir> #include <QDir>
#include <QSet> #include <QSet>
#include <QApplication>
TemplateLoader::TemplateLoader(QSettings* settings, QObject* parent) TemplateLoader::TemplateLoader(QSettings* settings, QObject* parent)
: QObject(parent) : QObject(parent)
@ -21,16 +22,16 @@ TemplateLoader::TemplateLoader(QSettings* settings, QObject* parent)
if (QDir::isRelativePath(templatePath)) if (QDir::isRelativePath(templatePath))
#endif #endif
{ {
QFileInfo configFile(settings->fileName()); QFileInfo configFile(QApplication::applicationDirPath());
templatePath=QFileInfo(configFile.absolutePath(),templatePath).absoluteFilePath(); templatePath=QFileInfo(QApplication::applicationDirPath(),templatePath).absoluteFilePath();
} }
fileNameSuffix=settings->value("suffix",".tpl").toString(); fileNameSuffix=settings->value("suffix",".tpl").toString();
QString encoding=settings->value("encoding","UTF-8").toString(); QString encoding=settings->value("encoding").toString();
if (encoding.isEmpty()) { if (encoding.isEmpty()) {
textCodec=QTextCodec::codecForLocale(); textCodec=QTextCodec::codecForLocale();
} }
else { else {
textCodec=QTextCodec::codecForName(encoding.toLatin1()); textCodec=QTextCodec::codecForName(encoding.toLocal8Bit());
} }
qDebug("TemplateLoader: path=%s, codec=%s",qPrintable(templatePath),textCodec->name().data()); qDebug("TemplateLoader: path=%s, codec=%s",qPrintable(templatePath),textCodec->name().data());
} }

View File

@ -9,6 +9,9 @@
#include "httplistener.h" #include "httplistener.h"
#include "requestmapper.h" #include "requestmapper.h"
#include "staticfilecontroller.h" #include "staticfilecontroller.h"
#include "yacreader_global.h"
#include <QDir> #include <QDir>
#include <QApplication> #include <QApplication>
@ -26,14 +29,14 @@ void Startup::start() {
QCoreApplication* app = QApplication::instance(); QCoreApplication* app = QApplication::instance();
app->setApplicationName(APPNAME); app->setApplicationName(APPNAME);
app->setOrganizationName(ORGANISATION); app->setOrganizationName(ORGANISATION);
QString configFileName=Static::getConfigDir()+"/"+QCoreApplication::applicationName()+".ini"; QString configFileName=YACReader::getSettingsPath()+"/"+QCoreApplication::applicationName()+".ini";
// Configure logging into files // Configure logging into files
QSettings* mainLogSettings=new QSettings(configFileName,QSettings::IniFormat,app); QSettings* mainLogSettings=new QSettings(configFileName,QSettings::IniFormat,app);
mainLogSettings->beginGroup("mainLogFile"); mainLogSettings->beginGroup("mainLogFile");
QSettings* debugLogSettings=new QSettings(configFileName,QSettings::IniFormat,app); //QSettings* debugLogSettings=new QSettings(configFileName,QSettings::IniFormat,app);
debugLogSettings->beginGroup("debugLogFile"); //debugLogSettings->beginGroup("debugLogFile");
Logger* logger=new DualFileLogger(mainLogSettings,debugLogSettings,10000,app); Logger* logger=new FileLogger(mainLogSettings,10000,app);
logger->installMsgHandler(); logger->installMsgHandler();
// Configure template loader and cache // Configure template loader and cache