Core: Only initialize logging once (#4509)

* Only initialize logging once

* Swap LOG macros for std::cerr and std::cout use.

* Add quick exit when trying to log before logger init

* Revert "Swap LOG macros for std::cerr and std::cout use."

This reverts commit a14d46d383.

* Use fmt's functions instead of cerr

Makes the commits a tad cleaner.

* Revert macro change

If I remember right, the if check here was to make sure we didn't throw exceptions after terminating the logger, which can happen due to a race involving some debug libSceVideoOut logs.

* Oops
This commit is contained in:
Stephen Miller 2026-06-02 01:03:18 -04:00 committed by GitHub
parent 87e774c4a1
commit 0b9eb3dd17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 37 additions and 65 deletions

View File

@ -78,13 +78,12 @@ bool KeyManager::LoadFromFile() {
SetDefaultKeys(); SetDefaultKeys();
TransferTrophyKey(); TransferTrophyKey();
SaveToFile(); SaveToFile();
LOG_DEBUG(KeyManager, "Created default key file: {}", keysPath.string());
return true; return true;
} }
std::ifstream file(keysPath); std::ifstream file(keysPath);
if (!file.is_open()) { if (!file.is_open()) {
LOG_ERROR(KeyManager, "Could not open key file: {}", keysPath.string()); fmt::println("Could not open key file: {}", keysPath.string());
return false; return false;
} }
@ -104,12 +103,10 @@ bool KeyManager::LoadFromFile() {
SaveToFile(); SaveToFile();
} }
} }
LOG_DEBUG(KeyManager, "Successfully loaded keys from: {}", keysPath.string());
return true; return true;
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_ERROR(KeyManager, "Error loading keys, using defaults: {}", e.what()); fmt::println("Error loading keys, using defaults: {}", e.what());
SetDefaultKeys(); SetDefaultKeys();
return false; return false;
} }
@ -125,7 +122,7 @@ bool KeyManager::SaveToFile() {
std::ofstream file(keysPath); std::ofstream file(keysPath);
if (!file.is_open()) { if (!file.is_open()) {
LOG_ERROR(KeyManager, "Could not open key file for writing: {}", keysPath.string()); fmt::println("Could not open key file for writing: {}", keysPath.string());
return false; return false;
} }
@ -133,15 +130,13 @@ bool KeyManager::SaveToFile() {
file.flush(); file.flush();
if (file.fail()) { if (file.fail()) {
LOG_ERROR(KeyManager, "Failed to write keys to: {}", keysPath.string()); fmt::println("Failed to write keys to: {}", keysPath.string());
return false; return false;
} }
LOG_DEBUG(KeyManager, "Successfully saved keys to: {}", keysPath.string());
return true; return true;
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_ERROR(KeyManager, "Error saving keys: {}", e.what()); fmt::println("Error saving keys: {}", e.what());
return false; return false;
} }
} }

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <iostream>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <spdlog/details/fmt_helper.h> #include <spdlog/details/fmt_helper.h>

View File

