diff options
Diffstat (limited to 'logworker.cpp')
| -rw-r--r-- | logworker.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/logworker.cpp b/logworker.cpp new file mode 100644 index 0000000..b165e4c --- /dev/null +++ b/logworker.cpp @@ -0,0 +1,273 @@ +#include "logworker.h" + +// qt +#include <QFile> +#include <QMetaEnum> +#include <QMutex> + +// cpp +#include <iostream> + +// goodies +#include "singleton.h" + +#define REGISTER_QT_MSG_TYPE(type) \ + {QtMsgType::type, QString(#type).replace("Qt", "").replace("Msg", "")} + +namespace goodies +{ + +// TODO: to avoid errors replace me via magic_enum lib or any other compile-time +// stuff when qt-distributed mingw will support it +static QHash<QtMsgType, QString> qtMsgTypes = { + REGISTER_QT_MSG_TYPE(QtDebugMsg), + REGISTER_QT_MSG_TYPE(QtWarningMsg), + REGISTER_QT_MSG_TYPE(QtCriticalMsg), + REGISTER_QT_MSG_TYPE(QtFatalMsg), + REGISTER_QT_MSG_TYPE(QtInfoMsg) +}; + +QString appLogFileName() +{ + QString path = + QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + + QDir::separator() + "logs"; + + QDir dir(path); + + if (!dir.exists()) + { + if (!dir.mkpath(path)) + { + // we'll get recursion here by using qWarning or some other + // QMessageLogger + std::cerr << "cannot create dir: " << path.toStdString() + << std::endl; + } + } + + QString filename = + QDateTime::currentDateTime().toString("yyyy.MM.dd_hh.mm.ss.zzz") + + ".log"; + + return path + QDir::separator() + filename; +} + +void myMessageHandler( + QtMsgType type, + const QMessageLogContext& context, + const QString& msg +) +{ + goodies::defaultMessageHandler(type, context, msg); + // std::cout << msg.toStdString() << std::endl; + SINGLETON(LogWorker)->writeMessage(type, context, msg); +} + +LogMsg::LogMsg( + QDateTime dateTime, + MessageType messageType, + QString message, + QObject* parent +) + : G_Object(parent) + , INIT_FIELD(dateTime) + , INIT_FIELD(messageType) + , INIT_FIELD(message) +{ +} + +LogWorker::LogWorker(const QString filepath) + : QAbstractListModel(nullptr) + , INIT_FIELD(filepath) + , m_file(filepath) + , m_fileStream(&m_file) +{ + QMutexLocker l(&m_mtx); + + auto onIsLoggingEnabledChanged = + [&]() { + if (get_isLoggingEnabled()) + { + if (!m_file.open(QFile::ReadWrite | QFile::Append)) + { + qWarning() + << tr("cannot open log file for reading and writing: ") + << m_file.fileName(); + set_isLoggingEnabled(false); + return; + } + + qDebug() << "log file opened reading and writing"; + } + else + { + if (!m_file.open(QFile::ReadOnly)) + { + qWarning() << tr("cannot open log file for reading: ") + << m_file.fileName(); + } + + qDebug() << "log file opened for reading"; + } + }; + + connect( + this, + qOverload<>(&LogWorker::isLoggingEnabledChanged), + onIsLoggingEnabledChanged + ); + onIsLoggingEnabledChanged(); +} + +LogWorker::~LogWorker() +{ + QMutexLocker l(&m_mtx); +} + +QString LogWorker::filepath() const +{ + return m_filepath; +} + +void LogWorker::initialize(QApplication& app) +{ + // LogWorker uses app info to open log file + Q_UNUSED(app) + SINGLETON(LogWorker); + goodies::defaultMessageHandler = qInstallMessageHandler(myMessageHandler); +} + +// LogWorker &LogWorker::operator<<(const QString &msg) +//{ +// QMutexLocker l(&m_mtx); + +// if(!m_file.isOpen()) +// return *this; + +// auto date = +// QDateTime::currentDateTime().toString("yyyy.MM.dd_hh.mm.ss.zzz"); + +// auto m = date + ": " + msg; + +// m_fileStream << m << Qt::endl << Qt::flush; +// beginInsertRows(QModelIndex(), m_messages.count(), m_messages.count()); +// m_messages << m; +// endInsertRows(); + +// auto delta = m_messages.count() - get_maxLinesCount(); + +// if(get_maxLinesCount() > 0 && delta > 0) +// { +// beginRemoveRows(QModelIndex(), 0, delta - 1); +// m_messages.erase(m_messages.begin(), +// m_messages.begin() + delta); +// endRemoveRows(); +// } + +// return *this; +//} + +// void LogWorker::writeMessage(QString msg) +//{ +// (*this) << msg; +// } + +void LogWorker::writeMessage( + QtMsgType type, + const QMessageLogContext& context, + const QString& msg +) +{ + QMutexLocker l(&m_mtx); + + // extract filename from filepath (not tested on windows \\\\\\\ ) + const char* file = context.file ? FILENAME(context.file) : ""; + // convert QtSomethingMsg to Something + // auto typeName = + // QString::fromStdString(std::string(magic_enum::enum_name(type))) + // .replace("Qt", "").replace("Msg", ""); + auto typeName = qtMsgTypes[type]; + auto newLineOrSpace = msg.contains("\n") ? "\n" : " "; + + if (!m_file.isOpen()) + return; + + // auto date = + // QDateTime::currentDateTime().toString("yyyy.MM.dd_hh.mm.ss.zzz"); + auto dt = QDateTime::currentDateTime(); + + auto m = QString("%1:%2: %3: %4%5") + .arg(file) + .arg(context.line) + .arg(typeName) + .arg(newLineOrSpace) + .arg(msg); + + auto full_m = dt.toString(Qt::ISODateWithMs) + ": " + m; + + m_fileStream << full_m << Qt::endl << Qt::flush; + + beginInsertRows(QModelIndex(), m_messages.count(), m_messages.count()); + m_messages << LogMsg(dt, LogMsg::MessageType(type), msg); + endInsertRows(); + + auto delta = m_messages.count() - get_maxLinesCount(); + + if (get_maxLinesCount() > 0 && delta > 0) + { + beginRemoveRows(QModelIndex(), 0, delta - 1); + m_messages.erase(m_messages.begin(), m_messages.begin() + delta); + endRemoveRows(); + } + + // writeMessage(QString("%1:%2: %3:%4%5") + // .arg(file) + // .arg(context.line) + // .arg(typeName) + // .arg(newLineOrSpace) + // .arg(msg)); +} + +int LogWorker::rowCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent) + + return m_messages.count(); +} + +QVariant LogWorker::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + // std::cout << Q_FUNC_INFO << std::endl; + if (role >= Qt::UserRole) + { + auto m = m_messages.at(index.row()); + + switch (role) + { + case Date: + return m.get_dateTime().toUTC(); + break; + case MsgType: + return m.get_messageType(); + break; + case Msg: + return m.get_message(); + break; + default: + break; + } + return m_messages.at(index.row()).get_message(); + } + + return QVariant(); +} + +LogWorker::LogWorker(const LogWorker& other) +{ + Q_ASSERT_X(false, Q_FUNC_INFO, "don't call me"); +} +} // namespace goodies |
