mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 21:00:05 +00:00
Add file logging to local application data directory
This commit is contained in:
parent
41d47878e3
commit
32cd672a40
6 changed files with 255 additions and 47 deletions
|
|
@ -91,6 +91,7 @@ set(HDR_MANAGER source/scwx/qt/manager/alert_manager.hpp
|
||||||
source/scwx/qt/manager/download_manager.hpp
|
source/scwx/qt/manager/download_manager.hpp
|
||||||
source/scwx/qt/manager/font_manager.hpp
|
source/scwx/qt/manager/font_manager.hpp
|
||||||
source/scwx/qt/manager/hotkey_manager.hpp
|
source/scwx/qt/manager/hotkey_manager.hpp
|
||||||
|
source/scwx/qt/manager/log_manager.hpp
|
||||||
source/scwx/qt/manager/media_manager.hpp
|
source/scwx/qt/manager/media_manager.hpp
|
||||||
source/scwx/qt/manager/placefile_manager.hpp
|
source/scwx/qt/manager/placefile_manager.hpp
|
||||||
source/scwx/qt/manager/position_manager.hpp
|
source/scwx/qt/manager/position_manager.hpp
|
||||||
|
|
@ -106,6 +107,7 @@ set(SRC_MANAGER source/scwx/qt/manager/alert_manager.cpp
|
||||||
source/scwx/qt/manager/download_manager.cpp
|
source/scwx/qt/manager/download_manager.cpp
|
||||||
source/scwx/qt/manager/font_manager.cpp
|
source/scwx/qt/manager/font_manager.cpp
|
||||||
source/scwx/qt/manager/hotkey_manager.cpp
|
source/scwx/qt/manager/hotkey_manager.cpp
|
||||||
|
source/scwx/qt/manager/log_manager.cpp
|
||||||
source/scwx/qt/manager/media_manager.cpp
|
source/scwx/qt/manager/media_manager.cpp
|
||||||
source/scwx/qt/manager/placefile_manager.cpp
|
source/scwx/qt/manager/placefile_manager.cpp
|
||||||
source/scwx/qt/manager/position_manager.cpp
|
source/scwx/qt/manager/position_manager.cpp
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <scwx/qt/config/radar_site.hpp>
|
#include <scwx/qt/config/radar_site.hpp>
|
||||||
#include <scwx/qt/main/main_window.hpp>
|
#include <scwx/qt/main/main_window.hpp>
|
||||||
#include <scwx/qt/main/versions.hpp>
|
#include <scwx/qt/main/versions.hpp>
|
||||||
|
#include <scwx/qt/manager/log_manager.hpp>
|
||||||
#include <scwx/qt/manager/radar_product_manager.hpp>
|
#include <scwx/qt/manager/radar_product_manager.hpp>
|
||||||
#include <scwx/qt/manager/resource_manager.hpp>
|
#include <scwx/qt/manager/resource_manager.hpp>
|
||||||
#include <scwx/qt/manager/settings_manager.hpp>
|
#include <scwx/qt/manager/settings_manager.hpp>
|
||||||
|
|
@ -22,7 +23,6 @@
|
||||||
#include <aws/core/Aws.h>
|
#include <aws/core/Aws.h>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <spdlog/spdlog.h>
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
|
@ -31,9 +31,6 @@ static const std::string logPrefix_ = "scwx::main";
|
||||||
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||||
|
|
||||||
static void OverrideDefaultStyle(const std::vector<std::string>& args);
|
static void OverrideDefaultStyle(const std::vector<std::string>& args);
|
||||||
static void QtLogMessageHandler(QtMsgType messageType,
|
|
||||||
const QMessageLogContext& context,
|
|
||||||
const QString& message);
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
|
@ -45,11 +42,8 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize logger
|
// Initialize logger
|
||||||
scwx::util::Logger::Initialize();
|
auto& logManager = scwx::qt::manager::LogManager::Instance();
|
||||||
spdlog::set_level(spdlog::level::debug);
|
logManager.Initialize();
|
||||||
|
|
||||||
// Install Qt Message Handler
|
|
||||||
qInstallMessageHandler(&QtLogMessageHandler);
|
|
||||||
|
|
||||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
|
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
|
||||||
|
|
||||||
|
|
@ -101,6 +95,7 @@ int main(int argc, char* argv[])
|
||||||
scwx::qt::config::RadarSite::Initialize();
|
scwx::qt::config::RadarSite::Initialize();
|
||||||
scwx::qt::config::CountyDatabase::Initialize();
|
scwx::qt::config::CountyDatabase::Initialize();
|
||||||
scwx::qt::manager::SettingsManager::Instance().Initialize();
|
scwx::qt::manager::SettingsManager::Instance().Initialize();
|
||||||
|
logManager.InitializeLogFile();
|
||||||
scwx::qt::manager::ResourceManager::Initialize();
|
scwx::qt::manager::ResourceManager::Initialize();
|
||||||
|
|
||||||
// Theme
|
// Theme
|
||||||
|
|
@ -176,40 +171,3 @@ OverrideDefaultStyle([[maybe_unused]] const std::vector<std::string>& args)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtLogMessageHandler(QtMsgType messageType,
|
|
||||||
const QMessageLogContext& context,
|
|
||||||
const QString& message)
|
|
||||||
{
|
|
||||||
static const auto qtLogger_ = scwx::util::Logger::Create("qt");
|
|
||||||
|
|
||||||
static const std::unordered_map<QtMsgType, spdlog::level::level_enum>
|
|
||||||
levelMap_ {{QtMsgType::QtDebugMsg, spdlog::level::level_enum::debug},
|
|
||||||
{QtMsgType::QtInfoMsg, spdlog::level::level_enum::info},
|
|
||||||
{QtMsgType::QtWarningMsg, spdlog::level::level_enum::warn},
|
|
||||||
{QtMsgType::QtCriticalMsg, spdlog::level::level_enum::err},
|
|
||||||
{QtMsgType::QtFatalMsg, spdlog::level::level_enum::critical}};
|
|
||||||
|
|
||||||
spdlog::level::level_enum level = spdlog::level::level_enum::info;
|
|
||||||
auto it = levelMap_.find(messageType);
|
|
||||||
if (it != levelMap_.cend())
|
|
||||||
{
|
|
||||||
level = it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
spdlog::source_loc location {};
|
|
||||||
if (context.file != nullptr && context.function != nullptr)
|
|
||||||
{
|
|
||||||
location = {context.file, context.line, context.function};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.category != nullptr)
|
|
||||||
{
|
|
||||||
qtLogger_->log(
|
|
||||||
location, level, "[{}] {}", context.category, message.toStdString());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qtLogger_->log(location, level, message.toStdString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
178
scwx-qt/source/scwx/qt/manager/log_manager.cpp
Normal file
178
scwx-qt/source/scwx/qt/manager/log_manager.cpp
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
#include <scwx/qt/manager/log_manager.hpp>
|
||||||
|
#include <scwx/util/logger.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <map>
|
||||||
|
#include <ranges>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <boost/process/environment.hpp>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
namespace manager
|
||||||
|
{
|
||||||
|
|
||||||
|
static const std::string logPrefix_ = "scwx::qt::manager::log_manager";
|
||||||
|
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||||
|
|
||||||
|
static void QtLogMessageHandler(QtMsgType messageType,
|
||||||
|
const QMessageLogContext& context,
|
||||||
|
const QString& message);
|
||||||
|
|
||||||
|
class LogManager::Impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Impl() {}
|
||||||
|
~Impl() {}
|
||||||
|
|
||||||
|
void PruneLogFiles();
|
||||||
|
|
||||||
|
std::string logPath_ {};
|
||||||
|
std::string logFile_ {};
|
||||||
|
int pid_ {};
|
||||||
|
};
|
||||||
|
|
||||||
|
LogManager::LogManager() : p(std::make_unique<Impl>()) {}
|
||||||
|
LogManager::~LogManager() = default;
|
||||||
|
|
||||||
|
void LogManager::Initialize()
|
||||||
|
{
|
||||||
|
// Initialize logger
|
||||||
|
scwx::util::Logger::Initialize();
|
||||||
|
spdlog::set_level(spdlog::level::debug);
|
||||||
|
|
||||||
|
// Install Qt Message Handler
|
||||||
|
qInstallMessageHandler(&QtLogMessageHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogManager::InitializeLogFile()
|
||||||
|
{
|
||||||
|
p->logPath_ =
|
||||||
|
QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)
|
||||||
|
.toStdString();
|
||||||
|
p->pid_ = boost::this_process::get_id();
|
||||||
|
p->logFile_ = fmt::format("{}/supercell-wx.{}.log", p->logPath_, p->pid_);
|
||||||
|
|
||||||
|
// Create log directory if it doesn't exist
|
||||||
|
if (!std::filesystem::exists(p->logPath_))
|
||||||
|
{
|
||||||
|
if (!std::filesystem::create_directories(p->logPath_))
|
||||||
|
{
|
||||||
|
logger_->error("Unable to create log directory: \"{}\"", p->logPath_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scwx::util::Logger::AddFileSink(p->logFile_);
|
||||||
|
|
||||||
|
p->PruneLogFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogManager::Impl::PruneLogFiles()
|
||||||
|
{
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
static constexpr std::size_t kMaxLogFiles_ = 5;
|
||||||
|
static constexpr auto kMinModificationAge_ = 30min;
|
||||||
|
|
||||||
|
std::multimap<std::filesystem::file_time_type, std::filesystem::path>
|
||||||
|
logFiles {};
|
||||||
|
|
||||||
|
// Find existing log files in log directory
|
||||||
|
for (auto& file : std::filesystem::directory_iterator(logPath_))
|
||||||
|
{
|
||||||
|
const std::string filename = file.path().filename().string();
|
||||||
|
|
||||||
|
if (file.is_regular_file() && filename.starts_with("supercell-wx.") &&
|
||||||
|
filename.ends_with(".log"))
|
||||||
|
{
|
||||||
|
logger_->trace("Found log file: {}", filename);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto lastWriteTime = std::filesystem::last_write_time(file);
|
||||||
|
logFiles.insert({lastWriteTime, file});
|
||||||
|
}
|
||||||
|
catch (const std::exception&)
|
||||||
|
{
|
||||||
|
logger_->error("Error getting last write time of file: {}",
|
||||||
|
file.path().string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up old log files
|
||||||
|
auto now = std::filesystem::file_time_type::clock::now();
|
||||||
|
auto modificationThreshold = now - kMinModificationAge_;
|
||||||
|
|
||||||
|
for (auto& logFile :
|
||||||
|
logFiles | std::views::reverse | std::views::drop(kMaxLogFiles_))
|
||||||
|
{
|
||||||
|
if (logFile.first < modificationThreshold)
|
||||||
|
{
|
||||||
|
const std::string filename = logFile.second.filename().string();
|
||||||
|
|
||||||
|
logger_->info("Removing old log file: {}", filename);
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
if (!std::filesystem::remove(logFile.second, ec))
|
||||||
|
{
|
||||||
|
logger_->warn(
|
||||||
|
"Could not remove file: {}, {}", filename, ec.message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager& LogManager::Instance()
|
||||||
|
{
|
||||||
|
static LogManager LogManager_ {};
|
||||||
|
return LogManager_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtLogMessageHandler(QtMsgType messageType,
|
||||||
|
const QMessageLogContext& context,
|
||||||
|
const QString& message)
|
||||||
|
{
|
||||||
|
static const auto qtLogger_ = scwx::util::Logger::Create("qt");
|
||||||
|
|
||||||
|
static const std::unordered_map<QtMsgType, spdlog::level::level_enum>
|
||||||
|
levelMap_ {{QtMsgType::QtDebugMsg, spdlog::level::level_enum::debug},
|
||||||
|
{QtMsgType::QtInfoMsg, spdlog::level::level_enum::info},
|
||||||
|
{QtMsgType::QtWarningMsg, spdlog::level::level_enum::warn},
|
||||||
|
{QtMsgType::QtCriticalMsg, spdlog::level::level_enum::err},
|
||||||
|
{QtMsgType::QtFatalMsg, spdlog::level::level_enum::critical}};
|
||||||
|
|
||||||
|
spdlog::level::level_enum level = spdlog::level::level_enum::info;
|
||||||
|
auto it = levelMap_.find(messageType);
|
||||||
|
if (it != levelMap_.cend())
|
||||||
|
{
|
||||||
|
level = it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::source_loc location {};
|
||||||
|
if (context.file != nullptr && context.function != nullptr)
|
||||||
|
{
|
||||||
|
location = {context.file, context.line, context.function};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.category != nullptr)
|
||||||
|
{
|
||||||
|
qtLogger_->log(
|
||||||
|
location, level, "[{}] {}", context.category, message.toStdString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qtLogger_->log(location, level, message.toStdString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace manager
|
||||||
|
} // namespace qt
|
||||||
|
} // namespace scwx
|
||||||
36
scwx-qt/source/scwx/qt/manager/log_manager.hpp
Normal file
36
scwx-qt/source/scwx/qt/manager/log_manager.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
namespace manager
|
||||||
|
{
|
||||||
|
|
||||||
|
class LogManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY_MOVE(LogManager)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit LogManager();
|
||||||
|
~LogManager();
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
void InitializeLogFile();
|
||||||
|
|
||||||
|
static LogManager& Instance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Impl;
|
||||||
|
std::unique_ptr<Impl> p;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace manager
|
||||||
|
} // namespace qt
|
||||||
|
} // namespace scwx
|
||||||
|
|
@ -21,6 +21,7 @@ namespace Logger
|
||||||
{
|
{
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
|
void AddFileSink(const std::string& baseFilename);
|
||||||
std::shared_ptr<spdlog::logger> Create(const std::string& name);
|
std::shared_ptr<spdlog::logger> Create(const std::string& name);
|
||||||
|
|
||||||
} // namespace Logger
|
} // namespace Logger
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <spdlog/sinks/rotating_file_sink.h>
|
||||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||||
|
|
||||||
namespace scwx
|
namespace scwx
|
||||||
|
|
@ -12,9 +13,34 @@ namespace util
|
||||||
namespace Logger
|
namespace Logger
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static const std::string logPattern_ = "[%Y-%m-%d %T.%e] [%t] [%^%l%$] [%n] %v";
|
||||||
|
|
||||||
|
static std::vector<std::shared_ptr<spdlog::sinks::sink>> extraSinks_ {};
|
||||||
|
|
||||||
void Initialize()
|
void Initialize()
|
||||||
{
|
{
|
||||||
spdlog::set_pattern("[%Y-%m-%d %T.%e] [%t] [%^%l%$] [%n] %v");
|
spdlog::set_pattern(logPattern_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddFileSink(const std::string& baseFilename)
|
||||||
|
{
|
||||||
|
constexpr std::size_t maxSize = 20u * 1024u * 1024u; // 20 MB
|
||||||
|
constexpr std::size_t maxFiles = 5u;
|
||||||
|
constexpr bool rotateOnOpen = true;
|
||||||
|
|
||||||
|
auto fileSink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
|
||||||
|
baseFilename, maxSize, maxFiles, rotateOnOpen);
|
||||||
|
|
||||||
|
fileSink->set_pattern(logPattern_);
|
||||||
|
|
||||||
|
spdlog::apply_all(
|
||||||
|
[&](std::shared_ptr<spdlog::logger> logger)
|
||||||
|
{
|
||||||
|
auto& sinks = logger->sinks();
|
||||||
|
sinks.push_back(fileSink);
|
||||||
|
});
|
||||||
|
|
||||||
|
extraSinks_.push_back(fileSink);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<spdlog::logger> Create(const std::string& name)
|
std::shared_ptr<spdlog::logger> Create(const std::string& name)
|
||||||
|
|
@ -26,6 +52,13 @@ std::shared_ptr<spdlog::logger> Create(const std::string& name)
|
||||||
std::shared_ptr<spdlog::logger> logger =
|
std::shared_ptr<spdlog::logger> logger =
|
||||||
std::make_shared<spdlog::logger>(name, sink);
|
std::make_shared<spdlog::logger>(name, sink);
|
||||||
|
|
||||||
|
// Add additional registered sinks
|
||||||
|
for (auto& extraSink : extraSinks_)
|
||||||
|
{
|
||||||
|
auto& sinks = logger->sinks();
|
||||||
|
sinks.push_back(extraSink);
|
||||||
|
}
|
||||||
|
|
||||||
// Register the logger, so it can be retrieved later using spdlog::get()
|
// Register the logger, so it can be retrieved later using spdlog::get()
|
||||||
spdlog::register_logger(logger);
|
spdlog::register_logger(logger);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue