// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: GPL-3.0+ #pragma once #include "Pcsx2Defs.h" #include "fmt/core.h" #include #include // TODO: This whole thing needs to get ripped out. enum ConsoleColors { Color_Default = 0, Color_Black, Color_Green, Color_Red, Color_Blue, Color_Magenta, Color_Orange, Color_Gray, Color_Cyan, // faint visibility, intended for logging PS2/IOP output Color_Yellow, // faint visibility, intended for logging PS2/IOP output Color_White, // faint visibility, intended for logging PS2/IOP output // Strong text *may* result in mis-aligned text in the console, depending on the // font and the platform, so use these with caution. Color_StrongBlack, Color_StrongRed, // intended for errors Color_StrongGreen, // intended for infrequent state information Color_StrongBlue, // intended for block headings Color_StrongMagenta, Color_StrongOrange, // intended for warnings Color_StrongGray, Color_StrongCyan, Color_StrongYellow, Color_StrongWhite, ConsoleColors_Count }; enum LOGLEVEL { LOGLEVEL_NONE, // Silences all log traffic LOGLEVEL_ERROR, LOGLEVEL_WARNING, LOGLEVEL_INFO, LOGLEVEL_DEV, LOGLEVEL_DEBUG, LOGLEVEL_TRACE, LOGLEVEL_COUNT, }; // TODO: Move this elsewhere, add channels. namespace Log { // log message callback type using HostCallbackType = void (*)(LOGLEVEL level, ConsoleColors color, std::string_view message); // returns the time in seconds since the start of the process float GetCurrentMessageTime(); // adds a standard console output bool IsConsoleOutputEnabled(); void SetConsoleOutputLevel(LOGLEVEL level); // adds a debug console output bool IsDebugOutputAvailable(); bool IsDebugOutputEnabled(); void SetDebugOutputLevel(LOGLEVEL level); // adds a file output bool IsFileOutputEnabled(); bool SetFileOutputLevel(LOGLEVEL level, std::string path); // returns the log file, this is really dangerous to use if it changes... std::FILE* GetFileLogHandle(); // adds host output bool IsHostOutputEnabled(); void SetHostOutputLevel(LOGLEVEL level, HostCallbackType callback); // sets logging timestamps bool AreTimestampsEnabled(); void SetTimestampsEnabled(bool enabled); // Returns the current global filtering level. LOGLEVEL GetMaxLevel(); // writes a message to the log void Write(LOGLEVEL level, ConsoleColors color, std::string_view message); void Writef(LOGLEVEL level, ConsoleColors color, const char* format, ...); void Writev(LOGLEVEL level, ConsoleColors color, const char* format, va_list ap); void WriteFmtArgs(LOGLEVEL level, ConsoleColors color, fmt::string_view fmt, fmt::format_args args); template __fi static void Write(LOGLEVEL level, ConsoleColors color, fmt::format_string fmt, T&&... args) { // Avoid arg packing if filtered. if (level <= GetMaxLevel()) return WriteFmtArgs(level, color, fmt, fmt::make_format_args(args...)); } } // namespace Log // Adapter classes to handle old code. template struct ConsoleLogWriter { __fi static void Error(std::string_view str) { Log::Write(level, Color_StrongRed, str); } __fi static void Warning(std::string_view str) { Log::Write(level, Color_StrongOrange, str); } __fi static void WriteLn(std::string_view str) { Log::Write(level, Color_Default, str); } __fi static void WriteLn(ConsoleColors color, std::string_view str) { Log::Write(level, color, str); } __fi static void WriteLn() { Log::Write(level, Color_Default, std::string_view()); } __fi static void FormatV(const char* format, va_list ap) { Log::Writev(level, Color_Default, format, ap); } __fi static void FormatV(ConsoleColors color, const char* format, va_list ap) { Log::Writev(level, color, format, ap); } #define MAKE_PRINTF_CONSOLE_WRITER(color) \ do \ { \ std::va_list ap; \ va_start(ap, format); \ Log::Writev(level, color, format, ap); \ va_end(ap); \ } while (0) // clang-format off static void Error(const char* format, ...) { MAKE_PRINTF_CONSOLE_WRITER(Color_StrongRed); } static void Warning(const char* format, ...) { MAKE_PRINTF_CONSOLE_WRITER(Color_StrongOrange); } static void WriteLn(const char* format, ...) { MAKE_PRINTF_CONSOLE_WRITER(Color_Default); } static void WriteLn(ConsoleColors color, const char* format, ...) { MAKE_PRINTF_CONSOLE_WRITER(color); } // clang-format on #undef MAKE_PRINTF_CONSOLE_WRITER #define MAKE_FMT_CONSOLE_WRITER(color) do \ { \ if (level <= Log::GetMaxLevel()) \ Log::WriteFmtArgs(level, color, fmt, fmt::make_format_args(args...)); \ } \ while (0) // clang-format off template __fi static void ErrorFmt(fmt::format_string fmt, T&&... args) { MAKE_FMT_CONSOLE_WRITER(Color_StrongRed); } template __fi static void WarningFmt(fmt::format_string fmt, T&&... args) { MAKE_FMT_CONSOLE_WRITER(Color_StrongOrange); } template __fi static void WriteLnFmt(fmt::format_string fmt, T&&... args) { MAKE_FMT_CONSOLE_WRITER(Color_Default); } template __fi static void WriteLnFmt(ConsoleColors color, fmt::format_string fmt, T&&... args) { MAKE_FMT_CONSOLE_WRITER(color); } // clang-format on #undef MAKE_FMT_CONSOLE_WRITER }; struct NullLogWriter { // clang-format off __fi static bool Error(std::string_view str) { return false; } __fi static bool Warning(std::string_view str) { return false; } __fi static bool WriteLn(std::string_view str) { return false; } __fi static bool WriteLn(ConsoleColors color, std::string_view str) { return false; } __fi static bool WriteLn() { return false; } __fi static bool Error(const char* format, ...) { return false; } __fi static bool Warning(const char* format, ...) { return false; } __fi static bool WriteLn(const char* format, ...) { return false; } __fi static bool WriteLn(ConsoleColors color, const char* format, ...) { return false; } template __fi static bool ErrorFmt(fmt::format_string fmt, T&&... args) { return false; } template __fi static bool WarningFmt(fmt::format_string fmt, T&&... args) { return false; } template __fi static bool WriteLnFmt(fmt::format_string fmt, T&&... args) { return false; } template __fi static bool WriteLnFmt(ConsoleColors color, fmt::format_string fmt, T&&... args) { return false; } // clang-format on }; extern ConsoleLogWriter Console; extern ConsoleLogWriter DevCon; #define ERROR_LOG(...) Log::Write(LOGLEVEL_ERROR, Color_StrongRed, __VA_ARGS__) #define WARNING_LOG(...) Log::Write(LOGLEVEL_WARNING, Color_StrongOrange, __VA_ARGS__) #define INFO_LOG(...) Log::Write(LOGLEVEL_INFO, Color_White, __VA_ARGS__) #define DEV_LOG(...) Log::Write(LOGLEVEL_DEV, Color_StrongGray, __VA_ARGS__) #ifdef _DEBUG extern ConsoleLogWriter DbgConWriter; #define DbgCon DbgConWriter #define DEBUG_LOG(...) Log::Write(LOGLEVEL_TRACE, Color_Gray, __VA_ARGS__) #define TRACE_LOG(...) Log::Write(LOGLEVEL_TRACE, Color_Blue, __VA_ARGS__) #else extern NullLogWriter DbgConWriter; #define DbgCon 0 && DbgConWriter #define DEBUG_LOG(...) (void)0 #define TRACE_LOG(...) (void)0 #endif