@ -89,12 +89,11 @@ std::optional<T> get_optional(const toml::value& v, const std::string& key) {
void EmulatorSettingsImpl::PrintChangedSummary(const std::vector<std::string>& changed) { void EmulatorSettingsImpl::PrintChangedSummary(const std::vector<std::string>& changed) {
if (changed.empty()) { if (changed.empty()) {
LOG_DEBUG(Config, "No game-specific overrides applied");
return; return;
} }
LOG_DEBUG(Config, "Game-specific overrides applied:"); fmt::println("Game-specific overrides applied:");
for (const auto& k : changed) for (const auto& k : changed)
LOG_DEBUG(Config, " * {}", k); fmt::println(" * {}", k);
} }
// ── Singleton ──────────────────────────────────────────────────────── // ── Singleton ────────────────────────────────────────────────────────
@ -232,7 +231,6 @@ void EmulatorSettingsImpl::ClearGameSpecificOverrides() {
ClearGroupOverrides(m_audio); ClearGroupOverrides(m_audio);
ClearGroupOverrides(m_gpu); ClearGroupOverrides(m_gpu);
ClearGroupOverrides(m_vulkan); ClearGroupOverrides(m_vulkan);
LOG_DEBUG(Config, "All game-specific overrides cleared");
} }
void EmulatorSettingsImpl::ResetGameSpecificValue(const std::string& key) { void EmulatorSettingsImpl::ResetGameSpecificValue(const std::string& key) {
@ -260,7 +258,7 @@ void EmulatorSettingsImpl::ResetGameSpecificValue(const std::string& key) {
return; return;
if (tryGroup(m_vulkan)) if (tryGroup(m_vulkan))
return; return;
LOG_WARNING(Config, "ResetGameSpecificValue: key '{}' not found", key); fmt::println("ResetGameSpecificValue: key '{}' not found", key);
} }
bool EmulatorSettingsImpl::Save(const std::string& serial) { bool EmulatorSettingsImpl::Save(const std::string& serial) {
@ -302,7 +300,7 @@ bool EmulatorSettingsImpl::Save(const std::string& serial) {
std::ofstream out(path); std::ofstream out(path);
if (!out) { if (!out) {
LOG_ERROR(Config, "Failed to open game config for writing: {}", path.string()); fmt::println("Failed to open game config for writing: {}", path.string());
return false; return false;
} }
out << std::setw(2) << j; out << std::setw(2) << j;
@ -344,14 +342,14 @@ bool EmulatorSettingsImpl::Save(const std::string& serial) {
std::ofstream out(path); std::ofstream out(path);
if (!out) { if (!out) {
LOG_ERROR(Config, "Failed to open config for writing: {}", path.string()); fmt::println("Failed to open config for writing: {}", path.string());
return false; return false;
} }
out << std::setw(2) << existing; out << std::setw(2) << existing;
return !out.fail(); return !out.fail();
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_ERROR(Config, "Error saving settings: {}", e.what()); fmt::println("Error saving settings: {}", e.what());
return false; return false;
} }
} }
@ -364,7 +362,6 @@ bool EmulatorSettingsImpl::Load(const std::string& serial) {
// ── Global config ────────────────────────────────────────── // ── Global config ──────────────────────────────────────────
const auto userDir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); const auto userDir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
const auto configPath = userDir / "config.json"; const auto configPath = userDir / "config.json";
LOG_DEBUG(Config, "Loading global config from: {}", configPath.string());
if (std::ifstream in{configPath}; in.good()) { if (std::ifstream in{configPath}; in.good()) {
json gj; json gj;
@ -385,8 +382,6 @@ bool EmulatorSettingsImpl::Load(const std::string& serial) {
mergeGroup(m_audio, "Audio"); mergeGroup(m_audio, "Audio");
mergeGroup(m_gpu, "GPU"); mergeGroup(m_gpu, "GPU");
mergeGroup(m_vulkan, "Vulkan"); mergeGroup(m_vulkan, "Vulkan");
LOG_DEBUG(Config, "Global config loaded successfully");
} else { } else {
if (std::filesystem::exists(Common::FS::GetUserPath(Common::FS::PathType::UserDir) / if (std::filesystem::exists(Common::FS::GetUserPath(Common::FS::PathType::UserDir) /
"config.toml")) { "config.toml")) {
@ -420,7 +415,6 @@ bool EmulatorSettingsImpl::Load(const std::string& serial) {
} }
} }
} }
LOG_DEBUG(Config, "Global config not found - using defaults");
SetDefaultValues(); SetDefaultValues();
Save(); Save();
} }
@ -436,16 +430,13 @@ bool EmulatorSettingsImpl::Load(const std::string& serial) {
// base configuration. // base configuration.
const auto gamePath = const auto gamePath =
Common::FS::GetUserPath(Common::FS::PathType::CustomConfigs) / (serial + ".json"); Common::FS::GetUserPath(Common::FS::PathType::CustomConfigs) / (serial + ".json");
LOG_DEBUG(Config, "Applying game config: {}", gamePath.string());
if (!std::filesystem::exists(gamePath)) { if (!std::filesystem::exists(gamePath)) {
LOG_DEBUG(Config, "No game-specific config found for {}", serial);
return false; return false;
} }
std::ifstream in(gamePath); std::ifstream in(gamePath);
if (!in) { if (!in) {
LOG_ERROR(Config, "Failed to open game config: {}", gamePath.string());
return false; return false;
} }
@ -478,7 +469,7 @@ bool EmulatorSettingsImpl::Load(const std::string& serial) {
return true; return true;
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_ERROR(Config, "Error loading settings: {}", e.what()); fmt::println("Error loading settings: {}", e.what());
return false; return false;
} }
} }
@ -678,7 +669,7 @@ bool EmulatorSettingsImpl::TransferSettings() {
} }
s.install_dirs.value = settings_install_dirs; s.install_dirs.value = settings_install_dirs;
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_WARNING(Config, "Failed to transfer install directories: {}", e.what()); fmt::println("Failed to transfer install directories: {}", e.what());
} }
// Transfer addon install directory // Transfer addon install directory
@ -694,7 +685,7 @@ bool EmulatorSettingsImpl::TransferSettings() {
} }
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_WARNING(Config, "Failed to transfer addon install directory: {}", e.what()); fmt::println("Failed to transfer addon install directory: {}", e.what());
} }
} }
if (og_data.contains("General")) { if (og_data.contains("General")) {
@ -713,7 +704,7 @@ bool EmulatorSettingsImpl::TransferSettings() {
} }
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_WARNING(Config, "Failed to transfer sysmodules install directory: {}", e.what()); fmt::println("Failed to transfer sysmodules install directory: {}", e.what());
} }
// Transfer font install directory // Transfer font install directory
@ -729,7 +720,7 @@ bool EmulatorSettingsImpl::TransferSettings() {
} }
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_WARNING(Config, "Failed to transfer font install directory: {}", e.what()); fmt::println("Failed to transfer font install directory: {}", e.what());
} }
} }

