refactor: 日志文件直接存整个软件的日志

This commit is contained in:
Chenx Dust
2026-08-03 22:25:32 +08:00
parent 05bb43cc76
commit dccb7a2874
14 changed files with 196 additions and 167 deletions

View File

@@ -53,7 +53,7 @@ set(SOURCE_FILES
infrastructure/coreprocess/coreoutputbuffer.cpp infrastructure/coreprocess/coreoutputbuffer.cpp
infrastructure/coreprocess/coreoutputparser.cpp infrastructure/coreprocess/coreoutputparser.cpp
core/connectionsessionstate.cpp core/connectionsessionstate.cpp
infrastructure/logging/corelogfile.cpp infrastructure/logging/applicationlogfile.cpp
infrastructure/platform/autostart.cpp infrastructure/platform/autostart.cpp
infrastructure/platform/privileges.cpp infrastructure/platform/privileges.cpp
infrastructure/settings/settingsprofileloader.cpp infrastructure/settings/settingsprofileloader.cpp
@@ -143,13 +143,13 @@ if(BUILD_TESTING)
target_link_libraries(applicationlogger_test Qt::Core) target_link_libraries(applicationlogger_test Qt::Core)
add_test(NAME applicationlogger_test COMMAND applicationlogger_test) add_test(NAME applicationlogger_test COMMAND applicationlogger_test)
add_executable(corelogfile_test add_executable(applicationlogfile_test
tests/corelogfile_test.cpp tests/applicationlogfile_test.cpp
infrastructure/logging/corelogfile.cpp infrastructure/logging/applicationlogfile.cpp
) )
target_include_directories(corelogfile_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(applicationlogfile_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(corelogfile_test Qt::Core) target_link_libraries(applicationlogfile_test Qt::Core)
add_test(NAME corelogfile_test COMMAND corelogfile_test) add_test(NAME applicationlogfile_test COMMAND applicationlogfile_test)
add_executable(corecommandbuilder_test add_executable(corecommandbuilder_test
tests/corecommandbuilder_test.cpp tests/corecommandbuilder_test.cpp

View File

@@ -0,0 +1,76 @@
#include "applicationlogfile.h"
#include <QCoreApplication>
#include <QDateTime>
#include <QMetaObject>
#include <QThread>
namespace
{
QString currentTimestamp()
{
return QDateTime::currentDateTime().toString("yyyy/MM/dd hh:mm:ss");
}
}
ApplicationLogFile::ApplicationLogFile(const QString &filePath, QObject *parent)
: QObject(parent),
file(filePath)
{
if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
{
stream.setDevice(&file);
stream.setEncoding(QStringConverter::Utf8);
appendEntry(
"=== Log started at " + currentTimestamp()
+ " with " + QCoreApplication::applicationName()
+ " " + QCoreApplication::applicationVersion()
+ " ==="
);
}
}
ApplicationLogFile::~ApplicationLogFile()
{
if (file.isOpen())
{
appendEntry("=== Log ended at " + currentTimestamp() + " ===");
stream.flush();
file.close();
}
}
QString ApplicationLogFile::filePath() const
{
return file.fileName();
}
bool ApplicationLogFile::isOpen() const
{
return file.isOpen();
}
void ApplicationLogFile::appendEntry(const QString &entry)
{
if (QThread::currentThread() != thread())
{
QMetaObject::invokeMethod(
this,
[this, entry]() { appendEntry(entry); },
Qt::QueuedConnection
);
return;
}
if (!file.isOpen())
{
return;
}
stream << entry;
if (!entry.endsWith('\n'))
{
stream << '\n';
}
stream.flush();
}

View File

@@ -0,0 +1,26 @@
#ifndef APPLICATIONLOGFILE_H
#define APPLICATIONLOGFILE_H
#include <QFile>
#include <QObject>
#include <QTextStream>
class ApplicationLogFile : public QObject
{
Q_OBJECT
public:
explicit ApplicationLogFile(const QString &filePath, QObject *parent = nullptr);
~ApplicationLogFile() override;
QString filePath() const;
bool isOpen() const;
void appendEntry(const QString &entry);
private:
QFile file;
QTextStream stream;
};
#endif // APPLICATIONLOGFILE_H

View File

@@ -1,59 +0,0 @@
#include "corelogfile.h"
#include <QMetaObject>
#include <QThread>
CoreLogFile::CoreLogFile(const QString &filePath, QObject *parent)
: QObject(parent),
file(filePath)
{
if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
{
stream.setDevice(&file);
stream.setEncoding(QStringConverter::Utf8);
}
}
CoreLogFile::~CoreLogFile()
{
if (file.isOpen())
{
stream.flush();
file.close();
}
}
QString CoreLogFile::filePath() const
{
return file.fileName();
}
bool CoreLogFile::isOpen() const
{
return file.isOpen();
}
void CoreLogFile::appendOutput(const QString &output)
{
if (QThread::currentThread() != thread())
{
QMetaObject::invokeMethod(
this,
[this, output]() { appendOutput(output); },
Qt::QueuedConnection
);
return;
}
if (!file.isOpen())
{
return;
}
stream << output;
if (!output.endsWith('\n'))
{
stream << '\n';
}
stream.flush();
}

View File

@@ -1,26 +0,0 @@
#ifndef CORELOGFILE_H
#define CORELOGFILE_H
#include <QFile>
#include <QObject>
#include <QTextStream>
class CoreLogFile : public QObject
{
Q_OBJECT
public:
explicit CoreLogFile(const QString &filePath, QObject *parent = nullptr);
~CoreLogFile() override;
QString filePath() const;
bool isOpen() const;
void appendOutput(const QString &output);
private:
QFile file;
QTextStream stream;
};
#endif // CORELOGFILE_H

View File

@@ -43,5 +43,5 @@ QString ApplicationPaths::logFile()
{ {
logDirectory.mkpath("."); logDirectory.mkpath(".");
} }
return logDirectory.filePath("zjuconnect.log"); return logDirectory.filePath("ez4connect.log");
} }

View File

@@ -8,6 +8,8 @@
#include "application/applicationlogger.h" #include "application/applicationlogger.h"
#include "application/applicationconstants.h" #include "application/applicationconstants.h"
#include "infrastructure/logging/applicationlogfile.h"
#include "infrastructure/storage/applicationpaths.h"
#include "presentation/main/mainwindow.h" #include "presentation/main/mainwindow.h"
#ifndef PROJ_VER #ifndef PROJ_VER
@@ -22,7 +24,14 @@ int main(int argc, char *argv[])
QApplication::setApplicationVersion(PROJ_VER); QApplication::setApplicationVersion(PROJ_VER);
QLocale::setDefault(QLocale(QLocale::Chinese, QLocale::SimplifiedChineseScript, QLocale::China)); QLocale::setDefault(QLocale(QLocale::Chinese, QLocale::SimplifiedChineseScript, QLocale::China));
ApplicationLogFile applicationLogFile(ApplicationPaths::logFile());
ApplicationLogger applicationLogger; ApplicationLogger applicationLogger;
QObject::connect(
&applicationLogger,
&ApplicationLogger::entryAdded,
&applicationLogFile,
&ApplicationLogFile::appendEntry
);
#if defined(Q_OS_WINDOWS) #if defined(Q_OS_WINDOWS)
QApplication::setFont(QFont("Microsoft YaHei UI", QApplication::font().pointSize())); QApplication::setFont(QFont("Microsoft YaHei UI", QApplication::font().pointSize()));
@@ -42,7 +51,7 @@ int main(int argc, char *argv[])
else else
qDebug() << "Failed to load transaction file for" << translateModule; qDebug() << "Failed to load transaction file for" << translateModule;
MainWindow mainWindow(&applicationLogger); MainWindow mainWindow(&applicationLogger, &applicationLogFile);
QObject::connect(&app, &SingleApplication::aboutToQuit, &mainWindow, &MainWindow::cleanUpWhenQuit); QObject::connect(&app, &SingleApplication::aboutToQuit, &mainWindow, &MainWindow::cleanUpWhenQuit);

View File

@@ -15,7 +15,6 @@
#include "application/connectionsession.h" #include "application/connectionsession.h"
#include "application/systemproxysession.h" #include "application/systemproxysession.h"
#include "infrastructure/coreprocess/coreexecutable.h" #include "infrastructure/coreprocess/coreexecutable.h"
#include "infrastructure/logging/corelogfile.h"
#include "infrastructure/platform/privileges.h" #include "infrastructure/platform/privileges.h"
#include "infrastructure/settings/settingsprofileloader.h" #include "infrastructure/settings/settingsprofileloader.h"
#include "presentation/coordinators/authdialogcoordinator.h" #include "presentation/coordinators/authdialogcoordinator.h"
@@ -29,7 +28,6 @@ ConnectionUiController::ConnectionUiController(
SystemProxySession *systemProxySession, SystemProxySession *systemProxySession,
AuthDialogCoordinator *authenticationDialogs, AuthDialogCoordinator *authenticationDialogs,
ApplicationLogger *applicationLogger, ApplicationLogger *applicationLogger,
CoreLogFile *coreLogFile,
SettingsProvider settingsProvider, SettingsProvider settingsProvider,
ProfileIdProvider profileIdProvider, ProfileIdProvider profileIdProvider,
NotificationHandler notificationHandler, NotificationHandler notificationHandler,
@@ -58,12 +56,6 @@ ConnectionUiController::ConnectionUiController(
applicationLogger, applicationLogger,
&ApplicationLogger::appendCoreOutput &ApplicationLogger::appendCoreOutput
); );
connect(
connectionSession,
&ConnectionSession::outputRead,
coreLogFile,
&CoreLogFile::appendOutput
);
connect( connect(
connectionSession, connectionSession,
&ConnectionSession::savedSudoPasswordRejected, &ConnectionSession::savedSudoPasswordRejected,

View File

@@ -12,7 +12,6 @@ class QAction;
class ApplicationLogger; class ApplicationLogger;
class AuthDialogCoordinator; class AuthDialogCoordinator;
class ConnectionSession; class ConnectionSession;
class CoreLogFile;
class QPushButton; class QPushButton;
class QSettings; class QSettings;
class SystemProxySession; class SystemProxySession;
@@ -40,7 +39,6 @@ public:
SystemProxySession *systemProxySession, SystemProxySession *systemProxySession,
AuthDialogCoordinator *authenticationDialogs, AuthDialogCoordinator *authenticationDialogs,
ApplicationLogger *applicationLogger, ApplicationLogger *applicationLogger,
CoreLogFile *coreLogFile,
SettingsProvider settingsProvider, SettingsProvider settingsProvider,
ProfileIdProvider profileIdProvider, ProfileIdProvider profileIdProvider,
NotificationHandler notificationHandler, NotificationHandler notificationHandler,

View File

@@ -17,7 +17,7 @@
#include "application/commandlineoptions.h" #include "application/commandlineoptions.h"
#include "application/settingsmigrator.h" #include "application/settingsmigrator.h"
#include "infrastructure/coreprocess/devicetrust.h" #include "infrastructure/coreprocess/devicetrust.h"
#include "infrastructure/logging/corelogfile.h" #include "infrastructure/logging/applicationlogfile.h"
#include "infrastructure/storage/applicationpaths.h" #include "infrastructure/storage/applicationpaths.h"
#include "infrastructure/update/updatechecker.h" #include "infrastructure/update/updatechecker.h"
#include "presentation/coordinators/connectionuicontroller.h" #include "presentation/coordinators/connectionuicontroller.h"
@@ -25,10 +25,15 @@
#include "presentation/presentationhelpers.h" #include "presentation/presentationhelpers.h"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
MainWindow::MainWindow(ApplicationLogger *logger, QWidget *parent) : MainWindow::MainWindow(
ApplicationLogger *logger,
ApplicationLogFile *logFile,
QWidget *parent
) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::MainWindow), ui(new Ui::MainWindow),
applicationLogger(logger) applicationLogger(logger),
applicationLogFile(logFile)
{ {
const QString overrideConfigPath = const QString overrideConfigPath =
CommandLineOptions::value(QCoreApplication::arguments(), "--config-path"); CommandLineOptions::value(QCoreApplication::arguments(), "--config-path");
@@ -45,7 +50,6 @@ MainWindow::MainWindow(ApplicationLogger *logger, QWidget *parent) :
authenticationDialogs = coordinator->authenticationDialogs(); authenticationDialogs = coordinator->authenticationDialogs();
connectionSession = coordinator->connection(); connectionSession = coordinator->connection();
systemProxySession = coordinator->systemProxy(); systemProxySession = coordinator->systemProxy();
coreLogFile = new CoreLogFile(ApplicationPaths::logFile(), this);
updateChecker = coordinator->updates(); updateChecker = coordinator->updates();
connect(updateChecker, &UpdateChecker::versionInfoChanged, this, connect(updateChecker, &UpdateChecker::versionInfoChanged, this,
[this](const VersionInfo &) { updateVersionInfo(); }); [this](const VersionInfo &) { updateVersionInfo(); });
@@ -128,7 +132,7 @@ MainWindow::MainWindow(ApplicationLogger *logger, QWidget *parent) :
connect(ui->openLogAction, &QAction::triggered, this, connect(ui->openLogAction, &QAction::triggered, this,
[this]() [this]()
{ {
const QString logFilePath = coreLogFile->filePath(); const QString logFilePath = applicationLogFile->filePath();
QFileInfo logFileInfo(logFilePath); QFileInfo logFileInfo(logFilePath);
if (logFileInfo.exists()) if (logFileInfo.exists())
@@ -280,7 +284,6 @@ MainWindow::MainWindow(ApplicationLogger *logger, QWidget *parent) :
systemProxySession, systemProxySession,
authenticationDialogs, authenticationDialogs,
applicationLogger, applicationLogger,
coreLogFile,
[this]() { return settings; }, [this]() { return settings; },
[this]() { return currentProfileId; }, [this]() { return currentProfileId; },
[this]( [this](

View File

@@ -20,8 +20,8 @@ namespace Ui
} }
class ApplicationLogger; class ApplicationLogger;
class ApplicationLogFile;
class ConnectionUiController; class ConnectionUiController;
class CoreLogFile;
class UpdateChecker; class UpdateChecker;
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
@@ -29,7 +29,11 @@ class MainWindow : public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
explicit MainWindow(ApplicationLogger *logger, QWidget *parent = nullptr); explicit MainWindow(
ApplicationLogger *logger,
ApplicationLogFile *logFile,
QWidget *parent = nullptr
);
~MainWindow() override; ~MainWindow() override;
@@ -98,7 +102,7 @@ private:
ConnectionUiController *connectionUiController; ConnectionUiController *connectionUiController;
MainWindowCoordinator *coordinator; MainWindowCoordinator *coordinator;
ApplicationLogger *applicationLogger; ApplicationLogger *applicationLogger;
CoreLogFile *coreLogFile = nullptr; ApplicationLogFile *applicationLogFile;
UpdateChecker *updateChecker; UpdateChecker *updateChecker;
QSettings *settings; QSettings *settings;
ProfileService *profileService; ProfileService *profileService;

View File

@@ -251,7 +251,7 @@ Line3</string>
<string>打开日志文件</string> <string>打开日志文件</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>打开核心程序的日志文件</string> <string>打开应用日志文件</string>
</property> </property>
</action> </action>
<action name="clearClientDataAction"> <action name="clearClientDataAction">

View File

@@ -0,0 +1,59 @@
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QTemporaryDir>
#include "infrastructure/logging/applicationlogfile.h"
namespace
{
bool writesApplicationLogEntries()
{
QTemporaryDir temporaryDirectory;
if (!temporaryDirectory.isValid())
{
qCritical() << "Unable to create temporary directory";
return false;
}
const QString logPath = temporaryDirectory.filePath("core.log");
{
ApplicationLogFile logFile(logPath);
if (!logFile.isOpen() || logFile.filePath() != logPath)
{
qCritical() << "Application log file did not open the requested path";
return false;
}
logFile.appendEntry("[INFO] application event");
logFile.appendEntry("[CORE] standard output\n[CORE] continued standard output");
}
QFile logFile(logPath);
if (!logFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
qCritical() << "Unable to read generated application log";
return false;
}
const QString contents = QString::fromUtf8(logFile.readAll());
if (!contents.contains("=== Log started at ")
|| !contents.contains(" with LogFileTest 1.0 ===\n")
|| !contents.contains("[INFO] application event\n")
|| !contents.contains("[CORE] standard output\n[CORE] continued standard output\n")
|| !contents.contains("=== Log ended at "))
{
qCritical().noquote() << "writesApplicationLogEntries failed:\n" << contents;
return false;
}
return true;
}
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName("LogFileTest");
QCoreApplication::setApplicationVersion("1.0");
return writesApplicationLogEntries() ? 0 : 1;
}

View File

@@ -1,53 +0,0 @@
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QTemporaryDir>
#include "infrastructure/logging/corelogfile.h"
namespace
{
bool writesOnlyRawCoreOutput()
{
QTemporaryDir temporaryDirectory;
if (!temporaryDirectory.isValid())
{
qCritical() << "Unable to create temporary directory";
return false;
}
const QString logPath = temporaryDirectory.filePath("core.log");
{
CoreLogFile logFile(logPath);
if (!logFile.isOpen() || logFile.filePath() != logPath)
{
qCritical() << "Core log file did not open the requested path";
return false;
}
logFile.appendOutput("standard output\ncontinued standard output");
logFile.appendOutput("error output");
}
QFile logFile(logPath);
if (!logFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
qCritical() << "Unable to read generated core log";
return false;
}
const QString contents = QString::fromUtf8(logFile.readAll());
if (contents != "standard output\ncontinued standard output\nerror output\n")
{
qCritical().noquote() << "writesOnlyRawCoreOutput failed:\n" << contents;
return false;
}
return true;
}
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
return writesOnlyRawCoreOutput() ? 0 : 1;
}