// Copyright (C) 2003 Dolphin Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 2.0 or later versions. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ #pragma once #include "ppsspp_config.h" #include #include #include #include "Common/Common.h" #include "Common/CommonFuncs.h" #include "Common/Log.h" #include "Common/File/Path.h" #define MAX_MESSAGES 8000 extern const char *hleCurrentThreadName; // Struct that listeners can output how they want. For example, on Android we don't want to add // timestamp or write the level as a string, those already exist. struct LogMessage { char timestamp[16]; char header[64]; // Filename/thread/etc. in front. LogLevel level; const char *log; std::string msg; // The actual log message. }; enum class LogOutput { Stdio = (1 << 0), // Also android log. DebugString = (1 << 1), RingBuffer = (1 << 2), File = (1 << 3), WinConsole = (1 << 4), Printf = (1 << 5), ExternalCallback = (1 << 6), }; ENUM_CLASS_BITOPS(LogOutput); class RingbufferLog { public: void Log(const LogMessage &msg); int GetCount() const { return count_ < MAX_LOGS ? count_ : MAX_LOGS; } std::string_view TextAt(int i) const { return messages_[(curMessage_ - i - 1) & (MAX_LOGS - 1)].msg; } LogLevel LevelAt(int i) const { return messages_[(curMessage_ - i - 1) & (MAX_LOGS - 1)].level; } void Clear() { curMessage_ = 0; count_ = 0; } private: enum { MAX_LOGS = 256 }; LogMessage messages_[MAX_LOGS]; int curMessage_ = 0; int count_ = 0; }; class Section; class ConsoleListener; typedef void (*LogCallback)(const LogMessage &message, void *userdata); extern bool *g_bLogEnabledSetting; class LogManager { public: LogManager(); ~LogManager(); void SetOutputsEnabled(LogOutput outputs); LogOutput GetOutputsEnabled() const { return outputs_; } void EnableOutput(LogOutput output) { SetOutputsEnabled(outputs_ | output); } void DisableOutput(LogOutput output) { LogOutput temp = outputs_; temp &= ~output; SetOutputsEnabled(temp); } void EnableOutput(LogOutput output, bool enabled) { if (enabled) { EnableOutput(output); } else { DisableOutput(output); } } static u32 GetMaxLevel() { return (u32)MAX_LOGLEVEL; } static int GetNumChannels() { return (int)Log::NUMBER_OF_LOGS; } void LogLine(LogLevel level, Log type, const char *file, int line, const char *fmt, va_list args); LogChannel *GetLogChannel(Log type) { return &g_log[(size_t)type]; } void SetLogLevel(Log type, LogLevel level) { g_log[(size_t)type].level = level; } void SetAllLogLevels(LogLevel level) { for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; ++i) { g_log[i].level = level; } } void SetEnabled(Log type, bool enable) { g_log[(size_t)type].enabled = enable; } LogLevel GetLogLevel(Log type) { return g_log[(size_t)type].level; } #if PPSSPP_PLATFORM(WINDOWS) ConsoleListener *GetConsoleListener() const { return consoleLog_; } #endif const RingbufferLog &GetRingbuffer() const { return ringLog_; } void Init(bool *enabledSetting, bool headless = false); void Shutdown(); void SetExternalLogCallback(LogCallback callback, void *userdata) { externalCallback_ = callback; externalUserData_ = userdata; } void SetFileLogPath(const Path &filename); const Path &GetLogFilePath() const { return logFilename_; } void SaveConfig(Section *section); void LoadConfig(const Section *section); static const char *GetLogTypeName(Log type); static u32 GetLevelColor(LogLevel level) { switch (level) { case LogLevel::LDEBUG: return 0xE0E0E0; case LogLevel::LWARNING: return 0x50FFFF; case LogLevel::LERROR: return 0x5050FF; case LogLevel::LNOTICE: return 0x30FF30; case LogLevel::LINFO: return 0xFFFF60; case LogLevel::LVERBOSE: default: return 0xC0C0C0; } } private: // Prevent copies. LogManager(const LogManager &) = delete; void operator=(const LogManager &) = delete; bool initialized_ = false; #if PPSSPP_PLATFORM(WINDOWS) ConsoleListener *consoleLog_ = nullptr; #endif // Stdio logging void StdioLog(const LogMessage &message); std::mutex stdioLock_; bool stdioUseColor_ = true; LogOutput outputs_ = (LogOutput)0; // File logging std::mutex logFileLock_; FILE *fp_ = nullptr; bool logFileOpenFailed_ = false; Path logFilename_; // Ring buffer RingbufferLog ringLog_; // Callback LogCallback externalCallback_ = nullptr; void *externalUserData_ = nullptr; }; extern LogManager g_logManager;