diff --git a/contrib/Distribution/Config/CrashLogger.ini b/contrib/Distribution/Config/CrashLogger.ini index 7728dd4..25eda1b 100644 --- a/contrib/Distribution/Config/CrashLogger.ini +++ b/contrib/Distribution/Config/CrashLogger.ini @@ -11,3 +11,6 @@ Wait for Debugger for Crash = false ;Local symbol cache directory. Symcache Directory = c:\symcache + +;Crashlog output directory. Defaults to "Documents\my games\[Skyrim]\SKSE" +Crashlog Directory = "" diff --git a/src/Crash/CrashHandler.cpp b/src/Crash/CrashHandler.cpp index 6509078..f05f43d 100644 --- a/src/Crash/CrashHandler.cpp +++ b/src/Crash/CrashHandler.cpp @@ -129,11 +129,7 @@ namespace Crash { [[nodiscard]] std::shared_ptr get_log() { - auto path = logger::log_directory(); - if (!path) { - util::report_and_fail("failed to find standard log directory"sv); - } - + std::optional path = crashPath; const auto time = std::time(nullptr); std::tm localTime{}; if (gmtime_s(&localTime, &time) != 0) { @@ -555,7 +551,7 @@ namespace Crash } } // namespace - void Install() + void Install(std::string a_crashPath) { const auto success = ::AddVectoredExceptionHandler(1, reinterpret_cast<::PVECTORED_EXCEPTION_HANDLER>(&VectoredExceptions)); @@ -563,5 +559,9 @@ namespace Crash util::report_and_fail("failed to install vectored exception handler"sv); } logger::info("installed crash handlers"sv); + if (!a_crashPath.empty()) { + crashPath = a_crashPath; + logger::info("Crash Logs will be written to {}", crashPath); + } } } // namespace Crash diff --git a/src/Crash/CrashHandler.h b/src/Crash/CrashHandler.h index 0a3c198..7ee1ce2 100644 --- a/src/Crash/CrashHandler.h +++ b/src/Crash/CrashHandler.h @@ -38,5 +38,6 @@ namespace Crash std::span _frames; }; - void Install(); + void Install(std::string a_crashPath); + static std::string crashPath; } diff --git a/src/Settings.cpp b/src/Settings.cpp index 46b6b7a..83e373e 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -29,6 +29,8 @@ void Settings::Debug::Load(CSimpleIniA& a_ini) get_value(a_ini, flushLevel, section, "Flush Level", ";Log level to force messages to print from buffer."); get_value(a_ini, waitForDebugger, section, "Wait for Debugger for Crash", ";Enable if using VisualStudio to debug CrashLogger; Set false otherwise because Crashlogger will not produce a crash until the debugger is detected."); get_value(a_ini, symcache, section, "Symcache Directory", ";Local symbol cache directory."); + std::string crashDirectoryComment = std::format("; Crashlog output directory. If blank, defaults to \"Documents\\my games\\{}\\SKSE\\\"", !REL::Module::IsVR() ? "Skyrim Special Edition" : "Skyrim VR"); + get_value(a_ini, crashDirectory, section, "Crashlog Directory", crashDirectoryComment.c_str()); } const Settings::Debug& Settings::GetDebug() const diff --git a/src/Settings.h b/src/Settings.h index e08b995..6f53870 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -12,6 +12,7 @@ class Settings spdlog::level::level_enum flushLevel{ spdlog::level::level_enum::trace }; bool waitForDebugger{ false }; std::string symcache{ "" }; + std::string crashDirectory{ "" }; }; [[nodiscard]] static Settings* GetSingleton(); diff --git a/src/main.cpp b/src/main.cpp index bf838b8..2b5edac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -58,6 +58,33 @@ namespace logger::info("Log Level: {}", spdlog::level::to_string_view(spdlog::get_level())); } + std::string SetupCrashLogPath() + { + std::optional path; + const auto& debugConfig = Settings::GetSingleton()->GetDebug(); + if (!debugConfig.crashDirectory.empty()) { + path.emplace(debugConfig.crashDirectory); + } else { + if (!logger::log_directory()) { + util::report_and_fail("failed to find standard log directory"sv); + } + path = logger::log_directory(); + } + try { + if (!std::filesystem::exists(path.value())) { + std::filesystem::create_directories(path.value()); + } + } + catch (const std::filesystem::filesystem_error& e) { + auto errorString = std::format("Unable to create Crashlog output directory: {}", e.what()); + util::report_and_fail(errorString); + } + if (path.has_value()) { + return path.value().string(); + } + return ""; + } + /** * Initialize the SKSE cosave system for our plugin. * @@ -197,7 +224,7 @@ SKSEPluginLoad(const LoadInterface* skse) log::info("NOTE: This is not a crashlog. Crashlogs have the name crash-[TIMESTAMP].log"); log::info("{} {} {} {} is loading...", plugin->GetName(), version, __DATE__, __TIME__); Init(skse); - Crash::Install(); + Crash::Install(SetupCrashLogPath()); //InitializeMessaging(); //InitializeSerialization(); //InitializePapyrus();