diff options
author | Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> | 2023-12-27 00:32:01 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-27 01:32:01 +0100 |
commit | f5ab6fb5e8be7b73e6003d4145081d5e0c0ce287 (patch) | |
tree | 90f2c6a4885dbd181799e2325cf33588697674e1 /primedev/logging/logging.cpp | |
parent | bb8ed59f6891b1196c5f5bbe7346cd171c8215fa (diff) | |
download | NorthstarLauncher-f5ab6fb5e8be7b73e6003d4145081d5e0c0ce287.tar.gz NorthstarLauncher-f5ab6fb5e8be7b73e6003d4145081d5e0c0ce287.zip |
Folder restructuring from primedev (#624)v1.21.2-rc3v1.21.2
Copies of over the primedev folder structure for easier cherry-picking of further changes
Co-authored-by: F1F7Y <filip.bartos07@proton.me>
Diffstat (limited to 'primedev/logging/logging.cpp')
-rw-r--r-- | primedev/logging/logging.cpp | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/primedev/logging/logging.cpp b/primedev/logging/logging.cpp new file mode 100644 index 00000000..3416bb8c --- /dev/null +++ b/primedev/logging/logging.cpp @@ -0,0 +1,302 @@ +#include "logging.h" +#include "core/convar/convar.h" +#include "core/convar/concommand.h" +#include "config/profile.h" +#include "core/tier0.h" +#include "util/version.h" +#include "spdlog/sinks/basic_file_sink.h" + +#include <winternl.h> +#include <cstdlib> +#include <iomanip> +#include <sstream> + +AUTOHOOK_INIT() + +std::vector<std::shared_ptr<ColoredLogger>> loggers {}; + +namespace NS::log +{ + std::shared_ptr<ColoredLogger> SCRIPT_UI; + std::shared_ptr<ColoredLogger> SCRIPT_CL; + std::shared_ptr<ColoredLogger> SCRIPT_SV; + + std::shared_ptr<ColoredLogger> NATIVE_UI; + std::shared_ptr<ColoredLogger> NATIVE_CL; + std::shared_ptr<ColoredLogger> NATIVE_SV; + std::shared_ptr<ColoredLogger> NATIVE_EN; + + std::shared_ptr<ColoredLogger> fs; + std::shared_ptr<ColoredLogger> rpak; + std::shared_ptr<ColoredLogger> echo; + + std::shared_ptr<ColoredLogger> NORTHSTAR; + std::shared_ptr<ColoredLogger> PLUGINSYS; +}; // namespace NS::log + +// This needs to be called after hooks are loaded so we can access the command line args +void CreateLogFiles() +{ + if (strstr(GetCommandLineA(), "-disablelogs")) + { + spdlog::default_logger()->set_level(spdlog::level::off); + } + else + { + try + { + // todo: might be good to delete logs that are too old + time_t time = std::time(nullptr); + tm currentTime = *std::localtime(&time); + std::stringstream stream; + + stream << std::put_time(¤tTime, (GetNorthstarPrefix() + "/logs/nslog%Y-%m-%d %H-%M-%S.txt").c_str()); + auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(stream.str(), false); + sink->set_pattern("[%Y-%m-%d] [%H:%M:%S] [%n] [%l] %v"); + for (auto& logger : loggers) + { + logger->sinks().push_back(sink); + } + spdlog::flush_on(spdlog::level::info); + } + catch (...) + { + spdlog::error("Failed creating log file!"); + MessageBoxA( + 0, "Failed creating log file! Make sure the profile directory is writable.", "Northstar Warning", MB_ICONWARNING | MB_OK); + } + } +} + +void ExternalConsoleSink::sink_it_(const spdlog::details::log_msg& msg) +{ + throw std::runtime_error("sink_it_ called on SourceConsoleSink with pure log_msg. This is an error!"); +} + +void ExternalConsoleSink::custom_sink_it_(const custom_log_msg& msg) +{ + spdlog::memory_buf_t formatted; + spdlog::sinks::base_sink<std::mutex>::formatter_->format(msg, formatted); + + std::string out = ""; + // if ansi colour is turned off, just use WriteConsoleA and return + if (!g_bSpdLog_UseAnsiColor) + { + out += fmt::to_string(formatted); + } + + // print to the console with colours + else + { + // get message string + std::string str = fmt::to_string(formatted); + + std::string levelColor = m_LogColours[msg.level]; + std::string name {msg.logger_name.begin(), msg.logger_name.end()}; + + std::string name_str = "[NAME]"; + int name_pos = str.find(name_str); + str.replace(name_pos, name_str.length(), msg.origin->ANSIColor + "[" + name + "]" + default_color); + + std::string level_str = "[LVL]"; + int level_pos = str.find(level_str); + str.replace(level_pos, level_str.length(), levelColor + "[" + std::string(level_names[msg.level]) + "]" + default_color); + + out += str; + } + // print the string to the console - this is definitely bad i think + HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); + auto ignored = WriteConsoleA(handle, out.c_str(), std::strlen(out.c_str()), nullptr, nullptr); + (void)ignored; +} + +void ExternalConsoleSink::flush_() +{ + std::cout << std::flush; +} + +void CustomSink::custom_log(const custom_log_msg& msg) +{ + std::lock_guard<std::mutex> lock(mutex_); + custom_sink_it_(msg); +} + +void InitialiseConsole() +{ + if (AllocConsole() == FALSE) + { + std::cout << "[*] Failed to create a console window, maybe a console already exists?" << std::endl; + } + else + { + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + } + + // this if statement is adapted from r5sdk + if (!strstr(GetCommandLineA(), "-noansiclr")) + { + g_bSpdLog_UseAnsiColor = true; + DWORD dwMode = 0; + HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); + + GetConsoleMode(hOutput, &dwMode); + dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + if (!SetConsoleMode(hOutput, dwMode)) // Some editions of Windows have 'VirtualTerminalLevel' disabled by default. + { + // If 'VirtualTerminalLevel' can't be set, just disable ANSI color, since it wouldnt work anyway. + spdlog::warn("could not set VirtualTerminalLevel. Disabling color output"); + g_bSpdLog_UseAnsiColor = false; + } + } +} + +void RegisterLogger(std::shared_ptr<ColoredLogger> logger) +{ + loggers.push_back(logger); +} + +void RegisterCustomSink(std::shared_ptr<CustomSink> sink) +{ + for (auto& logger : loggers) + { + logger->custom_sinks_.push_back(sink); + } +}; + +void InitialiseLogging() +{ + // create a logger, and set it to default + NS::log::NORTHSTAR = std::make_shared<ColoredLogger>("NORTHSTAR", NS::Colors::NORTHSTAR, true); + NS::log::NORTHSTAR->sinks().clear(); + loggers.push_back(NS::log::NORTHSTAR); + spdlog::set_default_logger(NS::log::NORTHSTAR); + + // create our console sink + auto sink = std::make_shared<ExternalConsoleSink>(); + // set the pattern + if (g_bSpdLog_UseAnsiColor) + // dont put the log level in the pattern if we are using colours, as the colour will show the log level + sink->set_pattern("[%H:%M:%S] [NAME] [LVL] %v"); + else + sink->set_pattern("[%H:%M:%S] [%n] [%l] %v"); + + // add our sink to the logger + NS::log::NORTHSTAR->custom_sinks_.push_back(sink); + + NS::log::SCRIPT_UI = std::make_shared<ColoredLogger>("SCRIPT UI", NS::Colors::SCRIPT_UI); + NS::log::SCRIPT_CL = std::make_shared<ColoredLogger>("SCRIPT CL", NS::Colors::SCRIPT_CL); + NS::log::SCRIPT_SV = std::make_shared<ColoredLogger>("SCRIPT SV", NS::Colors::SCRIPT_SV); + + NS::log::NATIVE_UI = std::make_shared<ColoredLogger>("NATIVE UI", NS::Colors::NATIVE_UI); + NS::log::NATIVE_CL = std::make_shared<ColoredLogger>("NATIVE CL", NS::Colors::NATIVE_CL); + NS::log::NATIVE_SV = std::make_shared<ColoredLogger>("NATIVE SV", NS::Colors::NATIVE_SV); + NS::log::NATIVE_EN = std::make_shared<ColoredLogger>("NATIVE EN", NS::Colors::NATIVE_ENGINE); + + NS::log::fs = std::make_shared<ColoredLogger>("FILESYSTM", NS::Colors::FILESYSTEM); + NS::log::rpak = std::make_shared<ColoredLogger>("RPAK_FSYS", NS::Colors::RPAK); + NS::log::echo = std::make_shared<ColoredLogger>("ECHO", NS::Colors::ECHO); + + NS::log::PLUGINSYS = std::make_shared<ColoredLogger>("PLUGINSYS", NS::Colors::PLUGINSYS); + + loggers.push_back(NS::log::SCRIPT_UI); + loggers.push_back(NS::log::SCRIPT_CL); + loggers.push_back(NS::log::SCRIPT_SV); + + loggers.push_back(NS::log::NATIVE_UI); + loggers.push_back(NS::log::NATIVE_CL); + loggers.push_back(NS::log::NATIVE_SV); + loggers.push_back(NS::log::NATIVE_EN); + + loggers.push_back(NS::log::PLUGINSYS); + + loggers.push_back(NS::log::fs); + loggers.push_back(NS::log::rpak); + loggers.push_back(NS::log::echo); +} + +void NS::log::FlushLoggers() +{ + for (auto& logger : loggers) + logger->flush(); + + spdlog::default_logger()->flush(); +} + +// Wine specific functions +typedef const char*(CDECL* wine_get_host_version_type)(const char**, const char**); +wine_get_host_version_type wine_get_host_version; + +typedef const char*(CDECL* wine_get_build_id_type)(void); +wine_get_build_id_type wine_get_build_id; + +// Not exported Winapi methods +typedef NTSTATUS(WINAPI* RtlGetVersion_type)(PRTL_OSVERSIONINFOW); +RtlGetVersion_type RtlGetVersion; + +void StartupLog() +{ + spdlog::info("NorthstarLauncher version: {}", version); + spdlog::info("Command line: {}", GetCommandLineA()); + spdlog::info("Using profile: {}", GetNorthstarPrefix()); + + HMODULE ntdll = GetModuleHandleA("ntdll.dll"); + if (!ntdll) + { + // How did we get here + spdlog::info("Operating System: Unknown"); + return; + } + + wine_get_host_version = (wine_get_host_version_type)GetProcAddress(ntdll, "wine_get_host_version"); + if (wine_get_host_version) + { + // Load the rest of the functions we need + wine_get_build_id = (wine_get_build_id_type)GetProcAddress(ntdll, "wine_get_build_id"); + + const char* sysname; + wine_get_host_version(&sysname, NULL); + + spdlog::info("Operating System: {} (Wine)", sysname); + spdlog::info("Wine build: {}", wine_get_build_id()); + + // STEAM_COMPAT_TOOL_PATHS is a colon separated lists of all compat tool paths used + // The first one tends to be the Proton path itself + // We extract the basename out of it to get the name used + char* compatToolPtr = std::getenv("STEAM_COMPAT_TOOL_PATHS"); + if (compatToolPtr) + { + std::string_view compatToolPath(compatToolPtr); + + auto protonBasenameEnd = compatToolPath.find(":"); + if (protonBasenameEnd == std::string_view::npos) + protonBasenameEnd = 0; + auto protonBasenameStart = compatToolPath.rfind("/", protonBasenameEnd) + 1; + if (protonBasenameStart == std::string_view::npos) + protonBasenameStart = 0; + + spdlog::info("Proton build: {}", compatToolPath.substr(protonBasenameStart, protonBasenameEnd - protonBasenameStart)); + } + } + else + { + // We are real Windows (hopefully) + const char* win_ver = "Unknown"; + + RTL_OSVERSIONINFOW osvi; + osvi.dwOSVersionInfoSize = sizeof(osvi); + + RtlGetVersion = (RtlGetVersion_type)GetProcAddress(ntdll, "RtlGetVersion"); + if (RtlGetVersion && !RtlGetVersion(&osvi)) + { + // Version reference table + // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoa#remarks + spdlog::info("Operating System: Windows (NT{}.{})", osvi.dwMajorVersion, osvi.dwMinorVersion); + } + else + { + spdlog::info("Operating System: Windows"); + } + } +} |