diff --git a/CMakeLists.txt b/CMakeLists.txt index fec4b8b..5a564ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,7 @@ set(SOURCE_FILES infrastructure/coreprocess/coreoutputbuffer.cpp infrastructure/coreprocess/coreoutputparser.cpp core/connectionsessionstate.cpp - infrastructure/logging/corelogfile.cpp + infrastructure/logging/applicationlogfile.cpp infrastructure/platform/autostart.cpp infrastructure/platform/privileges.cpp infrastructure/settings/settingsprofileloader.cpp @@ -143,13 +143,13 @@ if(BUILD_TESTING) target_link_libraries(applicationlogger_test Qt::Core) add_test(NAME applicationlogger_test COMMAND applicationlogger_test) - add_executable(corelogfile_test - tests/corelogfile_test.cpp - infrastructure/logging/corelogfile.cpp + add_executable(applicationlogfile_test + tests/applicationlogfile_test.cpp + infrastructure/logging/applicationlogfile.cpp ) - target_include_directories(corelogfile_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) - target_link_libraries(corelogfile_test Qt::Core) - add_test(NAME corelogfile_test COMMAND corelogfile_test) + target_include_directories(applicationlogfile_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + target_link_libraries(applicationlogfile_test Qt::Core) + add_test(NAME applicationlogfile_test COMMAND applicationlogfile_test) add_executable(corecommandbuilder_test tests/corecommandbuilder_test.cpp diff --git a/infrastructure/logging/applicationlogfile.cpp b/infrastructure/logging/applicationlogfile.cpp new file mode 100644 index 0000000..3cf07c9 --- /dev/null +++ b/infrastructure/logging/applicationlogfile.cpp @@ -0,0 +1,76 @@ +#include "applicationlogfile.h" + +#include +#include +#include +#include + +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(); +} diff --git a/infrastructure/logging/applicationlogfile.h b/infrastructure/logging/applicationlogfile.h new file mode 100644 index 0000000..f37c83d --- /dev/null +++ b/infrastructure/logging/applicationlogfile.h @@ -0,0 +1,26 @@ +#ifndef APPLICATIONLOGFILE_H +#define APPLICATIONLOGFILE_H + +#include +#include +#include + +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 diff --git a/infrastructure/logging/corelogfile.cpp b/infrastructure/logging/corelogfile.cpp deleted file mode 100644 index c24fec0..0000000 --- a/infrastructure/logging/corelogfile.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "corelogfile.h" - -#include -#include - -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(); -} diff --git a/infrastructure/logging/corelogfile.h b/infrastructure/logging/corelogfile.h deleted file mode 100644 index 7c5a3a1..0000000 --- a/infrastructure/logging/corelogfile.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CORELOGFILE_H -#define CORELOGFILE_H - -#include -#include -#include - -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 diff --git a/infrastructure/storage/applicationpaths.cpp b/infrastructure/storage/applicationpaths.cpp index 7fbea1a..a506a3d 100644 --- a/infrastructure/storage/applicationpaths.cpp +++ b/infrastructure/storage/applicationpaths.cpp @@ -43,5 +43,5 @@ QString ApplicationPaths::logFile() { logDirectory.mkpath("."); } - return logDirectory.filePath("zjuconnect.log"); + return logDirectory.filePath("ez4connect.log"); } diff --git a/main.cpp b/main.cpp index eb14694..3adf9ac 100644 --- a/main.cpp +++ b/main.cpp @@ -8,6 +8,8 @@ #include "application/applicationlogger.h" #include "application/applicationconstants.h" +#include "infrastructure/logging/applicationlogfile.h" +#include "infrastructure/storage/applicationpaths.h" #include "presentation/main/mainwindow.h" #ifndef PROJ_VER @@ -22,7 +24,14 @@ int main(int argc, char *argv[]) QApplication::setApplicationVersion(PROJ_VER); QLocale::setDefault(QLocale(QLocale::Chinese, QLocale::SimplifiedChineseScript, QLocale::China)); + ApplicationLogFile applicationLogFile(ApplicationPaths::logFile()); ApplicationLogger applicationLogger; + QObject::connect( + &applicationLogger, + &ApplicationLogger::entryAdded, + &applicationLogFile, + &ApplicationLogFile::appendEntry + ); #if defined(Q_OS_WINDOWS) QApplication::setFont(QFont("Microsoft YaHei UI", QApplication::font().pointSize())); @@ -42,7 +51,7 @@ int main(int argc, char *argv[]) else qDebug() << "Failed to load transaction file for" << translateModule; - MainWindow mainWindow(&applicationLogger); + MainWindow mainWindow(&applicationLogger, &applicationLogFile); QObject::connect(&app, &SingleApplication::aboutToQuit, &mainWindow, &MainWindow::cleanUpWhenQuit); diff --git a/presentation/coordinators/connectionuicontroller.cpp b/presentation/coordinators/connectionuicontroller.cpp index 9ccf90b..7d7e650 100644 --- a/presentation/coordinators/connectionuicontroller.cpp +++ b/presentation/coordinators/connectionuicontroller.cpp @@ -15,7 +15,6 @@ #include "application/connectionsession.h" #include "application/systemproxysession.h" #include "infrastructure/coreprocess/coreexecutable.h" -#include "infrastructure/logging/corelogfile.h" #include "infrastructure/platform/privileges.h" #include "infrastructure/settings/settingsprofileloader.h" #include "presentation/coordinators/authdialogcoordinator.h" @@ -29,7 +28,6 @@ ConnectionUiController::ConnectionUiController( SystemProxySession *systemProxySession, AuthDialogCoordinator *authenticationDialogs, ApplicationLogger *applicationLogger, - CoreLogFile *coreLogFile, SettingsProvider settingsProvider, ProfileIdProvider profileIdProvider, NotificationHandler notificationHandler, @@ -58,12 +56,6 @@ ConnectionUiController::ConnectionUiController( applicationLogger, &ApplicationLogger::appendCoreOutput ); - connect( - connectionSession, - &ConnectionSession::outputRead, - coreLogFile, - &CoreLogFile::appendOutput - ); connect( connectionSession, &ConnectionSession::savedSudoPasswordRejected, diff --git a/presentation/coordinators/connectionuicontroller.h b/presentation/coordinators/connectionuicontroller.h index e10809b..66b9560 100644 --- a/presentation/coordinators/connectionuicontroller.h +++ b/presentation/coordinators/connectionuicontroller.h @@ -12,7 +12,6 @@ class QAction; class ApplicationLogger; class AuthDialogCoordinator; class ConnectionSession; -class CoreLogFile; class QPushButton; class QSettings; class SystemProxySession; @@ -40,7 +39,6 @@ public: SystemProxySession *systemProxySession, AuthDialogCoordinator *authenticationDialogs, ApplicationLogger *applicationLogger, - CoreLogFile *coreLogFile, SettingsProvider settingsProvider, ProfileIdProvider profileIdProvider, NotificationHandler notificationHandler, diff --git a/presentation/main/mainwindow.cpp b/presentation/main/mainwindow.cpp index 0f7620c..d39ae29 100644 --- a/presentation/main/mainwindow.cpp +++ b/presentation/main/mainwindow.cpp @@ -17,7 +17,7 @@ #include "application/commandlineoptions.h" #include "application/settingsmigrator.h" #include "infrastructure/coreprocess/devicetrust.h" -#include "infrastructure/logging/corelogfile.h" +#include "infrastructure/logging/applicationlogfile.h" #include "infrastructure/storage/applicationpaths.h" #include "infrastructure/update/updatechecker.h" #include "presentation/coordinators/connectionuicontroller.h" @@ -25,10 +25,15 @@ #include "presentation/presentationhelpers.h" #include "ui_mainwindow.h" -MainWindow::MainWindow(ApplicationLogger *logger, QWidget *parent) : +MainWindow::MainWindow( + ApplicationLogger *logger, + ApplicationLogFile *logFile, + QWidget *parent +) : QMainWindow(parent), ui(new Ui::MainWindow), - applicationLogger(logger) + applicationLogger(logger), + applicationLogFile(logFile) { const QString overrideConfigPath = CommandLineOptions::value(QCoreApplication::arguments(), "--config-path"); @@ -45,7 +50,6 @@ MainWindow::MainWindow(ApplicationLogger *logger, QWidget *parent) : authenticationDialogs = coordinator->authenticationDialogs(); connectionSession = coordinator->connection(); systemProxySession = coordinator->systemProxy(); - coreLogFile = new CoreLogFile(ApplicationPaths::logFile(), this); updateChecker = coordinator->updates(); connect(updateChecker, &UpdateChecker::versionInfoChanged, this, [this](const VersionInfo &) { updateVersionInfo(); }); @@ -128,7 +132,7 @@ MainWindow::MainWindow(ApplicationLogger *logger, QWidget *parent) : connect(ui->openLogAction, &QAction::triggered, this, [this]() { - const QString logFilePath = coreLogFile->filePath(); + const QString logFilePath = applicationLogFile->filePath(); QFileInfo logFileInfo(logFilePath); if (logFileInfo.exists()) @@ -280,7 +284,6 @@ MainWindow::MainWindow(ApplicationLogger *logger, QWidget *parent) : systemProxySession, authenticationDialogs, applicationLogger, - coreLogFile, [this]() { return settings; }, [this]() { return currentProfileId; }, [this]( diff --git a/presentation/main/mainwindow.h b/presentation/main/mainwindow.h index 5eb668a..403af45 100644 --- a/presentation/main/mainwindow.h +++ b/presentation/main/mainwindow.h @@ -20,8 +20,8 @@ namespace Ui } class ApplicationLogger; +class ApplicationLogFile; class ConnectionUiController; -class CoreLogFile; class UpdateChecker; class MainWindow : public QMainWindow @@ -29,7 +29,11 @@ class MainWindow : public QMainWindow Q_OBJECT public: - explicit MainWindow(ApplicationLogger *logger, QWidget *parent = nullptr); + explicit MainWindow( + ApplicationLogger *logger, + ApplicationLogFile *logFile, + QWidget *parent = nullptr + ); ~MainWindow() override; @@ -98,7 +102,7 @@ private: ConnectionUiController *connectionUiController; MainWindowCoordinator *coordinator; ApplicationLogger *applicationLogger; - CoreLogFile *coreLogFile = nullptr; + ApplicationLogFile *applicationLogFile; UpdateChecker *updateChecker; QSettings *settings; ProfileService *profileService; diff --git a/presentation/main/mainwindow.ui b/presentation/main/mainwindow.ui index 7c0ce73..97605c3 100644 --- a/presentation/main/mainwindow.ui +++ b/presentation/main/mainwindow.ui @@ -251,7 +251,7 @@ Line3 打开日志文件 - 打开核心程序的日志文件 + 打开应用日志文件 diff --git a/tests/applicationlogfile_test.cpp b/tests/applicationlogfile_test.cpp new file mode 100644 index 0000000..3356e50 --- /dev/null +++ b/tests/applicationlogfile_test.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +#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; +} diff --git a/tests/corelogfile_test.cpp b/tests/corelogfile_test.cpp deleted file mode 100644 index f7e0e82..0000000 --- a/tests/corelogfile_test.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include - -#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; -}