diff --git a/gui/include/sessionlog.h b/gui/include/sessionlog.h index 24e5687..b49b78a 100644 --- a/gui/include/sessionlog.h +++ b/gui/include/sessionlog.h @@ -21,7 +21,9 @@ #include #include +#include +class QFile; class StreamSession; class SessionLog @@ -30,15 +32,19 @@ class SessionLog private: StreamSession *session; - ChiakiLog chiaki_log; + ChiakiLog log; + QFile *file; + QMutex file_mutex; void Log(ChiakiLogLevel level, const char *msg); public: SessionLog(StreamSession *session, uint32_t level_mask, const QString &filename); + ~SessionLog(); - ChiakiLog *GetChiakiLog() { return &chiaki_log; } - + ChiakiLog *GetChiakiLog() { return &log; } }; +QString CreateLogFilename(); + #endif //CHIAKI_SESSIONLOG_H diff --git a/gui/src/main.cpp b/gui/src/main.cpp index c145090..faedc7c 100644 --- a/gui/src/main.cpp +++ b/gui/src/main.cpp @@ -65,6 +65,7 @@ int main(int argc, char *argv[]) StreamSessionConnectInfo connect_info; connect_info.log_level_mask = CHIAKI_LOG_ALL & ~CHIAKI_LOG_VERBOSE; + connect_info.log_file = CreateLogFilename(); connect_info.host = host; connect_info.registkey = parser.value(regist_key_option); diff --git a/gui/src/sessionlog.cpp b/gui/src/sessionlog.cpp index 0b03b2a..a905a06 100644 --- a/gui/src/sessionlog.cpp +++ b/gui/src/sessionlog.cpp @@ -18,19 +18,57 @@ #include #include +#include +#include +#include +#include +#include + + static void LogCb(ChiakiLogLevel level, const char *msg, void *user); SessionLog::SessionLog(StreamSession *session, uint32_t level_mask, const QString &filename) : session(session) { - chiaki_log_init(&chiaki_log, level_mask, LogCb, this); + chiaki_log_init(&log, level_mask, LogCb, this); - // TODO: file + if(filename.isEmpty()) + { + file = nullptr; + CHIAKI_LOGI(&log, "Logging to file disabled"); + } + else + { + file = new QFile(filename); + if(!file->open(QIODevice::ReadWrite)) + { + delete file; + file = nullptr; + CHIAKI_LOGI(&log, "Failed to open file %s for logging", filename.toLocal8Bit().constData()); + } + else + { + CHIAKI_LOGI(&log, "Logging to file %s", filename.toLocal8Bit().constData()); + } + } +} + +SessionLog::~SessionLog() +{ + delete file; } void SessionLog::Log(ChiakiLogLevel level, const char *msg) { chiaki_log_cb_print(level, msg, nullptr); + + if(file) + { + QMutexLocker lock(&file_mutex); + // TODO: add timestamp and level + file->write(msg); + file->write("\n"); + } } class SessionLogPrivate @@ -43,4 +81,49 @@ static void LogCb(ChiakiLogLevel level, const char *msg, void *user) { auto log = reinterpret_cast(user); SessionLogPrivate::Log(log, level, msg); -} \ No newline at end of file +} + +#define KEEP_LOG_FILES_COUNT 5 + +static const QString date_format = "yyyy-MM-dd_HH-mm-ss-zzzz"; +static const QString session_log_wildcard = "chiaki_session_*.log"; +static const QRegularExpression session_log_regex("chiaki_session_(.*).log"); + +QString CreateLogFilename() +{ + auto base_dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + if(base_dir.isEmpty()) + return QString(); + + QDir dir(base_dir); + if(!dir.mkpath("log")) + return QString(); + if(!dir.cd("log")) + return QString(); + + dir.setNameFilters({ session_log_wildcard }); + auto existing_files = dir.entryList(); + QVector> existing_files_date; + existing_files_date.resize(existing_files.count()); + std::transform(existing_files.begin(), existing_files.end(), existing_files_date.begin(), [](const QString &filename) { + QDateTime date; + auto match = session_log_regex.match(filename); + if(match.hasMatch()) + date = QDateTime::fromString(match.captured(1), date_format); + return QPair(filename, date); + }); + std::sort(existing_files_date.begin(), existing_files_date.end(), [](const QPair &a, const QPair &b) { + return a.second > b.second; + }); + + for(int i=KEEP_LOG_FILES_COUNT; i #include -#include #include