Create log files under configDir/logs; seed initial pipeline cache

This commit is contained in:
Luke Street
2026-04-14 01:32:58 -06:00
parent 588910c642
commit 27d95c37d5
4 changed files with 186 additions and 23 deletions
+3
View File
@@ -7,6 +7,9 @@
void aurora_log_callback(AuroraLogLevel level, const char* module, const char* message, unsigned int len);
namespace dusk {
void InitializeFileLogging(const char* configDir, AuroraLogLevel logLevel);
void ShutdownFileLogging();
const char* GetLogFilePath();
void SendToStubLog(AuroraLogLevel level, const char* module, const char* message);
}
+16
View File
@@ -69,6 +69,13 @@ std::filesystem::path GetSentryDatabasePath() {
return std::filesystem::path(configPath) / "sentry";
}
std::filesystem::path GetLogAttachmentPath() {
if (const char* logPath = GetLogFilePath()) {
return logPath;
}
return {};
}
std::filesystem::path GetCrashpadHandlerPath() {
const char* basePath = SDL_GetBasePath();
if (!basePath) {
@@ -111,6 +118,15 @@ void ConfigurePathOptions(sentry_options_t* options) {
sentry_options_set_handler_path(options, handlerPathUtf8.c_str());
}
#endif
const auto logPath = GetLogAttachmentPath();
if (!logPath.empty()) {
#if _WIN32
sentry_options_add_attachmentw(options, logPath.wstring().c_str());
#else
sentry_options_add_attachment(options, logPath.string().c_str());
#endif
}
}
#endif
+118 -22
View File
@@ -1,6 +1,11 @@
#include "dusk/logging.h"
#include <array>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <mutex>
#include <string>
#include "tracy/Tracy.hpp"
@@ -20,6 +25,60 @@ static constexpr std::string_view StubFragments[] = {
"but selective updates are not implemented"sv,
};
namespace {
std::mutex g_logMutex;
FILE* g_logFile = nullptr;
std::string g_logFilePath;
const char* LogLevelString(AuroraLogLevel level) {
switch (level) {
case LOG_DEBUG:
return "DEBUG";
case LOG_INFO:
return "INFO";
case LOG_WARNING:
return "WARNING";
case LOG_ERROR:
return "ERROR";
case LOG_FATAL:
return "FATAL";
}
return "??";
}
FILE* LogStreamForLevel(AuroraLogLevel level) {
return level >= LOG_ERROR ? stderr : stdout;
}
std::string MakeTimestampedLogName() {
const auto now = std::chrono::system_clock::now();
const std::time_t nowTime = std::chrono::system_clock::to_time_t(now);
std::tm localTime{};
#if _WIN32
localtime_s(&localTime, &nowTime);
#else
localtime_r(&nowTime, &localTime);
#endif
std::array<char, 32> buffer{};
std::strftime(buffer.data(), buffer.size(), "dusk-%Y%m%d-%H%M%S.log", &localTime);
return buffer.data();
}
void WriteLogLine(FILE* out, const char* levelStr, const char* module, const char* message, unsigned int len) {
if (out == nullptr) {
return;
}
std::fprintf(out, "[%s | %s] ", levelStr, module);
std::fwrite(message, 1, len, out);
std::fputc('\n', out);
std::fflush(out);
}
} // namespace
static bool IsForStubLog(const char* message) {
std::string_view msg_view(message);
@@ -40,32 +99,69 @@ void aurora_log_callback(AuroraLogLevel level, const char* module, const char* m
return;
}
const char* levelStr = "??";
FILE* out = stdout;
switch (level) {
case LOG_DEBUG:
levelStr = "DEBUG";
break;
case LOG_INFO:
levelStr = "INFO";
break;
case LOG_WARNING:
levelStr = "WARNING";
break;
case LOG_ERROR:
levelStr = "ERROR";
out = stderr;
break;
case LOG_FATAL:
levelStr = "FATAL";
out = stderr;
break;
if (module == nullptr) {
module = "";
}
fprintf(out, "[%s | %s] %s\n", levelStr, module, message);
const char* levelStr = LogLevelString(level);
FILE* out = LogStreamForLevel(level);
WriteLogLine(out, levelStr, module, message, len);
{
std::lock_guard lock(g_logMutex);
if (g_logFile != nullptr) {
WriteLogLine(g_logFile, levelStr, module, message, len);
}
}
if (level == LOG_FATAL) {
fflush(out);
abort();
}
}
aurora::Module DuskLog("dusk");
void dusk::InitializeFileLogging(const char* configDir, AuroraLogLevel logLevel) {
std::lock_guard lock(g_logMutex);
if (g_logFile != nullptr || configDir == nullptr) {
return;
}
std::error_code ec;
const std::filesystem::path logsDir = std::filesystem::path(configDir) / "logs";
std::filesystem::create_directories(logsDir, ec);
if (ec) {
std::fprintf(stderr, "[WARNING | dusk] Failed to create log directory '%s': %s\n",
logsDir.string().c_str(), ec.message().c_str());
return;
}
const std::filesystem::path logPath = logsDir / MakeTimestampedLogName();
g_logFile = std::fopen(logPath.string().c_str(), "wb");
if (g_logFile == nullptr) {
std::fprintf(stderr, "[WARNING | dusk] Failed to open log file '%s'\n",
logPath.string().c_str());
return;
}
g_logFilePath = logPath.string();
aurora::g_config.logCallback = &aurora_log_callback;
aurora::g_config.logLevel = logLevel;
WriteLogLine(g_logFile, "INFO", "dusk", "File logging initialized", 24);
}
void dusk::ShutdownFileLogging() {
std::lock_guard lock(g_logMutex);
if (g_logFile == nullptr) {
return;
}
std::fflush(g_logFile);
std::fclose(g_logFile);
g_logFile = nullptr;
}
const char* dusk::GetLogFilePath() {
std::lock_guard lock(g_logMutex);
return g_logFilePath.empty() ? nullptr : g_logFilePath.c_str();
}
+49 -1
View File
@@ -43,6 +43,8 @@
#include <cstring>
#include <chrono>
#include <filesystem>
#include <system_error>
#include <thread>
#include "SSystem/SComponent/c_API.h"
#include "dusk/app_info.hpp"
@@ -366,6 +368,48 @@ static const char* CalculateConfigPath() {
return result;
}
static void EnsureInitialPipelineCache(const char* configDir) {
if (configDir == nullptr) {
return;
}
const std::filesystem::path configPathFs(configDir);
const std::filesystem::path pipelineCachePath = configPathFs / "pipeline_cache.db";
if (std::filesystem::exists(pipelineCachePath)) {
return;
}
const char* basePath = SDL_GetBasePath();
if (basePath == nullptr) {
DuskLog.warn("Unable to resolve base path while seeding pipeline cache: {}", SDL_GetError());
return;
}
const std::filesystem::path initialPipelineCachePath =
std::filesystem::path(basePath) / "initial_pipeline_cache.db";
if (!std::filesystem::exists(initialPipelineCachePath)) {
DuskLog.info("No bundled initial pipeline cache found at '{}'", initialPipelineCachePath.string());
return;
}
std::error_code ec;
std::filesystem::create_directories(configPathFs, ec);
if (ec) {
DuskLog.warn("Failed to create config directory '{}' for pipeline cache: {}",
configPathFs.string(), ec.message());
return;
}
std::filesystem::copy_file(initialPipelineCachePath, pipelineCachePath, std::filesystem::copy_options::none, ec);
if (ec) {
DuskLog.warn("Failed to seed pipeline cache from '{}' to '{}': {}",
initialPipelineCachePath.string(), pipelineCachePath.string(), ec.message());
return;
}
DuskLog.info("Seeded pipeline cache from '{}'", initialPipelineCachePath.string());
}
static constexpr PADDefaultMapping defaultPadMapping = {
.buttons = {
{SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A},
@@ -444,10 +488,13 @@ int game_main(int argc, char* argv[]) {
}
configPath = CalculateConfigPath();
const auto startupLogLevel = static_cast<AuroraLogLevel>(parsed_arg_options["log-level"].as<uint8_t>());
dusk::InitializeFileLogging(configPath, startupLogLevel);
dusk::config::LoadFromUserPreferences();
ApplyCVarOverrides(parsed_arg_options["cvar"]);
dusk::InitializeCrashReporting();
EnsureInitialPipelineCache(configPath);
AuroraConfig config{};
config.appName = dusk::AppName;
@@ -460,7 +507,7 @@ int game_main(int argc, char* argv[]) {
config.windowHeight = defaultWindowHeight * 2;
config.desiredBackend = ResolveDesiredBackend(parsed_arg_options);
config.logCallback = &aurora_log_callback;
config.logLevel = (AuroraLogLevel)parsed_arg_options["log-level"].as<uint8_t>();
config.logLevel = startupLogLevel;
config.mem1Size = 256 * 1024 * 1024;
config.mem2Size = 24 * 1024 * 1024;
config.allowJoystickBackgroundEvents = true;
@@ -542,6 +589,7 @@ int game_main(int argc, char* argv[]) {
main01();
dusk::ShutdownCrashReporting();
dusk::ShutdownFileLogging();
fflush(stdout);
fflush(stderr);