forked from quickshell/quickshell
core/log: add filesystem logger
This commit is contained in:
parent
46f48f2f87
commit
6bf4826ae7
9 changed files with 299 additions and 53 deletions
|
@ -38,6 +38,8 @@ qt_add_library(quickshell-core STATIC
|
|||
qsmenuanchor.cpp
|
||||
clock.cpp
|
||||
logging.cpp
|
||||
paths.cpp
|
||||
filelogger.cpp
|
||||
)
|
||||
|
||||
set_source_files_properties(main.cpp PROPERTIES COMPILE_DEFINITIONS GIT_REVISION="${GIT_REVISION}")
|
||||
|
|
60
src/core/filelogger.cpp
Normal file
60
src/core/filelogger.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include "filelogger.hpp"
|
||||
|
||||
#include <qlogging.h>
|
||||
#include <qloggingcategory.h>
|
||||
#include <qnamespace.h>
|
||||
#include <qobject.h>
|
||||
#include <qobjectdefs.h>
|
||||
#include <qtextstream.h>
|
||||
|
||||
#include "filelogger_p.hpp"
|
||||
#include "logging.hpp"
|
||||
#include "paths.hpp"
|
||||
|
||||
Q_LOGGING_CATEGORY(logLogger, "quickshell.logger", QtWarningMsg);
|
||||
|
||||
void FileLoggerThread::init() {
|
||||
auto* thread = new FileLoggerThread();
|
||||
auto* logger = new FileLogger();
|
||||
logger->moveToThread(thread);
|
||||
thread->start();
|
||||
QMetaObject::invokeMethod(logger, "init", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
void FileLogger::init() {
|
||||
qCDebug(logLogger) << "Initializing filesystem logger...";
|
||||
auto* runDir = QsPaths::instance()->instanceRunDir();
|
||||
|
||||
if (!runDir) {
|
||||
qCCritical(logLogger
|
||||
) << "Could not start filesystem logger as the runtime directory could not be created.";
|
||||
return;
|
||||
}
|
||||
|
||||
auto path = runDir->filePath("log.log");
|
||||
auto* file = new QFile(path);
|
||||
|
||||
if (!file->open(QFile::WriteOnly | QFile::Truncate)) {
|
||||
qCCritical(logLogger
|
||||
) << "Could not start filesystem logger as the log file could not be created:"
|
||||
<< path;
|
||||
return;
|
||||
}
|
||||
|
||||
this->fileStream.setDevice(file);
|
||||
|
||||
QObject::connect(
|
||||
LogManager::instance(),
|
||||
&LogManager::logMessage,
|
||||
this,
|
||||
&FileLogger::onMessage,
|
||||
Qt::QueuedConnection
|
||||
);
|
||||
|
||||
qDebug(logLogger) << "Initialized filesystem logger";
|
||||
}
|
||||
|
||||
void FileLogger::onMessage(const LogMessage& msg) {
|
||||
LogManager::formatMessage(this->fileStream, msg, false);
|
||||
this->fileStream << Qt::endl;
|
||||
}
|
13
src/core/filelogger.hpp
Normal file
13
src/core/filelogger.hpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <qthread.h>
|
||||
#include <qtmetamacros.h>
|
||||
class FileLoggerThread: public QThread {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
static void init();
|
||||
|
||||
private:
|
||||
explicit FileLoggerThread() = default;
|
||||
};
|
24
src/core/filelogger_p.hpp
Normal file
24
src/core/filelogger_p.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <qfile.h>
|
||||
#include <qobject.h>
|
||||
#include <qtextstream.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
#include "logging.hpp"
|
||||
|
||||
class FileLogger: public QObject {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
explicit FileLogger() = default;
|
||||
|
||||
public slots:
|
||||
void init();
|
||||
|
||||
private slots:
|
||||
void onMessage(const LogMessage& msg);
|
||||
|
||||
private:
|
||||
QTextStream fileStream;
|
||||
};
|
|
@ -5,70 +5,61 @@
|
|||
#include <qlogging.h>
|
||||
#include <qstring.h>
|
||||
#include <qtenvironmentvariables.h>
|
||||
#include <qtextstream.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
namespace {
|
||||
LogManager::LogManager(): colorLogs(qEnvironmentVariableIsEmpty("NO_COLOR")), stdoutStream(stdout) {
|
||||
qInstallMessageHandler(&LogManager::messageHandler);
|
||||
}
|
||||
|
||||
bool COLOR_LOGS = false; // NOLINT
|
||||
|
||||
void formatMessage(
|
||||
void LogManager::messageHandler(
|
||||
QtMsgType type,
|
||||
const QMessageLogContext& context,
|
||||
const QString& msg,
|
||||
bool color
|
||||
const QString& msg
|
||||
) {
|
||||
const auto* typeString = "[log error]";
|
||||
auto message = LogMessage(type, context.category, msg.toUtf8());
|
||||
|
||||
auto* self = LogManager::instance();
|
||||
|
||||
LogManager::formatMessage(self->stdoutStream, message, self->colorLogs);
|
||||
self->stdoutStream << Qt::endl;
|
||||
|
||||
emit self->logMessage(message);
|
||||
}
|
||||
|
||||
LogManager* LogManager::instance() {
|
||||
static auto* instance = new LogManager(); // NOLINT
|
||||
return instance;
|
||||
}
|
||||
|
||||
void LogManager::formatMessage(QTextStream& stream, const LogMessage& msg, bool color) {
|
||||
if (color) {
|
||||
switch (type) {
|
||||
case QtDebugMsg: typeString = "\033[34m DEBUG"; break;
|
||||
case QtInfoMsg: typeString = "\033[32m INFO"; break;
|
||||
case QtWarningMsg: typeString = "\033[33m WARN"; break;
|
||||
case QtCriticalMsg: typeString = "\033[31m ERROR"; break;
|
||||
case QtFatalMsg: typeString = "\033[31m FATAL"; break;
|
||||
switch (msg.type) {
|
||||
case QtDebugMsg: stream << "\033[34m DEBUG"; break;
|
||||
case QtInfoMsg: stream << "\033[32m INFO"; break;
|
||||
case QtWarningMsg: stream << "\033[33m WARN"; break;
|
||||
case QtCriticalMsg: stream << "\033[31m ERROR"; break;
|
||||
case QtFatalMsg: stream << "\033[31m FATAL"; break;
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
case QtDebugMsg: typeString = " DEBUG"; break;
|
||||
case QtInfoMsg: typeString = " INFO"; break;
|
||||
case QtWarningMsg: typeString = " WARN"; break;
|
||||
case QtCriticalMsg: typeString = " ERROR"; break;
|
||||
case QtFatalMsg: typeString = " FATAL"; break;
|
||||
switch (msg.type) {
|
||||
case QtDebugMsg: stream << " DEBUG"; break;
|
||||
case QtInfoMsg: stream << " INFO"; break;
|
||||
case QtWarningMsg: stream << " WARN"; break;
|
||||
case QtCriticalMsg: stream << " ERROR"; break;
|
||||
case QtFatalMsg: stream << " FATAL"; break;
|
||||
}
|
||||
}
|
||||
|
||||
const auto isDefault = strcmp(context.category, "default") == 0;
|
||||
const auto isDefault = strcmp(msg.category, "default") == 0;
|
||||
|
||||
const char* format = nullptr;
|
||||
if (color && !isDefault && msg.type != QtFatalMsg) stream << "\033[97m";
|
||||
|
||||
if (color) {
|
||||
if (type == QtFatalMsg) {
|
||||
if (isDefault) format = "%s: %s\033[0m\n";
|
||||
else format = "%s %s: %s\033[0m\n";
|
||||
} else {
|
||||
if (isDefault) format = "%s\033[0m: %s\n";
|
||||
else format = "%s \033[97m%s\033[0m: %s\n";
|
||||
}
|
||||
} else {
|
||||
if (isDefault) format = "%s: %s\n";
|
||||
else format = "%s %s: %s\n";
|
||||
if (!isDefault) {
|
||||
stream << ' ' << msg.category;
|
||||
}
|
||||
|
||||
if (isDefault) {
|
||||
printf(format, typeString, msg.toStdString().c_str());
|
||||
} else {
|
||||
printf(format, typeString, context.category, msg.toStdString().c_str());
|
||||
}
|
||||
if (color && msg.type != QtFatalMsg) stream << "\033[0m";
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
|
||||
formatMessage(type, context, msg, COLOR_LOGS);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void LogManager::setup() {
|
||||
COLOR_LOGS = qEnvironmentVariableIsEmpty("NO_COLOR");
|
||||
qInstallMessageHandler(&messageHandler);
|
||||
stream << ": " << msg.body;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
class LogManager {
|
||||
public:
|
||||
static void setup();
|
||||
#include <utility>
|
||||
|
||||
#include <qlogging.h>
|
||||
#include <qobject.h>
|
||||
#include <qtextstream.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
struct LogMessage {
|
||||
explicit LogMessage(QtMsgType type, const char* category, QByteArray body)
|
||||
: type(type)
|
||||
, category(category)
|
||||
, body(std::move(body)) {}
|
||||
|
||||
QtMsgType type;
|
||||
const char* category;
|
||||
QByteArray body;
|
||||
};
|
||||
|
||||
class LogManager: public QObject {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
static LogManager* instance();
|
||||
|
||||
static void formatMessage(QTextStream& stream, const LogMessage& msg, bool color);
|
||||
|
||||
signals:
|
||||
void logMessage(LogMessage msg);
|
||||
|
||||
private:
|
||||
explicit LogManager();
|
||||
static void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
||||
|
||||
bool colorLogs;
|
||||
QTextStream stdoutStream;
|
||||
};
|
||||
|
|
|
@ -22,12 +22,14 @@
|
|||
#include <qtextstream.h>
|
||||
#include <qtpreprocessorsupport.h>
|
||||
|
||||
#include "filelogger.hpp"
|
||||
#include "logging.hpp"
|
||||
#include "paths.hpp"
|
||||
#include "plugin.hpp"
|
||||
#include "rootwrapper.hpp"
|
||||
|
||||
int qs_main(int argc, char** argv) {
|
||||
LogManager::setup();
|
||||
LogManager::instance();
|
||||
QString configFilePath;
|
||||
QString workingDirectory;
|
||||
|
||||
|
@ -340,6 +342,8 @@ int qs_main(int argc, char** argv) {
|
|||
qputenv(var.toUtf8(), val.toUtf8());
|
||||
}
|
||||
|
||||
QsPaths::init(shellId);
|
||||
|
||||
// While the simple animation driver can lead to better animations in some cases,
|
||||
// it also can cause excessive repainting at excessively high framerates which can
|
||||
// lead to noticeable amounts of gpu usage, including overheating on some systems.
|
||||
|
@ -386,6 +390,8 @@ int qs_main(int argc, char** argv) {
|
|||
app = new QGuiApplication(argc, argv);
|
||||
}
|
||||
|
||||
FileLoggerThread::init();
|
||||
|
||||
if (debugPort != -1) {
|
||||
QQmlDebuggingEnabler::enableDebugging(true);
|
||||
auto wait = waitForDebug ? QQmlDebuggingEnabler::WaitForClient
|
||||
|
|
91
src/core/paths.cpp
Normal file
91
src/core/paths.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
#include "paths.hpp"
|
||||
#include <utility>
|
||||
|
||||
#include <qdatetime.h>
|
||||
#include <qdir.h>
|
||||
#include <qlogging.h>
|
||||
#include <qloggingcategory.h>
|
||||
#include <qstandardpaths.h>
|
||||
#include <qtenvironmentvariables.h>
|
||||
#include <unistd.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(logPaths, "quickshell.paths", QtWarningMsg);
|
||||
|
||||
QsPaths* QsPaths::instance() {
|
||||
static auto* instance = new QsPaths(); // NOLINT
|
||||
return instance;
|
||||
}
|
||||
|
||||
void QsPaths::init(QString shellId) { QsPaths::instance()->shellId = std::move(shellId); }
|
||||
|
||||
QDir* QsPaths::cacheDir() {
|
||||
if (this->cacheState == DirState::Unknown) {
|
||||
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
|
||||
dir = QDir(dir.filePath("quickshell"));
|
||||
dir = QDir(dir.filePath(this->shellId));
|
||||
this->mCacheDir = dir;
|
||||
|
||||
qCDebug(logPaths) << "Initialized cache path:" << dir.path();
|
||||
|
||||
if (!dir.mkpath(".")) {
|
||||
qCCritical(logPaths) << "Cannot create cache directory at" << dir.path();
|
||||
|
||||
this->cacheState = DirState::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->cacheState == DirState::Failed) return nullptr;
|
||||
else return &this->mCacheDir;
|
||||
}
|
||||
|
||||
QDir* QsPaths::runDir() {
|
||||
if (this->runState == DirState::Unknown) {
|
||||
auto runtimeDir = qEnvironmentVariable("XDG_RUNTIME_DIR");
|
||||
if (runtimeDir.isEmpty()) {
|
||||
runtimeDir = QString("/run/user/$1").arg(getuid());
|
||||
qCInfo(logPaths) << "XDG_RUNTIME_DIR was not set, defaulting to" << runtimeDir;
|
||||
}
|
||||
|
||||
auto dir = QDir(runtimeDir);
|
||||
dir = QDir(dir.filePath("quickshell"));
|
||||
dir = QDir(dir.filePath(this->shellId));
|
||||
this->mRunDir = dir;
|
||||
|
||||
qCDebug(logPaths) << "Initialized runtime path:" << dir.path();
|
||||
|
||||
if (!dir.mkpath(".")) {
|
||||
qCCritical(logPaths) << "Cannot create runtime directory at" << dir.path();
|
||||
|
||||
this->runState = DirState::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->runState == DirState::Failed) return nullptr;
|
||||
else return &this->mRunDir;
|
||||
}
|
||||
|
||||
QDir* QsPaths::instanceRunDir() {
|
||||
if (this->instanceRunState == DirState::Unknown) {
|
||||
auto* runtimeDir = this->runDir();
|
||||
|
||||
if (!runtimeDir) {
|
||||
qCCritical(logPaths) << "Cannot create instance runtime directory as main runtim directory "
|
||||
"could not be created.";
|
||||
this->instanceRunState = DirState::Failed;
|
||||
} else {
|
||||
this->mInstanceRunDir =
|
||||
runtimeDir->filePath(QString("run-%1").arg(QDateTime::currentMSecsSinceEpoch()));
|
||||
|
||||
qCDebug(logPaths) << "Initialized instance runtime path:" << this->mInstanceRunDir.path();
|
||||
|
||||
if (!this->mInstanceRunDir.mkpath(".")) {
|
||||
qCCritical(logPaths) << "Cannot create instance runtime directory at"
|
||||
<< this->mInstanceRunDir.path();
|
||||
this->instanceRunState = DirState::Failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->runState == DirState::Failed) return nullptr;
|
||||
else return &this->mInstanceRunDir;
|
||||
}
|
27
src/core/paths.hpp
Normal file
27
src/core/paths.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
#include <qdir.h>
|
||||
|
||||
class QsPaths {
|
||||
public:
|
||||
static QsPaths* instance();
|
||||
static void init(QString shellId);
|
||||
|
||||
QDir* cacheDir();
|
||||
QDir* runDir();
|
||||
QDir* instanceRunDir();
|
||||
|
||||
private:
|
||||
enum class DirState {
|
||||
Unknown = 0,
|
||||
Ready = 1,
|
||||
Failed = 2,
|
||||
};
|
||||
|
||||
QString shellId;
|
||||
QDir mCacheDir;
|
||||
QDir mRunDir;
|
||||
QDir mInstanceRunDir;
|
||||
DirState cacheState = DirState::Unknown;
|
||||
DirState runState = DirState::Unknown;
|
||||
DirState instanceRunState = DirState::Unknown;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue