mirror of
https://github.com/hyblocker/OpenVR-SpaceCalibrator.git
synced 2026-10-24 23:00:57 +02:00
203 lines
8.1 KiB
C++
203 lines
8.1 KiB
C++
#include "quill/Backend.h"
|
|
#include "quill/Frontend.h"
|
|
#include "quill/Logger.h"
|
|
#include "quill/LogMacros.h"
|
|
#include "quill/sinks/ConsoleSink.h"
|
|
#include "quill/sinks/FileSink.h"
|
|
|
|
#include <openvr_driver.h>
|
|
#include "log.h"
|
|
#include "util.h"
|
|
#include <fmt/chrono.h>
|
|
|
|
#include <filesystem>
|
|
#include <cassert>
|
|
|
|
namespace fs = ::std::filesystem;
|
|
|
|
namespace logging {
|
|
::quill::Logger* s_logger = nullptr;
|
|
::quill::Logger* s_loggerOpenVr = nullptr;
|
|
::quill::Logger* s_loggerIpc = nullptr;
|
|
::quill::Logger* s_loggerHooking = nullptr;
|
|
::quill::Logger* s_loggerCalibration = nullptr;
|
|
|
|
class UiHaltOnErrorSink final : public quill::Sink {
|
|
public:
|
|
UiHaltOnErrorSink() = default;
|
|
|
|
void write_log(quill::MacroMetadata const* /** log_metadata **/, uint64_t /** log_timestamp **/,
|
|
std::string_view /** thread_id **/, std::string_view /** thread_name **/,
|
|
std::string const& /** process_id **/, std::string_view /** logger_name **/,
|
|
quill::LogLevel log_level, std::string_view /** log_level_description **/,
|
|
std::string_view /** log_level_short_code **/,
|
|
std::vector<std::pair<std::string, std::string>> const* /** named_args - only populated when named args in the format placeholder are used **/,
|
|
std::string_view /** log_message **/, std::string_view log_statement) override
|
|
{
|
|
// Propagate error logs to the UI
|
|
if (log_level < quill::LogLevel::Backtrace && log_level >= quill::LogLevel::Error) {
|
|
// @TODO: propagate to ui
|
|
}
|
|
}
|
|
|
|
void flush_sink() noexcept override { }
|
|
void run_periodic_tasks() noexcept override { }
|
|
};
|
|
|
|
class DriverLogSink final : public quill::Sink {
|
|
public:
|
|
DriverLogSink() = default;
|
|
|
|
void write_log(quill::MacroMetadata const* /** log_metadata **/, uint64_t /** log_timestamp **/,
|
|
std::string_view /** thread_id **/, std::string_view /** thread_name **/,
|
|
std::string const& /** process_id **/, std::string_view logger_name,
|
|
quill::LogLevel log_level, std::string_view /** log_level_description **/,
|
|
std::string_view /** log_level_short_code **/,
|
|
std::vector<std::pair<std::string, std::string>> const* /** named_args - only populated when named args in the format placeholder are used **/,
|
|
std::string_view log_message, std::string_view log_statement) override
|
|
{
|
|
// Propagate error logs to the steamVR
|
|
std::string szLogLevel;
|
|
switch (log_level) {
|
|
case quill::LogLevel::TraceL3:
|
|
case quill::LogLevel::TraceL2:
|
|
case quill::LogLevel::TraceL1:
|
|
szLogLevel = "Trace";
|
|
break;
|
|
case quill::LogLevel::Debug:
|
|
szLogLevel = "Debug";
|
|
break;
|
|
case quill::LogLevel::Info:
|
|
szLogLevel = "Info";
|
|
break;
|
|
case quill::LogLevel::Notice:
|
|
szLogLevel = "Notice";
|
|
break;
|
|
case quill::LogLevel::Warning:
|
|
szLogLevel = "Warning";
|
|
break;
|
|
case quill::LogLevel::Error:
|
|
szLogLevel = "Error";
|
|
break;
|
|
case quill::LogLevel::Critical:
|
|
szLogLevel = "Critical";
|
|
break;
|
|
case quill::LogLevel::Backtrace:
|
|
szLogLevel = "Backtrace";
|
|
break;
|
|
case quill::LogLevel::None:
|
|
szLogLevel = "None";
|
|
break;
|
|
default:
|
|
szLogLevel = fmt::format("LogLevel_{}", (uint32_t)log_level);
|
|
break;
|
|
}
|
|
|
|
std::string vrLogMsg = fmt::format("[{} : {}] {}", logger_name, szLogLevel, log_message);
|
|
vr::VRDriverLog()->Log(vrLogMsg.c_str());
|
|
}
|
|
|
|
void flush_sink() noexcept override { }
|
|
void run_periodic_tasks() noexcept override { }
|
|
};
|
|
|
|
bool IsFileOlderThan30Days(int year, int month, int day, int hour, int minute, int second)
|
|
{
|
|
std::tm time = std::tm{ second, minute, hour, day, month - 1, year - 1900 };
|
|
auto fileTime = std::chrono::system_clock::from_time_t(std::mktime(&time));
|
|
auto currentTime = std::chrono::system_clock::now();
|
|
auto fileAge = currentTime - fileTime;
|
|
return fileAge > std::chrono::days(CLEAR_LOG_FILES_AFTER_DAYS);
|
|
}
|
|
|
|
bool ParseLogFilename(const std::string& filename, int& year, int& month, int& day, int& hour, int& minute, int& second)
|
|
{
|
|
if (filename.size() != 27) {
|
|
return false;
|
|
}
|
|
|
|
std::stringstream ss(filename.substr(4, 23));
|
|
ss >> year;
|
|
ss.ignore(1);
|
|
ss >> month;
|
|
ss.ignore(1);
|
|
ss >> day;
|
|
ss.ignore(1);
|
|
ss >> hour;
|
|
ss.ignore(1);
|
|
ss >> minute;
|
|
ss.ignore(1);
|
|
ss >> second;
|
|
|
|
return !ss.fail();
|
|
}
|
|
|
|
void DeleteOldLogFiles(const std::filesystem::path& directoryPath)
|
|
{
|
|
for (const auto& entry : std::filesystem::directory_iterator(directoryPath)) {
|
|
if (entry.is_regular_file() && entry.path().filename() != "log_latest.log") {
|
|
std::string fileName = entry.path().filename().string();
|
|
int year, month, day, hour, minute, second;
|
|
|
|
if (fileName.substr(0, 4) == "log_" && ParseLogFilename(fileName, year, month, day, hour, minute, second) && IsFileOlderThan30Days(year, month, day, hour, minute, second)) {
|
|
std::filesystem::remove(entry.path());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper for declaring a logger
|
|
#ifdef _DEBUG
|
|
#define CONSOLE_SINK quill::Frontend::create_or_get_sink<quill::ConsoleSink>("console"),
|
|
#else
|
|
#define CONSOLE_SINK
|
|
#endif
|
|
|
|
#define MAKE_LOGGER_OVERLAY(title) \
|
|
quill::Frontend::create_or_get_logger(title, \
|
|
{ \
|
|
CONSOLE_SINK \
|
|
quill::Frontend::create_or_get_sink<quill::FileSink>(logFilePath), \
|
|
quill::Frontend::create_or_get_sink<quill::FileSink>(logFilePath2), \
|
|
quill::Frontend::create_or_get_sink<UiHaltOnErrorSink>("halt_on_error") \
|
|
});
|
|
#define MAKE_LOGGER_DRIVER(title) \
|
|
quill::Frontend::create_or_get_logger(title, \
|
|
{ \
|
|
quill::Frontend::create_or_get_sink<quill::FileSink>(logFilePath), \
|
|
quill::Frontend::create_or_get_sink<quill::FileSink>(logFilePath2), \
|
|
quill::Frontend::create_or_get_sink<DriverLogSink>("driverlog") \
|
|
});
|
|
|
|
void Init(bool isOverlay)
|
|
{
|
|
assert(s_logger == nullptr);
|
|
assert(s_loggerOpenVr == nullptr);
|
|
|
|
quill::Backend::start();
|
|
|
|
auto now = std::chrono::system_clock::now();
|
|
auto time = std::chrono::system_clock::to_time_t(now);
|
|
auto tm = *std::localtime(&time);
|
|
|
|
const char* logType = isOverlay ? "overlay" : "driver";
|
|
|
|
std::string logFilePath = (util::getSpaceCalibratorLogsDir() / fmt::format("log_{}_{:%Y_%m_%d_%H_%M_%S}.log", logType, tm)).string();
|
|
std::string logFilePath2 = (util::getSpaceCalibratorLogsDir() / fmt::format("log_{}_latest.log", logType)).string();
|
|
DeleteOldLogFiles(util::getSpaceCalibratorLogsDir());
|
|
|
|
if (isOverlay) {
|
|
s_logger = MAKE_LOGGER_OVERLAY("overlay");
|
|
s_loggerOpenVr = MAKE_LOGGER_OVERLAY("openvr");
|
|
s_loggerIpc = MAKE_LOGGER_OVERLAY("ipc");
|
|
s_loggerHooking = MAKE_LOGGER_OVERLAY("hooking");
|
|
s_loggerCalibration = MAKE_LOGGER_OVERLAY("calibration");
|
|
} else {
|
|
s_logger = MAKE_LOGGER_DRIVER("driver");
|
|
s_loggerOpenVr = MAKE_LOGGER_DRIVER("openvr");
|
|
s_loggerIpc = MAKE_LOGGER_DRIVER("ipc");
|
|
s_loggerHooking = MAKE_LOGGER_DRIVER("hooking");
|
|
s_loggerCalibration = MAKE_LOGGER_DRIVER("calibration");
|
|
}
|
|
}
|
|
} |