View File

@ -116,26 +116,20 @@ inline OverrideItem make_override(const char* key, Setting<T> Struct::* member)
return OverrideItem{ return OverrideItem{
key, key,
[member, key](void* base, const nlohmann::json& entry, std::vector<std::string>& changed) { [member, key](void* base, const nlohmann::json& entry, std::vector<std::string>& changed) {
LOG_DEBUG(Config, "[make_override] Processing key: {}", key);
LOG_DEBUG(Config, "[make_override] Entry JSON: {}", entry.dump());
Struct* obj = reinterpret_cast<Struct*>(base); Struct* obj = reinterpret_cast<Struct*>(base);
Setting<T>& dst = obj->*member; Setting<T>& dst = obj->*member;
try { try {
T newValue = entry.get<T>(); T newValue = entry.get<T>();
LOG_DEBUG(Config, "[make_override] Parsed value: {}", newValue);
LOG_DEBUG(Config, "[make_override] Current value: {}", dst.value);
if (dst.value != newValue) { if (dst.value != newValue) {
std::ostringstream oss; std::ostringstream oss;
oss << key << " ( " << dst.value << " " << newValue << " )"; oss << key << " ( " << dst.value << " -> " << newValue << " )";
changed.push_back(oss.str()); changed.push_back(oss.str());
LOG_DEBUG(Config, "[make_override] Recorded change: {}", oss.str());
} }
dst.game_specific_value = newValue; dst.game_specific_value = newValue;
LOG_DEBUG(Config, "[make_override] Successfully updated {}", key);
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_ERROR(Config, "[make_override] ERROR parsing {}: {}", key, e.what()); fmt::println("[make_override] error parsing {}: {}", key, e.what());
LOG_ERROR(Config, "[make_override] Entry was: {}", entry.dump()); fmt::println("[make_override] Entry was: {}", entry.dump());
LOG_ERROR(Config, "[make_override] Type name: {}", entry.type_name()); fmt::println("[make_override] Type name: {}", entry.type_name());
} }
}, },

View File

@ -59,13 +59,13 @@ bool UserSettingsImpl::Save() const {
std::ofstream out(path); std::ofstream out(path);
if (!out) { if (!out) {
LOG_ERROR(Config, "Failed to open user settings for writing: {}", path.string()); fmt::println("Failed to open user settings for writing: {}", path.string());
return false; return false;
} }
out << std::setw(2) << existing; out << std::setw(2) << existing;
return !out.fail(); return !out.fail();
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_ERROR(Config, "Error saving user settings: {}", e.what()); fmt::println("Error saving user settings: {}", e.what());
return false; return false;
} }
} }
@ -74,7 +74,6 @@ bool UserSettingsImpl::Load() {
const auto path = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "users.json"; const auto path = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "users.json";
try { try {
if (!std::filesystem::exists(path)) { if (!std::filesystem::exists(path)) {
LOG_DEBUG(Config, "User settings file not found: {}", path.string());
if (m_userManager.GetUsers().user.empty()) if (m_userManager.GetUsers().user.empty())
m_userManager.GetUsers() = m_userManager.CreateDefaultUsers(); m_userManager.GetUsers() = m_userManager.CreateDefaultUsers();
m_loaded = true; m_loaded = true;
@ -84,7 +83,7 @@ bool UserSettingsImpl::Load() {
std::ifstream in(path); std::ifstream in(path);
if (!in) { if (!in) {
LOG_ERROR(Config, "Failed to open user settings: {}", path.string()); fmt::println("Failed to open user settings: {}", path.string());
return false; return false;
} }
@ -103,15 +102,13 @@ bool UserSettingsImpl::Load() {
m_userManager.GetUsers() = default_users; m_userManager.GetUsers() = default_users;
} }
LOG_DEBUG(Config, "User settings loaded successfully");
m_loaded = true; m_loaded = true;
if (m_userManager.GetUsers().commit_hash != Common::g_scm_rev) if (m_userManager.GetUsers().commit_hash != Common::g_scm_rev)
Save(); Save();
return true; return true;
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG_ERROR(Config, "Error loading user settings: {}", e.what()); fmt::println("Error loading user settings: {}", e.what());
if (m_userManager.GetUsers().user.empty()) if (m_userManager.GetUsers().user.empty())
m_userManager.GetUsers() = m_userManager.CreateDefaultUsers(); m_userManager.GetUsers() = m_userManager.CreateDefaultUsers();
return false; return false;

View File

@ -252,6 +252,11 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
} }
} }
// Initialize logging as soon as possible
EmulatorSettings.Load(id);
Common::Log::Setup((!id.empty() && EmulatorSettings.IsLogSeparate()) ? id + ".log"
: "shad_log.txt");
auto guest_eboot_path = "/app0/" + eboot_name.generic_string(); auto guest_eboot_path = "/app0/" + eboot_name.generic_string();
const auto eboot_path = mnt->GetHostPath(guest_eboot_path); const auto eboot_path = mnt->GetHostPath(guest_eboot_path);
@ -271,12 +276,6 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
} }
game_info.game_folder = game_folder; game_info.game_folder = game_folder;
EmulatorSettings.Load(id);
Common::Log::Shutdown();
// Initialize logging as soon as possible
Common::Log::Setup((!id.empty() && EmulatorSettings.IsLogSeparate()) ? id + ".log"
: "shad_log.txt");
if (!std::filesystem::exists(file)) { if (!std::filesystem::exists(file)) {
LOG_CRITICAL(Loader, "eboot.bin does not exist: {}", LOG_CRITICAL(Loader, "eboot.bin does not exist: {}",

View File

@ -115,18 +115,18 @@ SDL_Texture* LoadSdlTextureData(std::vector<u8> data) {
unsigned char* image_data = stbi_load_from_memory( unsigned char* image_data = stbi_load_from_memory(
(const unsigned char*)data.data(), (int)data.size(), &image_width, &image_height, NULL, 4); (const unsigned char*)data.data(), (int)data.size(), &image_width, &image_height, NULL, 4);
if (image_data == nullptr) { if (image_data == nullptr) {
LOG_ERROR(ImGui, "Failed to load image: {}", stbi_failure_reason()); fmt::println("Failed to load image: {}", stbi_failure_reason());
} }
SDL_Surface* surface = SDL_CreateSurfaceFrom(image_width, image_height, SDL_PIXELFORMAT_RGBA32, SDL_Surface* surface = SDL_CreateSurfaceFrom(image_width, image_height, SDL_PIXELFORMAT_RGBA32,
(void*)image_data, channels * image_width); (void*)image_data, channels * image_width);
if (surface == nullptr) { if (surface == nullptr) {
LOG_ERROR(ImGui, "Unable to create SDL surface: {}", SDL_GetError()); fmt::println("Unable to create SDL surface: {}", SDL_GetError());
} }
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
if (texture == nullptr) { if (texture == nullptr) {
LOG_ERROR(ImGui, "Unable to create SDL texture: {}", SDL_GetError()); fmt::println("Unable to create SDL texture: {}", SDL_GetError());
} }
SDL_DestroySurface(surface); SDL_DestroySurface(surface);
@ -190,13 +190,13 @@ void GetGameIconInfo(std::vector<IconInfo>& icons) {
void Launch(char* executableName) { void Launch(char* executableName) {
if (!SDL_Init(SDL_INIT_VIDEO)) { if (!SDL_Init(SDL_INIT_VIDEO)) {
LOG_ERROR(ImGui, "SDL_INIT_VIDEO Error: {}", SDL_GetError()); fmt::println("SDL_INIT_VIDEO Error: {}", SDL_GetError());
SDL_Quit(); SDL_Quit();
return; return;
} }
if (!SDL_Init(SDL_INIT_GAMEPAD)) { if (!SDL_Init(SDL_INIT_GAMEPAD)) {
LOG_ERROR(ImGui, "SDL_INIT_GAMEPAD Error: {}", SDL_GetError()); fmt::println("SDL_INIT_GAMEPAD Error: {}", SDL_GetError());
} }
SDL_Window* window = SDL_Window* window =
@ -204,7 +204,7 @@ void Launch(char* executableName) {
renderer = SDL_CreateRenderer(window, nullptr); renderer = SDL_CreateRenderer(window, nullptr);
if (window == nullptr) { if (window == nullptr) {
LOG_ERROR(ImGui, "SDL Window Creation Error: {}", SDL_GetError()); fmt::println("SDL Window Creation Error: {}", SDL_GetError());
SDL_DestroyRenderer(renderer); SDL_DestroyRenderer(renderer);
SDL_Quit(); SDL_Quit();
return; return;

View File

@ -103,9 +103,6 @@ int main(int argc, char* argv[]) {
if (waitPid) if (waitPid)
Core::Debugger::WaitForPid(*waitPid); Core::Debugger::WaitForPid(*waitPid);
// Start default log
Common::Log::Setup("shad_log.txt");
IPC::Instance().Init(); IPC::Instance().Init();
auto emu_state = std::make_shared<EmulatorState>(); auto emu_state = std::make_shared<EmulatorState>();
@ -121,10 +118,8 @@ int main(int argc, char* argv[]) {
EmulatorSettingsImpl::SetInstance(emu_settings); EmulatorSettingsImpl::SetInstance(emu_settings);
emu_settings->Load(); emu_settings->Load();
Common::Log::Shutdown(); // Configure logger appropriately
// Start configured log
Common::Log::g_should_append |= EmulatorSettings.IsLogAppend(); Common::Log::g_should_append |= EmulatorSettings.IsLogAppend();
Common::Log::Setup("shad_log.txt");
if (bigPicture) { if (bigPicture) {
BigPictureMode::Launch(argv[0]); BigPictureMode::Launch(argv[0]);