mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 13:58:51 +02:00
Merge pull request #5285 from jherico/homer
Move log file writing to a separate thread
This commit is contained in:
commit
489a8b4b3d
6 changed files with 129 additions and 25 deletions
|
@ -24,7 +24,7 @@ public:
|
||||||
inline bool extraDebugging() { return _extraDebugging; }
|
inline bool extraDebugging() { return _extraDebugging; }
|
||||||
inline void setExtraDebugging(bool debugging) { _extraDebugging = debugging; }
|
inline void setExtraDebugging(bool debugging) { _extraDebugging = debugging; }
|
||||||
|
|
||||||
virtual void addMessage(QString) = 0;
|
virtual void addMessage(const QString&) = 0;
|
||||||
virtual QString getLogData() = 0;
|
virtual QString getLogData() = 0;
|
||||||
virtual void locateLog() = 0;
|
virtual void locateLog() = 0;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ signals:
|
||||||
void logReceived(QString message);
|
void logReceived(QString message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _extraDebugging;
|
bool _extraDebugging{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AbstractLoggerInterface_h
|
#endif // hifi_AbstractLoggerInterface_h
|
||||||
|
|
|
@ -21,11 +21,34 @@ const QString FILENAME_FORMAT = "hifi-log_%1_%2.txt";
|
||||||
const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss";
|
const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss";
|
||||||
const QString LOGS_DIRECTORY = "Logs";
|
const QString LOGS_DIRECTORY = "Logs";
|
||||||
|
|
||||||
|
class FilePersistThread : public GenericQueueThread < QString > {
|
||||||
|
public:
|
||||||
|
FilePersistThread(const FileLogger& logger) : _logger(logger) {
|
||||||
|
setObjectName("LogFileWriter");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool processQueueItems(const Queue& messages) {
|
||||||
|
QFile file(_logger._fileName);
|
||||||
|
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
|
||||||
|
QTextStream out(&file);
|
||||||
|
foreach(const QString& message, messages) {
|
||||||
|
out << message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
const FileLogger& _logger;
|
||||||
|
};
|
||||||
|
|
||||||
|
static FilePersistThread* _persistThreadInstance;
|
||||||
|
|
||||||
FileLogger::FileLogger(QObject* parent) :
|
FileLogger::FileLogger(QObject* parent) :
|
||||||
AbstractLoggerInterface(parent),
|
AbstractLoggerInterface(parent)
|
||||||
_logData("")
|
|
||||||
{
|
{
|
||||||
setExtraDebugging(false);
|
_persistThreadInstance = new FilePersistThread(*this);
|
||||||
|
_persistThreadInstance->initialize(true, QThread::LowestPriority);
|
||||||
|
|
||||||
_fileName = FileUtils::standardPath(LOGS_DIRECTORY);
|
_fileName = FileUtils::standardPath(LOGS_DIRECTORY);
|
||||||
QHostAddress clientAddress = getLocalAddress();
|
QHostAddress clientAddress = getLocalAddress();
|
||||||
|
@ -33,18 +56,24 @@ FileLogger::FileLogger(QObject* parent) :
|
||||||
_fileName.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT)));
|
_fileName.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileLogger::addMessage(QString message) {
|
FileLogger::~FileLogger() {
|
||||||
QMutexLocker locker(&_mutex);
|
_persistThreadInstance->terminate();
|
||||||
emit logReceived(message);
|
}
|
||||||
_logData += message;
|
|
||||||
|
|
||||||
QFile file(_fileName);
|
void FileLogger::addMessage(const QString& message) {
|
||||||
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
|
_persistThreadInstance->queueItem(message);
|
||||||
QTextStream out(&file);
|
emit logReceived(message);
|
||||||
out << message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileLogger::locateLog() {
|
void FileLogger::locateLog() {
|
||||||
FileUtils::locateFile(_fileName);
|
FileUtils::locateFile(_fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString FileLogger::getLogData() {
|
||||||
|
QString result;
|
||||||
|
QFile f(_fileName);
|
||||||
|
if (f.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
|
result = QTextStream(&f).readAll();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -13,23 +13,24 @@
|
||||||
#define hifi_FileLogger_h
|
#define hifi_FileLogger_h
|
||||||
|
|
||||||
#include "AbstractLoggerInterface.h"
|
#include "AbstractLoggerInterface.h"
|
||||||
#include <QMutex>
|
#include <GenericQueueThread.h>
|
||||||
|
|
||||||
class FileLogger : public AbstractLoggerInterface {
|
class FileLogger : public AbstractLoggerInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileLogger(QObject* parent = NULL);
|
FileLogger(QObject* parent = NULL);
|
||||||
|
virtual ~FileLogger();
|
||||||
|
|
||||||
virtual void addMessage(QString);
|
virtual void addMessage(const QString&) override;
|
||||||
virtual QString getLogData() { return _logData; }
|
virtual QString getLogData() override;
|
||||||
virtual void locateLog();
|
virtual void locateLog() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _logData;
|
|
||||||
QString _fileName;
|
QString _fileName;
|
||||||
QMutex _mutex;
|
friend class FilePersistThread;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // hifi_FileLogger_h
|
#endif // hifi_FileLogger_h
|
||||||
|
|
72
libraries/shared/src/GenericQueueThread.h
Normal file
72
libraries/shared/src/GenericQueueThread.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis 2015/07/08.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_GenericQueueThread_h
|
||||||
|
#define hifi_GenericQueueThread_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <QQueue>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
|
||||||
|
#include "GenericThread.h"
|
||||||
|
#include "NumericalConstants.h"
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class GenericQueueThread : public GenericThread {
|
||||||
|
public:
|
||||||
|
using Queue = QQueue<T>;
|
||||||
|
GenericQueueThread(QObject* parent = nullptr)
|
||||||
|
: GenericThread(parent) {}
|
||||||
|
|
||||||
|
virtual ~GenericQueueThread() {}
|
||||||
|
|
||||||
|
void queueItem(const T& t) {
|
||||||
|
lock();
|
||||||
|
queueItemInternal(t);
|
||||||
|
unlock();
|
||||||
|
_hasItems.wakeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void queueItemInternal(const T& t) {
|
||||||
|
_items.push_back(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint32_t getMaxWait() {
|
||||||
|
return MSECS_PER_SECOND;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool process() {
|
||||||
|
if (!_items.size()) {
|
||||||
|
_hasItemsMutex.lock();
|
||||||
|
_hasItems.wait(&_hasItemsMutex, getMaxWait());
|
||||||
|
_hasItemsMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_items.size()) {
|
||||||
|
return isStillRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
Queue processItems;
|
||||||
|
lock();
|
||||||
|
processItems.swap(_items);
|
||||||
|
unlock();
|
||||||
|
return processQueueItems(processItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool processQueueItems(const Queue& items) = 0;
|
||||||
|
|
||||||
|
Queue _items;
|
||||||
|
QWaitCondition _hasItems;
|
||||||
|
QMutex _hasItemsMutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_GenericQueueThread_h
|
|
@ -14,7 +14,8 @@
|
||||||
#include "GenericThread.h"
|
#include "GenericThread.h"
|
||||||
|
|
||||||
|
|
||||||
GenericThread::GenericThread() :
|
GenericThread::GenericThread(QObject* parent) :
|
||||||
|
QObject(parent),
|
||||||
_stopThread(false),
|
_stopThread(false),
|
||||||
_isThreaded(false) // assume non-threaded, must call initialize()
|
_isThreaded(false) // assume non-threaded, must call initialize()
|
||||||
{
|
{
|
||||||
|
@ -27,13 +28,14 @@ GenericThread::~GenericThread() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericThread::initialize(bool isThreaded) {
|
void GenericThread::initialize(bool isThreaded, QThread::Priority priority) {
|
||||||
_isThreaded = isThreaded;
|
_isThreaded = isThreaded;
|
||||||
if (_isThreaded) {
|
if (_isThreaded) {
|
||||||
_thread = new QThread(this);
|
_thread = new QThread(this);
|
||||||
|
|
||||||
// match the thread name to our object name
|
// match the thread name to our object name
|
||||||
_thread->setObjectName(objectName());
|
_thread->setObjectName(objectName());
|
||||||
|
_thread->setPriority(priority);
|
||||||
|
|
||||||
// when the worker thread is started, call our engine's run..
|
// when the worker thread is started, call our engine's run..
|
||||||
connect(_thread, SIGNAL(started()), this, SLOT(threadRoutine()));
|
connect(_thread, SIGNAL(started()), this, SLOT(threadRoutine()));
|
||||||
|
|
|
@ -23,12 +23,12 @@
|
||||||
class GenericThread : public QObject {
|
class GenericThread : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
GenericThread();
|
GenericThread(QObject* parent = nullptr);
|
||||||
virtual ~GenericThread();
|
virtual ~GenericThread();
|
||||||
|
|
||||||
/// Call to start the thread.
|
/// Call to start the thread.
|
||||||
/// \param bool isThreaded true by default. false for non-threaded mode and caller must call threadRoutine() regularly.
|
/// \param bool isThreaded true by default. false for non-threaded mode and caller must call threadRoutine() regularly.
|
||||||
void initialize(bool isThreaded = true);
|
void initialize(bool isThreaded = true, QThread::Priority priority = QThread::NormalPriority);
|
||||||
|
|
||||||
/// Call to stop the thread
|
/// Call to stop the thread
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
Loading…
Reference in a new issue