summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/logging/backend.cpp350
-rw-r--r--src/common/logging/backend.h113
-rw-r--r--src/core/core.cpp9
-rw-r--r--src/core/core.h9
-rw-r--r--src/tests/common/param_package.cpp2
-rw-r--r--src/yuzu/debugger/console.cpp11
-rw-r--r--src/yuzu/main.cpp19
-rw-r--r--src/yuzu_cmd/yuzu.cpp22
8 files changed, 243 insertions, 292 deletions
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 61dddab3f..13edda9c9 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -2,13 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <atomic> 5#include <atomic>
7#include <chrono> 6#include <chrono>
8#include <climits> 7#include <climits>
9#include <condition_variable>
10#include <memory>
11#include <mutex>
12#include <thread> 8#include <thread>
13#include <vector> 9#include <vector>
14 10
@@ -16,104 +12,229 @@
16#include <windows.h> // For OutputDebugStringW 12#include <windows.h> // For OutputDebugStringW
17#endif 13#endif
18 14
19#include "common/assert.h"
20#include "common/fs/file.h" 15#include "common/fs/file.h"
21#include "common/fs/fs.h" 16#include "common/fs/fs.h"
17#include "common/fs/fs_paths.h"
18#include "common/fs/path_util.h"
22#include "common/literals.h" 19#include "common/literals.h"
23 20
24#include "common/logging/backend.h" 21#include "common/logging/backend.h"
25#include "common/logging/log.h" 22#include "common/logging/log.h"
26#include "common/logging/text_formatter.h" 23#include "common/logging/text_formatter.h"
27#include "common/settings.h" 24#include "common/settings.h"
25#ifdef _WIN32
28#include "common/string_util.h" 26#include "common/string_util.h"
27#endif
29#include "common/threadsafe_queue.h" 28#include "common/threadsafe_queue.h"
30 29
31namespace Common::Log { 30namespace Common::Log {
32 31
32namespace {
33
33/** 34/**
34 * Static state as a singleton. 35 * Interface for logging backends.
35 */ 36 */
36class Impl { 37class Backend {
37public: 38public:
38 static Impl& Instance() { 39 virtual ~Backend() = default;
39 static Impl backend; 40
40 return backend; 41 virtual void Write(const Entry& entry) = 0;
42
43 virtual void EnableForStacktrace() = 0;
44
45 virtual void Flush() = 0;
46};
47
48/**
49 * Backend that writes to stderr and with color
50 */
51class ColorConsoleBackend final : public Backend {
52public:
53 explicit ColorConsoleBackend() = default;
54
55 ~ColorConsoleBackend() override = default;
56
57 void Write(const Entry& entry) override {
58 if (enabled.load(std::memory_order_relaxed)) {
59 PrintColoredMessage(entry);
60 }
41 } 61 }
42 62
43 Impl(const Impl&) = delete; 63 void Flush() override {
44 Impl& operator=(const Impl&) = delete; 64 // stderr shouldn't be buffered
65 }
45 66
46 Impl(Impl&&) = delete; 67 void EnableForStacktrace() override {
47 Impl& operator=(Impl&&) = delete; 68 enabled = true;
69 }
48 70
49 void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num, 71 void SetEnabled(bool enabled_) {
50 const char* function, std::string message) { 72 enabled = enabled_;
51 message_queue.Push( 73 }
52 CreateEntry(log_class, log_level, filename, line_num, function, std::move(message))); 74
75private:
76 std::atomic_bool enabled{false};
77};
78
79/**
80 * Backend that writes to a file passed into the constructor
81 */
82class FileBackend final : public Backend {
83public:
84 explicit FileBackend(const std::filesystem::path& filename) {
85 auto old_filename = filename;
86 old_filename += ".old.txt";
87
88 // Existence checks are done within the functions themselves.
89 // We don't particularly care if these succeed or not.
90 static_cast<void>(FS::RemoveFile(old_filename));
91 static_cast<void>(FS::RenameFile(filename, old_filename));
92
93 file = std::make_unique<FS::IOFile>(filename, FS::FileAccessMode::Write,
94 FS::FileType::TextFile);
95 }
96
97 ~FileBackend() override = default;
98
99 void Write(const Entry& entry) override {
100 if (!enabled) {
101 return;
102 }
103
104 bytes_written += file->WriteString(FormatLogMessage(entry).append(1, '\n'));
105
106 using namespace Common::Literals;
107 // Prevent logs from exceeding a set maximum size in the event that log entries are spammed.
108 const auto write_limit = Settings::values.extended_logging ? 1_GiB : 100_MiB;
109 const bool write_limit_exceeded = bytes_written > write_limit;
110 if (entry.log_level >= Level::Error || write_limit_exceeded) {
111 if (write_limit_exceeded) {
112 // Stop writing after the write limit is exceeded.
113 // Don't close the file so we can print a stacktrace if necessary
114 enabled = false;
115 }
116 file->Flush();
117 }
118 }
119
120 void Flush() override {
121 file->Flush();
122 }
123
124 void EnableForStacktrace() override {
125 enabled = true;
126 bytes_written = 0;
53 } 127 }
54 128
55 void AddBackend(std::unique_ptr<Backend> backend) { 129private:
56 std::lock_guard lock{writing_mutex}; 130 std::unique_ptr<FS::IOFile> file;
57 backends.push_back(std::move(backend)); 131 bool enabled = true;
132 std::size_t bytes_written = 0;
133};
134
135/**
136 * Backend that writes to Visual Studio's output window
137 */
138class DebuggerBackend final : public Backend {
139public:
140 explicit DebuggerBackend() = default;
141
142 ~DebuggerBackend() override = default;
143
144 void Write(const Entry& entry) override {
145#ifdef _WIN32
146 ::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
147#endif
58 } 148 }
59 149
60 void RemoveBackend(std::string_view backend_name) { 150 void Flush() override {}
61 std::lock_guard lock{writing_mutex}; 151
152 void EnableForStacktrace() override {}
153};
154
155bool initialization_in_progress_suppress_logging = false;
62 156
63 std::erase_if(backends, [&backend_name](const auto& backend) { 157/**
64 return backend_name == backend->GetName(); 158 * Static state as a singleton.
65 }); 159 */
160class Impl {
161public:
162 static Impl& Instance() {
163 if (!instance) {
164 abort();
165 }
166 return *instance;
66 } 167 }
67 168
68 const Filter& GetGlobalFilter() const { 169 static void Initialize() {
69 return filter; 170 if (instance) {
171 abort();
172 }
173 using namespace Common::FS;
174 initialization_in_progress_suppress_logging = true;
175 const auto& log_dir = GetYuzuPath(YuzuPath::LogDir);
176 void(CreateDir(log_dir));
177 Filter filter;
178 filter.ParseFilterString(Settings::values.log_filter.GetValue());
179 instance = std::unique_ptr<Impl, decltype(&Deleter)>(new Impl(log_dir / LOG_FILE, filter),
180 Deleter);
181 initialization_in_progress_suppress_logging = false;
70 } 182 }
71 183
184 Impl(const Impl&) = delete;
185 Impl& operator=(const Impl&) = delete;
186
187 Impl(Impl&&) = delete;
188 Impl& operator=(Impl&&) = delete;
189
72 void SetGlobalFilter(const Filter& f) { 190 void SetGlobalFilter(const Filter& f) {
73 filter = f; 191 filter = f;
74 } 192 }
75 193
76 Backend* GetBackend(std::string_view backend_name) { 194 void SetColorConsoleBackendEnabled(bool enabled) {
77 const auto it = 195 color_console_backend.SetEnabled(enabled);
78 std::find_if(backends.begin(), backends.end(), 196 }
79 [&backend_name](const auto& i) { return backend_name == i->GetName(); }); 197
80 if (it == backends.end()) 198 void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
81 return nullptr; 199 const char* function, std::string message) {
82 return it->get(); 200 if (!filter.CheckMessage(log_class, log_level))
201 return;
202 const Entry& entry =
203 CreateEntry(log_class, log_level, filename, line_num, function, std::move(message));
204 message_queue.Push(entry);
83 } 205 }
84 206
85private: 207private:
86 Impl() { 208 Impl(const std::filesystem::path& file_backend_filename, const Filter& filter_)
87 backend_thread = std::thread([&] { 209 : filter{filter_}, file_backend{file_backend_filename}, backend_thread{std::thread([this] {
88 Entry entry; 210 Common::SetCurrentThreadName("yuzu:Log");
89 auto write_logs = [&](Entry& e) { 211 Entry entry;
90 std::lock_guard lock{writing_mutex}; 212 const auto write_logs = [this, &entry]() {
91 for (const auto& backend : backends) { 213 ForEachBackend([&entry](Backend& backend) { backend.Write(entry); });
92 backend->Write(e); 214 };
93 } 215 while (true) {
94 }; 216 entry = message_queue.PopWait();
95 while (true) { 217 if (entry.final_entry) {
96 entry = message_queue.PopWait(); 218 break;
97 if (entry.final_entry) { 219 }
98 break; 220 write_logs();
99 } 221 }
100 write_logs(entry); 222 // Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a
101 } 223 // case where a system is repeatedly spamming logs even on close.
224 int max_logs_to_write = filter.IsDebug() ? INT_MAX : 100;
225 while (max_logs_to_write-- && message_queue.Pop(entry)) {
226 write_logs();
227 }
228 })} {}
102 229
103 // Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a 230 ~Impl() {
104 // case where a system is repeatedly spamming logs even on close. 231 StopBackendThread();
105 const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100;
106 int logs_written = 0;
107 while (logs_written++ < MAX_LOGS_TO_WRITE && message_queue.Pop(entry)) {
108 write_logs(entry);
109 }
110 });
111 } 232 }
112 233
113 ~Impl() { 234 void StopBackendThread() {
114 Entry entry; 235 Entry stop_entry{};
115 entry.final_entry = true; 236 stop_entry.final_entry = true;
116 message_queue.Push(entry); 237 message_queue.Push(stop_entry);
117 backend_thread.join(); 238 backend_thread.join();
118 } 239 }
119 240
@@ -135,100 +256,51 @@ private:
135 }; 256 };
136 } 257 }
137 258
138 std::mutex writing_mutex; 259 void ForEachBackend(auto lambda) {
139 std::thread backend_thread; 260 lambda(static_cast<Backend&>(debugger_backend));
140 std::vector<std::unique_ptr<Backend>> backends; 261 lambda(static_cast<Backend&>(color_console_backend));
141 MPSCQueue<Entry> message_queue; 262 lambda(static_cast<Backend&>(file_backend));
142 Filter filter; 263 }
143 std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
144};
145
146ConsoleBackend::~ConsoleBackend() = default;
147
148void ConsoleBackend::Write(const Entry& entry) {
149 PrintMessage(entry);
150}
151
152ColorConsoleBackend::~ColorConsoleBackend() = default;
153
154void ColorConsoleBackend::Write(const Entry& entry) {
155 PrintColoredMessage(entry);
156}
157
158FileBackend::FileBackend(const std::filesystem::path& filename) {
159 auto old_filename = filename;
160 old_filename += ".old.txt";
161
162 // Existence checks are done within the functions themselves.
163 // We don't particularly care if these succeed or not.
164 FS::RemoveFile(old_filename);
165 void(FS::RenameFile(filename, old_filename));
166
167 file =
168 std::make_unique<FS::IOFile>(filename, FS::FileAccessMode::Write, FS::FileType::TextFile);
169}
170
171FileBackend::~FileBackend() = default;
172 264
173void FileBackend::Write(const Entry& entry) { 265 static void Deleter(Impl* ptr) {
174 if (!file->IsOpen()) { 266 delete ptr;
175 return;
176 } 267 }
177 268
178 using namespace Common::Literals; 269 static inline std::unique_ptr<Impl, decltype(&Deleter)> instance{nullptr, Deleter};
179 // Prevent logs from exceeding a set maximum size in the event that log entries are spammed.
180 constexpr std::size_t MAX_BYTES_WRITTEN = 100_MiB;
181 constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1_GiB;
182 270
183 const bool write_limit_exceeded = 271 Filter filter;
184 bytes_written > MAX_BYTES_WRITTEN_EXTENDED || 272 DebuggerBackend debugger_backend{};
185 (bytes_written > MAX_BYTES_WRITTEN && !Settings::values.extended_logging); 273 ColorConsoleBackend color_console_backend{};
274 FileBackend file_backend;
186 275
187 // Close the file after the write limit is exceeded. 276 std::thread backend_thread;
188 if (write_limit_exceeded) { 277 MPSCQueue<Entry> message_queue{};
189 file->Close(); 278 std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
190 return; 279};
191 } 280} // namespace
192 281
193 bytes_written += file->WriteString(FormatLogMessage(entry).append(1, '\n')); 282void Initialize() {
194 if (entry.log_level >= Level::Error) { 283 Impl::Initialize();
195 file->Flush();
196 }
197} 284}
198 285
199DebuggerBackend::~DebuggerBackend() = default; 286void DisableLoggingInTests() {
200 287 initialization_in_progress_suppress_logging = true;
201void DebuggerBackend::Write(const Entry& entry) {
202#ifdef _WIN32
203 ::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
204#endif
205} 288}
206 289
207void SetGlobalFilter(const Filter& filter) { 290void SetGlobalFilter(const Filter& filter) {
208 Impl::Instance().SetGlobalFilter(filter); 291 Impl::Instance().SetGlobalFilter(filter);
209} 292}
210 293
211void AddBackend(std::unique_ptr<Backend> backend) { 294void SetColorConsoleBackendEnabled(bool enabled) {
212 Impl::Instance().AddBackend(std::move(backend)); 295 Impl::Instance().SetColorConsoleBackendEnabled(enabled);
213}
214
215void RemoveBackend(std::string_view backend_name) {
216 Impl::Instance().RemoveBackend(backend_name);
217}
218
219Backend* GetBackend(std::string_view backend_name) {
220 return Impl::Instance().GetBackend(backend_name);
221} 296}
222 297
223void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, 298void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
224 unsigned int line_num, const char* function, const char* format, 299 unsigned int line_num, const char* function, const char* format,
225 const fmt::format_args& args) { 300 const fmt::format_args& args) {
226 auto& instance = Impl::Instance(); 301 if (!initialization_in_progress_suppress_logging) {
227 const auto& filter = instance.GetGlobalFilter(); 302 Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function,
228 if (!filter.CheckMessage(log_class, log_level)) 303 fmt::vformat(format, args));
229 return; 304 }
230
231 instance.PushEntry(log_class, log_level, filename, line_num, function,
232 fmt::vformat(format, args));
233} 305}
234} // namespace Common::Log 306} // namespace Common::Log
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index 4b9a910c1..cb7839ee9 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -5,120 +5,21 @@
5#pragma once 5#pragma once
6 6
7#include <filesystem> 7#include <filesystem>
8#include <memory>
9#include <string>
10#include <string_view>
11#include "common/logging/filter.h" 8#include "common/logging/filter.h"
12#include "common/logging/log.h"
13
14namespace Common::FS {
15class IOFile;
16}
17 9
18namespace Common::Log { 10namespace Common::Log {
19 11
20class Filter; 12class Filter;
21 13
22/** 14/// Initializes the logging system. This should be the first thing called in main.
23 * Interface for logging backends. As loggers can be created and removed at runtime, this can be 15void Initialize();
24 * used by a frontend for adding a custom logging backend as needed
25 */
26class Backend {
27public:
28 virtual ~Backend() = default;
29
30 virtual void SetFilter(const Filter& new_filter) {
31 filter = new_filter;
32 }
33 virtual const char* GetName() const = 0;
34 virtual void Write(const Entry& entry) = 0;
35
36private:
37 Filter filter;
38};
39
40/**
41 * Backend that writes to stderr without any color commands
42 */
43class ConsoleBackend : public Backend {
44public:
45 ~ConsoleBackend() override;
46
47 static const char* Name() {
48 return "console";
49 }
50 const char* GetName() const override {
51 return Name();
52 }
53 void Write(const Entry& entry) override;
54};
55
56/**
57 * Backend that writes to stderr and with color
58 */
59class ColorConsoleBackend : public Backend {
60public:
61 ~ColorConsoleBackend() override;
62
63 static const char* Name() {
64 return "color_console";
65 }
66
67 const char* GetName() const override {
68 return Name();
69 }
70 void Write(const Entry& entry) override;
71};
72 16
73/** 17void DisableLoggingInTests();
74 * Backend that writes to a file passed into the constructor
75 */
76class FileBackend : public Backend {
77public:
78 explicit FileBackend(const std::filesystem::path& filename);
79 ~FileBackend() override;
80
81 static const char* Name() {
82 return "file";
83 }
84
85 const char* GetName() const override {
86 return Name();
87 }
88
89 void Write(const Entry& entry) override;
90
91private:
92 std::unique_ptr<FS::IOFile> file;
93 std::size_t bytes_written = 0;
94};
95
96/**
97 * Backend that writes to Visual Studio's output window
98 */
99class DebuggerBackend : public Backend {
100public:
101 ~DebuggerBackend() override;
102
103 static const char* Name() {
104 return "debugger";
105 }
106 const char* GetName() const override {
107 return Name();
108 }
109 void Write(const Entry& entry) override;
110};
111
112void AddBackend(std::unique_ptr<Backend> backend);
113
114void RemoveBackend(std::string_view backend_name);
115
116Backend* GetBackend(std::string_view backend_name);
117 18
118/** 19/**
119 * The global filter will prevent any messages from even being processed if they are filtered. Each 20 * The global filter will prevent any messages from even being processed if they are filtered.
120 * backend can have a filter, but if the level is lower than the global filter, the backend will
121 * never get the message
122 */ 21 */
123void SetGlobalFilter(const Filter& filter); 22void SetGlobalFilter(const Filter& filter);
124} // namespace Common::Log \ No newline at end of file 23
24void SetColorConsoleBackendEnabled(bool enabled);
25} // namespace Common::Log
diff --git a/src/core/core.cpp b/src/core/core.cpp
index d3e84c4ef..0d3c4182a 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -84,8 +84,6 @@ FileSys::StorageId GetStorageIdForFrontendSlot(
84 84
85} // Anonymous namespace 85} // Anonymous namespace
86 86
87/*static*/ System System::s_instance;
88
89FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, 87FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
90 const std::string& path) { 88 const std::string& path) {
91 // To account for split 00+01+etc files. 89 // To account for split 00+01+etc files.
@@ -425,6 +423,13 @@ struct System::Impl {
425System::System() : impl{std::make_unique<Impl>(*this)} {} 423System::System() : impl{std::make_unique<Impl>(*this)} {}
426System::~System() = default; 424System::~System() = default;
427 425
426void System::InitializeGlobalInstance() {
427 if (s_instance) {
428 abort();
429 }
430 s_instance = std::unique_ptr<System>(new System);
431}
432
428CpuManager& System::GetCpuManager() { 433CpuManager& System::GetCpuManager() {
429 return impl->cpu_manager; 434 return impl->cpu_manager;
430} 435}
diff --git a/src/core/core.h b/src/core/core.h
index ea143043c..85836f2f8 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -121,9 +121,14 @@ public:
121 * @returns Reference to the instance of the System singleton class. 121 * @returns Reference to the instance of the System singleton class.
122 */ 122 */
123 [[deprecated("Use of the global system instance is deprecated")]] static System& GetInstance() { 123 [[deprecated("Use of the global system instance is deprecated")]] static System& GetInstance() {
124 return s_instance; 124 if (!s_instance) {
125 abort();
126 }
127 return *s_instance;
125 } 128 }
126 129
130 static void InitializeGlobalInstance();
131
127 /// Enumeration representing the return values of the System Initialize and Load process. 132 /// Enumeration representing the return values of the System Initialize and Load process.
128 enum class ResultStatus : u32 { 133 enum class ResultStatus : u32 {
129 Success, ///< Succeeded 134 Success, ///< Succeeded
@@ -396,7 +401,7 @@ private:
396 struct Impl; 401 struct Impl;
397 std::unique_ptr<Impl> impl; 402 std::unique_ptr<Impl> impl;
398 403
399 static System s_instance; 404 inline static std::unique_ptr<System> s_instance{};
400}; 405};
401 406
402} // namespace Core 407} // namespace Core
diff --git a/src/tests/common/param_package.cpp b/src/tests/common/param_package.cpp
index 4c0f9654f..e31ca3544 100644
--- a/src/tests/common/param_package.cpp
+++ b/src/tests/common/param_package.cpp
@@ -4,11 +4,13 @@
4 4
5#include <catch2/catch.hpp> 5#include <catch2/catch.hpp>
6#include <math.h> 6#include <math.h>
7#include "common/logging/backend.h"
7#include "common/param_package.h" 8#include "common/param_package.h"
8 9
9namespace Common { 10namespace Common {
10 11
11TEST_CASE("ParamPackage", "[common]") { 12TEST_CASE("ParamPackage", "[common]") {
13 Common::Log::DisableLoggingInTests();
12 ParamPackage original{ 14 ParamPackage original{
13 {"abc", "xyz"}, 15 {"abc", "xyz"},
14 {"def", "42"}, 16 {"def", "42"},
diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp
index 22ca1285d..f89ea8ea7 100644
--- a/src/yuzu/debugger/console.cpp
+++ b/src/yuzu/debugger/console.cpp
@@ -21,6 +21,7 @@ void ToggleConsole() {
21 console_shown = UISettings::values.show_console.GetValue(); 21 console_shown = UISettings::values.show_console.GetValue();
22 } 22 }
23 23
24 using namespace Common::Log;
24#if defined(_WIN32) && !defined(_DEBUG) 25#if defined(_WIN32) && !defined(_DEBUG)
25 FILE* temp; 26 FILE* temp;
26 if (UISettings::values.show_console) { 27 if (UISettings::values.show_console) {
@@ -29,24 +30,20 @@ void ToggleConsole() {
29 freopen_s(&temp, "CONIN$", "r", stdin); 30 freopen_s(&temp, "CONIN$", "r", stdin);
30 freopen_s(&temp, "CONOUT$", "w", stdout); 31 freopen_s(&temp, "CONOUT$", "w", stdout);
31 freopen_s(&temp, "CONOUT$", "w", stderr); 32 freopen_s(&temp, "CONOUT$", "w", stderr);
32 Common::Log::AddBackend(std::make_unique<Common::Log::ColorConsoleBackend>()); 33 SetColorConsoleBackendEnabled(true);
33 } 34 }
34 } else { 35 } else {
35 if (FreeConsole()) { 36 if (FreeConsole()) {
36 // In order to close the console, we have to also detach the streams on it. 37 // In order to close the console, we have to also detach the streams on it.
37 // Just redirect them to NUL if there is no console window 38 // Just redirect them to NUL if there is no console window
38 Common::Log::RemoveBackend(Common::Log::ColorConsoleBackend::Name()); 39 SetColorConsoleBackendEnabled(false);
39 freopen_s(&temp, "NUL", "r", stdin); 40 freopen_s(&temp, "NUL", "r", stdin);
40 freopen_s(&temp, "NUL", "w", stdout); 41 freopen_s(&temp, "NUL", "w", stdout);
41 freopen_s(&temp, "NUL", "w", stderr); 42 freopen_s(&temp, "NUL", "w", stderr);
42 } 43 }
43 } 44 }
44#else 45#else
45 if (UISettings::values.show_console) { 46 SetColorConsoleBackendEnabled(UISettings::values.show_console.GetValue());
46 Common::Log::AddBackend(std::make_unique<Common::Log::ColorConsoleBackend>());
47 } else {
48 Common::Log::RemoveBackend(Common::Log::ColorConsoleBackend::Name());
49 }
50#endif 47#endif
51} 48}
52} // namespace Debugger 49} // namespace Debugger
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 5940e0cfd..1bae1489f 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -175,21 +175,6 @@ void GMainWindow::ShowTelemetryCallout() {
175 175
176const int GMainWindow::max_recent_files_item; 176const int GMainWindow::max_recent_files_item;
177 177
178static void InitializeLogging() {
179 using namespace Common;
180
181 Log::Filter log_filter;
182 log_filter.ParseFilterString(Settings::values.log_filter.GetValue());
183 Log::SetGlobalFilter(log_filter);
184
185 const auto log_dir = FS::GetYuzuPath(FS::YuzuPath::LogDir);
186 void(FS::CreateDir(log_dir));
187 Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir / LOG_FILE));
188#ifdef _WIN32
189 Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
190#endif
191}
192
193static void RemoveCachedContents() { 178static void RemoveCachedContents() {
194 const auto cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir); 179 const auto cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir);
195 const auto offline_fonts = cache_dir / "fonts"; 180 const auto offline_fonts = cache_dir / "fonts";
@@ -207,8 +192,6 @@ GMainWindow::GMainWindow()
207 : input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, 192 : input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
208 config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, 193 config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
209 provider{std::make_unique<FileSys::ManualContentProvider>()} { 194 provider{std::make_unique<FileSys::ManualContentProvider>()} {
210 InitializeLogging();
211
212 LoadTranslation(); 195 LoadTranslation();
213 196
214 setAcceptDrops(true); 197 setAcceptDrops(true);
@@ -3398,6 +3381,7 @@ void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
3398#endif 3381#endif
3399 3382
3400int main(int argc, char* argv[]) { 3383int main(int argc, char* argv[]) {
3384 Common::Log::Initialize();
3401 Common::DetachedTasks detached_tasks; 3385 Common::DetachedTasks detached_tasks;
3402 MicroProfileOnThreadCreate("Frontend"); 3386 MicroProfileOnThreadCreate("Frontend");
3403 SCOPE_EXIT({ MicroProfileShutdown(); }); 3387 SCOPE_EXIT({ MicroProfileShutdown(); });
@@ -3437,6 +3421,7 @@ int main(int argc, char* argv[]) {
3437 // generating shaders 3421 // generating shaders
3438 setlocale(LC_ALL, "C"); 3422 setlocale(LC_ALL, "C");
3439 3423
3424 Core::System::InitializeGlobalInstance();
3440 GMainWindow main_window; 3425 GMainWindow main_window;
3441 // After settings have been loaded by GMainWindow, apply the filter 3426 // After settings have been loaded by GMainWindow, apply the filter
3442 main_window.show(); 3427 main_window.show();
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index c10093820..ba2c993ba 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -74,31 +74,14 @@ static void PrintVersion() {
74 std::cout << "yuzu " << Common::g_scm_branch << " " << Common::g_scm_desc << std::endl; 74 std::cout << "yuzu " << Common::g_scm_branch << " " << Common::g_scm_desc << std::endl;
75} 75}
76 76
77static void InitializeLogging() {
78 using namespace Common;
79
80 Log::Filter log_filter(Log::Level::Debug);
81 log_filter.ParseFilterString(static_cast<std::string>(Settings::values.log_filter));
82 Log::SetGlobalFilter(log_filter);
83
84 Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
85
86 const auto& log_dir = FS::GetYuzuPath(FS::YuzuPath::LogDir);
87 void(FS::CreateDir(log_dir));
88 Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir / LOG_FILE));
89#ifdef _WIN32
90 Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
91#endif
92}
93
94/// Application entry point 77/// Application entry point
95int main(int argc, char** argv) { 78int main(int argc, char** argv) {
79 Common::Log::Initialize();
80 Common::Log::SetColorConsoleBackendEnabled(true);
96 Common::DetachedTasks detached_tasks; 81 Common::DetachedTasks detached_tasks;
97 Config config; 82 Config config;
98 83
99 int option_index = 0; 84 int option_index = 0;
100
101 InitializeLogging();
102#ifdef _WIN32 85#ifdef _WIN32
103 int argc_w; 86 int argc_w;
104 auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w); 87 auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
@@ -163,6 +146,7 @@ int main(int argc, char** argv) {
163 return -1; 146 return -1;
164 } 147 }
165 148
149 Core::System::InitializeGlobalInstance();
166 auto& system{Core::System::GetInstance()}; 150 auto& system{Core::System::GetInstance()};
167 InputCommon::InputSubsystem input_subsystem; 151 InputCommon::InputSubsystem input_subsystem;
168 152