mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Rework the log manager to be more robust
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Log/LogManager.h"
|
||||
#include "Common/Log/ConsoleListener.h"
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
#include "Common/Log/LogManager.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Common/CommonWindows.h"
|
||||
|
||||
class ConsoleListener : public LogListener {
|
||||
struct LogMessage;
|
||||
|
||||
class ConsoleListener {
|
||||
public:
|
||||
ConsoleListener();
|
||||
~ConsoleListener();
|
||||
@@ -43,7 +45,7 @@ public:
|
||||
void BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst);
|
||||
void PixelSpace(int Left, int Top, int Width, int Height, bool);
|
||||
COORD GetCoordinates(int BytesRead, int BufferWidth);
|
||||
void Log(const LogMessage &message) override;
|
||||
void Log(const LogMessage &message);
|
||||
void ClearScreen(bool Cursor = true);
|
||||
|
||||
void Show(bool bShow);
|
||||
|
||||
+153
-127
@@ -38,6 +38,7 @@
|
||||
#include "Common/TimeUtil.h"
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/Data/Format/IniFile.h"
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
LogManager g_logManager;
|
||||
@@ -54,6 +55,10 @@ static const char level_to_char[8] = "-NEWIDV";
|
||||
#define LOG_MSC_OUTPUTDEBUG false
|
||||
#endif
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
void AndroidLog(const LogMessage &message);
|
||||
#endif
|
||||
|
||||
void GenericLog(LogLevel level, Log type, const char *file, int line, const char* fmt, ...) {
|
||||
if (g_bLogEnabledSetting && !(*g_bLogEnabledSetting))
|
||||
return;
|
||||
@@ -106,6 +111,10 @@ static const char * const g_logTypeNames[] = {
|
||||
"SCEMISC",
|
||||
};
|
||||
|
||||
const char *LogManager::GetLogTypeName(Log type) {
|
||||
return g_logTypeNames[(size_t)type];
|
||||
}
|
||||
|
||||
void LogManager::Init(bool *enabledSetting, bool headless) {
|
||||
g_bLogEnabledSetting = enabledSetting;
|
||||
if (initialized_) {
|
||||
@@ -115,9 +124,9 @@ void LogManager::Init(bool *enabledSetting, bool headless) {
|
||||
initialized_ = true;
|
||||
|
||||
_dbg_assert_(ARRAY_SIZE(g_logTypeNames) == (size_t)Log::NUMBER_OF_LOGS);
|
||||
_dbg_assert_(ARRAY_SIZE(g_logTypeNames) == ARRAY_SIZE(log_));
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(g_logTypeNames); i++) {
|
||||
truncate_cpy(log_[i].m_shortName, g_logTypeNames[i]);
|
||||
for (size_t i = 0; i < ARRAY_SIZE(log_); i++) {
|
||||
log_[i].enabled = true;
|
||||
#if defined(_DEBUG)
|
||||
log_[i].level = LogLevel::LDEBUG;
|
||||
@@ -126,75 +135,42 @@ void LogManager::Init(bool *enabledSetting, bool headless) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Remove file logging on small devices in Release mode.
|
||||
#if PPSSPP_PLATFORM(UWP)
|
||||
if (IsDebuggerPresent())
|
||||
debuggerLog_ = new OutputDebugStringLogListener();
|
||||
#else
|
||||
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
||||
fileLog_ = new FileLogListener("");
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
#if !PPSSPP_PLATFORM(UWP)
|
||||
consoleLog_ = new ConsoleListener();
|
||||
#endif
|
||||
if (IsDebuggerPresent())
|
||||
debuggerLog_ = new OutputDebugStringLogListener();
|
||||
#else
|
||||
stdioLog_ = new StdioListener();
|
||||
#endif
|
||||
#endif
|
||||
ringLog_ = new RingbufferLogListener();
|
||||
#endif
|
||||
|
||||
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
||||
AddListener(fileLog_);
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
#if !PPSSPP_PLATFORM(UWP)
|
||||
AddListener(consoleLog_);
|
||||
#endif
|
||||
#else
|
||||
AddListener(stdioLog_);
|
||||
#endif
|
||||
#if defined(_MSC_VER) && (defined(USING_WIN_UI) || PPSSPP_PLATFORM(UWP))
|
||||
if (IsDebuggerPresent() && debuggerLog_ && (LOG_MSC_OUTPUTDEBUG || headless))
|
||||
AddListener(debuggerLog_);
|
||||
#endif
|
||||
AddListener(ringLog_);
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
if (!consoleLog_) {
|
||||
consoleLog_ = new ConsoleListener();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LogManager::Shutdown() {
|
||||
if (!initialized_) {
|
||||
// already done
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; ++i) {
|
||||
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
||||
RemoveListener(fileLog_);
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
RemoveListener(consoleLog_);
|
||||
#endif
|
||||
RemoveListener(stdioLog_);
|
||||
#if defined(_MSC_VER) && defined(USING_WIN_UI)
|
||||
RemoveListener(debuggerLog_);
|
||||
#endif
|
||||
#endif
|
||||
if (fp_) {
|
||||
fclose(fp_);
|
||||
fp_ = nullptr;
|
||||
}
|
||||
|
||||
// Make sure we don't shutdown while logging. RemoveListener locks too, but there are gaps.
|
||||
std::lock_guard<std::mutex> listeners_lock(listeners_lock_);
|
||||
outputs_ = (LogOutput)0;
|
||||
|
||||
delete fileLog_;
|
||||
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
delete consoleLog_;
|
||||
consoleLog_ = nullptr;
|
||||
#endif
|
||||
delete stdioLog_;
|
||||
delete debuggerLog_;
|
||||
#endif
|
||||
delete ringLog_;
|
||||
|
||||
ringLog_.Clear();
|
||||
initialized_ = false;
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(log_); i++) {
|
||||
log_[i].enabled = true;
|
||||
#if defined(_DEBUG)
|
||||
log_[i].level = LogLevel::LDEBUG;
|
||||
#else
|
||||
log_[i].level = LogLevel::LINFO;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
LogManager::LogManager() {}
|
||||
@@ -203,23 +179,30 @@ LogManager::~LogManager() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void LogManager::ChangeFileLog(const char *filename) {
|
||||
if (fileLog_) {
|
||||
RemoveListener(fileLog_);
|
||||
delete fileLog_;
|
||||
fileLog_ = nullptr;
|
||||
void LogManager::ChangeFileLog(const Path &filename) {
|
||||
if (fp_ && filename == logFilename_) {
|
||||
// All good
|
||||
return;
|
||||
}
|
||||
|
||||
if (filename) {
|
||||
fileLog_ = new FileLogListener(filename);
|
||||
AddListener(fileLog_);
|
||||
if (fp_) {
|
||||
fclose(fp_);
|
||||
}
|
||||
|
||||
if (!filename.empty()) {
|
||||
logFilename_ = Path(filename);
|
||||
fp_ = File::OpenCFile(logFilename_, "at");
|
||||
logFileOpenFailed_ = fp_ == nullptr;
|
||||
if (logFileOpenFailed_) {
|
||||
printf("Failed to open log file %s", filename.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::SaveConfig(Section *section) {
|
||||
for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; i++) {
|
||||
section->Set((std::string(log_[i].m_shortName) + "Enabled"), log_[i].enabled);
|
||||
section->Set((std::string(log_[i].m_shortName) + "Level"), (int)log_[i].level);
|
||||
section->Set((std::string(g_logTypeNames[i]) + "Enabled"), log_[i].enabled);
|
||||
section->Set((std::string(g_logTypeNames[i]) + "Level"), (int)log_[i].level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,13 +210,20 @@ void LogManager::LoadConfig(const Section *section, bool debugDefaults) {
|
||||
for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; i++) {
|
||||
bool enabled = false;
|
||||
int level = 0;
|
||||
section->Get((std::string(log_[i].m_shortName) + "Enabled"), &enabled, true);
|
||||
section->Get((std::string(log_[i].m_shortName) + "Level"), &level, (int)(debugDefaults ? LogLevel::LDEBUG : LogLevel::LERROR));
|
||||
section->Get((std::string(g_logTypeNames[i]) + "Enabled"), &enabled, true);
|
||||
section->Get((std::string(g_logTypeNames[i]) + "Level"), &level, (int)(debugDefaults ? LogLevel::LDEBUG : LogLevel::LERROR));
|
||||
log_[i].enabled = enabled;
|
||||
log_[i].level = (LogLevel)level;
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::SetOutputsEnabled(LogOutput outputs) {
|
||||
outputs_ = outputs;
|
||||
if (outputs & LogOutput::File) {
|
||||
ChangeFileLog(logFilename_);
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::LogLine(LogLevel level, Log type, const char *file, int line, const char *format, va_list args) {
|
||||
char msgBuf[1024];
|
||||
if (!initialized_) {
|
||||
@@ -252,12 +242,12 @@ void LogManager::LogLine(LogLevel level, Log type, const char *file, int line, c
|
||||
}
|
||||
|
||||
const LogChannel &log = log_[(size_t)type];
|
||||
if (level > log.level || !log.enabled)
|
||||
if (level > log.level || !log.enabled || outputs_ == (LogOutput)0)
|
||||
return;
|
||||
|
||||
LogMessage message;
|
||||
message.level = level;
|
||||
message.log = log.m_shortName;
|
||||
message.log = g_logTypeNames[(size_t)type];
|
||||
|
||||
#ifdef _WIN32
|
||||
static const char sep = '\\';
|
||||
@@ -290,12 +280,12 @@ void LogManager::LogLine(LogLevel level, Log type, const char *file, int line, c
|
||||
if (threadName) {
|
||||
snprintf(message.header, sizeof(message.header), "%-12.12s %c[%s]: %s:%d",
|
||||
threadName, level_to_char[(int)level],
|
||||
log.m_shortName,
|
||||
message.log,
|
||||
file, line);
|
||||
} else {
|
||||
snprintf(message.header, sizeof(message.header), "%s:%d %c[%s]:",
|
||||
file, line, level_to_char[(int)level],
|
||||
log.m_shortName);
|
||||
message.log);
|
||||
}
|
||||
|
||||
GetCurrentTimeFormatted(message.timestamp);
|
||||
@@ -314,70 +304,61 @@ void LogManager::LogLine(LogLevel level, Log type, const char *file, int line, c
|
||||
message.msg[neededBytes] = '\n';
|
||||
va_end(args_copy);
|
||||
|
||||
std::lock_guard<std::mutex> listeners_lock(listeners_lock_);
|
||||
for (auto &iter : listeners_) {
|
||||
iter->Log(message);
|
||||
if (outputs_ & LogOutput::Stdio) {
|
||||
// This has its own mutex.
|
||||
stdioLog_.Log(message);
|
||||
}
|
||||
}
|
||||
|
||||
bool LogManager::IsEnabled(LogLevel level, Log type) {
|
||||
LogChannel &log = log_[(size_t)type];
|
||||
if (level > log.level || !log.enabled)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogManager::AddListener(LogListener *listener) {
|
||||
_dbg_assert_(initialized_);
|
||||
if (!listener)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lk(listeners_lock_);
|
||||
listeners_.push_back(listener);
|
||||
}
|
||||
|
||||
void LogManager::RemoveListener(LogListener *listener) {
|
||||
_dbg_assert_(initialized_);
|
||||
if (!listener)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lk(listeners_lock_);
|
||||
auto iter = std::find(listeners_.begin(), listeners_.end(), listener);
|
||||
if (iter != listeners_.end())
|
||||
listeners_.erase(iter);
|
||||
}
|
||||
|
||||
FileLogListener::FileLogListener(const char *filename) {
|
||||
if (strlen(filename) > 0) {
|
||||
fp_ = File::OpenCFile(Path(std::string(filename)), "at");
|
||||
// OK, now go through the possible listeners in order.
|
||||
if (outputs_ & LogOutput::File) {
|
||||
if (fp_) {
|
||||
std::lock_guard<std::mutex> lk(logFileLock_);
|
||||
fprintf(fp_, "%s %s %s", message.timestamp, message.header, message.msg.c_str());
|
||||
// Is this really necessary to do every time? I guess to catch the last message before a crash..
|
||||
fflush(fp_);
|
||||
}
|
||||
}
|
||||
SetEnabled(fp_ != nullptr);
|
||||
}
|
||||
|
||||
FileLogListener::~FileLogListener() {
|
||||
if (fp_)
|
||||
fclose(fp_);
|
||||
}
|
||||
|
||||
void FileLogListener::Log(const LogMessage &message) {
|
||||
if (!IsEnabled() || !IsValid())
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lk(m_log_lock);
|
||||
fprintf(fp_, "%s %s %s", message.timestamp, message.header, message.msg.c_str());
|
||||
fflush(fp_);
|
||||
}
|
||||
|
||||
void OutputDebugStringLogListener::Log(const LogMessage &message) {
|
||||
char buffer[4096];
|
||||
// We omit the timestamp for easy copy-paste-diffing.
|
||||
snprintf(buffer, sizeof(buffer), "%s %s", message.header, message.msg.c_str());
|
||||
if (outputs_ & LogOutput::DebugString) {
|
||||
// No mutex needed
|
||||
#if _MSC_VER
|
||||
OutputDebugStringUTF8(buffer);
|
||||
char buffer[4096];
|
||||
// We omit the timestamp for easy copy-paste-diffing.
|
||||
snprintf(buffer, sizeof(buffer), "%s %s", message.header, message.msg.c_str());
|
||||
OutputDebugStringUTF8(buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (outputs_ & LogOutput::RingBuffer) {
|
||||
ringLog_.Log(message);
|
||||
}
|
||||
|
||||
if (outputs_ & LogOutput::Printf) {
|
||||
PrintfLog(message);
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
if (outputs_ & LogOutput::WinConsole) {
|
||||
if (consoleLog_) {
|
||||
consoleLog_->Log(message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
if (outputs_ & LogOutput::Android) {
|
||||
AndroidLog(message);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (outputs_ & LogOutput::ExternalCallback) {
|
||||
if (externalCallback_) {
|
||||
externalCallback_(message, externalUserData_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RingbufferLogListener::Log(const LogMessage &message) {
|
||||
if (!enabled_)
|
||||
return;
|
||||
void RingbufferLog::Log(const LogMessage &message) {
|
||||
messages_[curMessage_] = message;
|
||||
curMessage_++;
|
||||
if (curMessage_ >= MAX_LOGS)
|
||||
@@ -406,3 +387,48 @@ void OutputDebugStringUTF8(const char *p) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
|
||||
#ifndef LOG_APP_NAME
|
||||
#define LOG_APP_NAME "PPSSPP"
|
||||
#endif
|
||||
|
||||
void AndroidLog(const LogMessage &message) {
|
||||
int mode;
|
||||
switch (message.level) {
|
||||
case LogLevel::LWARNING:
|
||||
mode = ANDROID_LOG_WARN;
|
||||
break;
|
||||
case LogLevel::LERROR:
|
||||
mode = ANDROID_LOG_ERROR;
|
||||
break;
|
||||
default:
|
||||
mode = ANDROID_LOG_INFO;
|
||||
break;
|
||||
}
|
||||
|
||||
// Long log messages need splitting up.
|
||||
// Not sure what the actual limit is (seems to vary), but let's be conservative.
|
||||
const size_t maxLogLength = 512;
|
||||
if (message.msg.length() < maxLogLength) {
|
||||
// Log with simplified headers as Android already provides timestamp etc.
|
||||
__android_log_print(mode, LOG_APP_NAME, "[%s] %s", message.log, message.msg.c_str());
|
||||
} else {
|
||||
std::string msg = message.msg;
|
||||
|
||||
// Ideally we should split at line breaks, but it's at least fairly usable anyway.
|
||||
std::string first_part = msg.substr(0, maxLogLength);
|
||||
__android_log_print(mode, LOG_APP_NAME, "[%s] %s", message.log, first_part.c_str());
|
||||
msg = msg.substr(maxLogLength);
|
||||
|
||||
while (msg.length() > maxLogLength) {
|
||||
std::string first_part = msg.substr(0, maxLogLength);
|
||||
__android_log_print(mode, LOG_APP_NAME, "%s", first_part.c_str());
|
||||
msg = msg.substr(maxLogLength);
|
||||
}
|
||||
// Print the final part.
|
||||
__android_log_print(mode, LOG_APP_NAME, "%s", msg.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+86
-75
@@ -21,12 +21,13 @@
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
|
||||
#include "Common/Data/Format/IniFile.h"
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonFuncs.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Common/File/Path.h"
|
||||
#include "Common/Log/StdioListener.h"
|
||||
|
||||
#define MAX_MESSAGES 8000
|
||||
|
||||
@@ -42,99 +43,82 @@ struct LogMessage {
|
||||
std::string msg; // The actual log message.
|
||||
};
|
||||
|
||||
// pure virtual interface
|
||||
class LogListener {
|
||||
public:
|
||||
virtual ~LogListener() = default;
|
||||
|
||||
virtual void Log(const LogMessage &msg) = 0;
|
||||
enum class LogOutput {
|
||||
Stdio = (1 << 0),
|
||||
DebugString = (1 << 1),
|
||||
RingBuffer = (1 << 2),
|
||||
File = (1 << 3),
|
||||
WinConsole = (1 << 4),
|
||||
Android = (1 << 5),
|
||||
Printf = (1 << 6),
|
||||
ExternalCallback = (1 << 7),
|
||||
};
|
||||
ENUM_CLASS_BITOPS(LogOutput);
|
||||
|
||||
class FileLogListener : public LogListener {
|
||||
class RingbufferLog {
|
||||
public:
|
||||
FileLogListener(const char *filename);
|
||||
~FileLogListener();
|
||||
|
||||
void Log(const LogMessage &msg) override;
|
||||
|
||||
bool IsValid() { if (!fp_) return false; else return true; }
|
||||
bool IsEnabled() const { return m_enable; }
|
||||
void SetEnabled(bool enable) { m_enable = enable; }
|
||||
|
||||
const char *GetName() const { return "file"; }
|
||||
|
||||
private:
|
||||
std::mutex m_log_lock;
|
||||
FILE *fp_ = nullptr;
|
||||
bool m_enable;
|
||||
};
|
||||
|
||||
class OutputDebugStringLogListener : public LogListener {
|
||||
public:
|
||||
void Log(const LogMessage &msg) override;
|
||||
};
|
||||
|
||||
class RingbufferLogListener : public LogListener {
|
||||
public:
|
||||
void Log(const LogMessage &msg) override;
|
||||
|
||||
bool IsEnabled() const { return enabled_; }
|
||||
void SetEnabled(bool enable) { enabled_ = enable; }
|
||||
void Log(const LogMessage &msg);
|
||||
|
||||
int GetCount() const { return count_ < MAX_LOGS ? count_ : MAX_LOGS; }
|
||||
const char *TextAt(int i) const { return messages_[(curMessage_ - i - 1) & (MAX_LOGS - 1)].msg.c_str(); }
|
||||
LogLevel LevelAt(int i) const { return messages_[(curMessage_ - i - 1) & (MAX_LOGS - 1)].level; }
|
||||
|
||||
void Clear() {
|
||||
curMessage_ = 0;
|
||||
count_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
enum { MAX_LOGS = 128 };
|
||||
LogMessage messages_[MAX_LOGS];
|
||||
int curMessage_ = 0;
|
||||
int count_ = 0;
|
||||
bool enabled_ = false;
|
||||
};
|
||||
|
||||
struct LogChannel {
|
||||
char m_shortName[32]{};
|
||||
LogLevel level;
|
||||
bool enabled;
|
||||
#if defined(_DEBUG)
|
||||
LogLevel level = LogLevel::LDEBUG;
|
||||
#else
|
||||
LogLevel level = LogLevel::LDEBUG;
|
||||
#endif
|
||||
bool enabled = true;
|
||||
};
|
||||
|
||||
class Section;
|
||||
class ConsoleListener;
|
||||
class StdioListener;
|
||||
|
||||
typedef void (*LogCallback)(const LogMessage &message, void *userdata);
|
||||
|
||||
class LogManager {
|
||||
private:
|
||||
// Prevent copies.
|
||||
LogManager(const LogManager &) = delete;
|
||||
void operator=(const LogManager &) = delete;
|
||||
|
||||
bool initialized_ = false;
|
||||
|
||||
LogChannel log_[(size_t)Log::NUMBER_OF_LOGS];
|
||||
FileLogListener *fileLog_ = nullptr;
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
ConsoleListener *consoleLog_ = nullptr;
|
||||
#endif
|
||||
StdioListener *stdioLog_ = nullptr;
|
||||
OutputDebugStringLogListener *debuggerLog_ = nullptr;
|
||||
RingbufferLogListener *ringLog_ = nullptr;
|
||||
|
||||
std::mutex listeners_lock_;
|
||||
std::vector<LogListener*> listeners_;
|
||||
|
||||
public:
|
||||
LogManager();
|
||||
~LogManager();
|
||||
|
||||
void AddListener(LogListener *listener);
|
||||
void RemoveListener(LogListener *listener);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
bool IsEnabled(LogLevel level, Log type);
|
||||
|
||||
bool IsEnabled(LogLevel level, Log type) const {
|
||||
const LogChannel &log = log_[(size_t)type];
|
||||
if (level > log.level || !log.enabled)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
LogChannel *GetLogChannel(Log type) {
|
||||
return &log_[(size_t)type];
|
||||
@@ -164,25 +148,52 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
StdioListener *GetStdioListener() const {
|
||||
return stdioLog_;
|
||||
}
|
||||
|
||||
OutputDebugStringLogListener *GetDebuggerListener() const {
|
||||
return debuggerLog_;
|
||||
}
|
||||
|
||||
RingbufferLogListener *GetRingbufferListener() const {
|
||||
return ringLog_;
|
||||
const RingbufferLog *GetRingbuffer() const {
|
||||
return &ringLog_;
|
||||
}
|
||||
|
||||
void Init(bool *enabledSetting, bool headless = false);
|
||||
void Shutdown();
|
||||
|
||||
void ChangeFileLog(const char *filename);
|
||||
void SetExternalLogCallback(LogCallback callback, void *userdata) {
|
||||
externalCallback_ = callback;
|
||||
externalUserData_ = userdata;
|
||||
}
|
||||
|
||||
void ChangeFileLog(const Path &filename);
|
||||
|
||||
void SaveConfig(Section *section);
|
||||
void LoadConfig(const Section *section, bool debugDefaults);
|
||||
|
||||
static const char *GetLogTypeName(Log type);
|
||||
|
||||
private:
|
||||
// Prevent copies.
|
||||
LogManager(const LogManager &) = delete;
|
||||
void operator=(const LogManager &) = delete;
|
||||
|
||||
bool initialized_ = false;
|
||||
|
||||
LogChannel log_[(size_t)Log::NUMBER_OF_LOGS];
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
ConsoleListener *consoleLog_ = nullptr;
|
||||
#endif
|
||||
StdioLog stdioLog_;
|
||||
|
||||
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;
|
||||
|
||||
@@ -15,24 +15,18 @@
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <atomic>
|
||||
#include <algorithm> // min
|
||||
#include <cstring>
|
||||
#include <string> // System: To be able to add strings with "+"
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Log/LogManager.h"
|
||||
#include "Common/Log/StdioListener.h"
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
StdioListener::StdioListener() {
|
||||
StdioLog::StdioLog() {
|
||||
#if PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(SWITCH)
|
||||
bUseColor = false;
|
||||
#elif defined(_MSC_VER)
|
||||
@@ -46,36 +40,60 @@ StdioListener::StdioListener() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void StdioListener::Log(const LogMessage &msg) {
|
||||
char Text[2048];
|
||||
snprintf(Text, sizeof(Text), "%s %s %s", msg.timestamp, msg.header, msg.msg.c_str());
|
||||
Text[sizeof(Text) - 2] = '\n';
|
||||
Text[sizeof(Text) - 1] = '\0';
|
||||
void StdioLog::Log(const LogMessage &msg) {
|
||||
char text[2048];
|
||||
snprintf(text, sizeof(text), "%s %s %s", msg.timestamp, msg.header, msg.msg.c_str());
|
||||
text[sizeof(text) - 2] = '\n';
|
||||
text[sizeof(text) - 1] = '\0';
|
||||
|
||||
char ColorAttr[16] = "";
|
||||
char ResetAttr[16] = "";
|
||||
const char *colorAttr = "";
|
||||
const char *resetAttr = "";
|
||||
|
||||
if (bUseColor) {
|
||||
strcpy(ResetAttr, "\033[0m");
|
||||
resetAttr = "\033[0m";
|
||||
switch (msg.level) {
|
||||
case LogLevel::LNOTICE: // light green
|
||||
strcpy(ColorAttr, "\033[92m");
|
||||
colorAttr = "\033[92m";
|
||||
break;
|
||||
case LogLevel::LERROR: // light red
|
||||
strcpy(ColorAttr, "\033[91m");
|
||||
colorAttr = "\033[91m";
|
||||
break;
|
||||
case LogLevel::LWARNING: // light yellow
|
||||
strcpy(ColorAttr, "\033[93m");
|
||||
colorAttr = "\033[93m";
|
||||
break;
|
||||
case LogLevel::LINFO: // cyan
|
||||
strcpy(ColorAttr, "\033[96m");
|
||||
colorAttr = "\033[96m";
|
||||
break;
|
||||
case LogLevel::LDEBUG: // gray
|
||||
strcpy(ColorAttr, "\033[90m");
|
||||
colorAttr = "\033[90m";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr);
|
||||
fprintf(stderr, "%s%s%s", colorAttr, text, resetAttr);
|
||||
}
|
||||
|
||||
void PrintfLog(const LogMessage &message) {
|
||||
switch (message.level) {
|
||||
case LogLevel::LVERBOSE:
|
||||
fprintf(stderr, "V %s", message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LDEBUG:
|
||||
fprintf(stderr, "D %s", message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LINFO:
|
||||
fprintf(stderr, "I %s", message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LERROR:
|
||||
fprintf(stderr, "E %s", message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LWARNING:
|
||||
fprintf(stderr, "W %s", message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LNOTICE:
|
||||
default:
|
||||
fprintf(stderr, "N %s", message.msg.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,18 +19,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#include "Common/Log/LogManager.h"
|
||||
struct LogMessage;
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Common/CommonWindows.h"
|
||||
#endif
|
||||
|
||||
class StdioListener : public LogListener {
|
||||
// Nice, colored output.
|
||||
class StdioLog {
|
||||
public:
|
||||
StdioListener();
|
||||
void Log(const LogMessage &message) override;
|
||||
StdioLog();
|
||||
void Log(const LogMessage &message);
|
||||
private:
|
||||
std::mutex lock_;
|
||||
bool bUseColor = true;
|
||||
};
|
||||
|
||||
// Ultra plain output, for CI and stuff.
|
||||
void PrintfLog(const LogMessage &message);
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#include "Core/Debugger/WebSocket/LogBroadcaster.h"
|
||||
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
|
||||
|
||||
class DebuggerLogListener : public LogListener {
|
||||
class DebuggerLogListener {
|
||||
public:
|
||||
void Log(const LogMessage &msg) override {
|
||||
void Log(const LogMessage &msg) {
|
||||
std::lock_guard<std::mutex> guard(lock_);
|
||||
messages_[nextMessage_] = msg;
|
||||
nextMessage_++;
|
||||
@@ -73,13 +73,20 @@ private:
|
||||
int read_ = 0;
|
||||
};
|
||||
|
||||
static void BroadcastCallback(const LogMessage &message, void *userdata) {
|
||||
DebuggerLogListener *listener = (DebuggerLogListener *)userdata;
|
||||
listener->Log(message);
|
||||
}
|
||||
|
||||
LogBroadcaster::LogBroadcaster() {
|
||||
listener_ = new DebuggerLogListener();
|
||||
g_logManager.AddListener(listener_);
|
||||
g_logManager.SetExternalLogCallback(&BroadcastCallback, (void *)listener_);
|
||||
g_logManager.EnableOutput(LogOutput::ExternalCallback);
|
||||
}
|
||||
|
||||
LogBroadcaster::~LogBroadcaster() {
|
||||
g_logManager.RemoveListener(listener_);
|
||||
g_logManager.DisableOutput(LogOutput::ExternalCallback);
|
||||
g_logManager.SetExternalLogCallback(nullptr, nullptr);
|
||||
delete listener_;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -763,7 +763,7 @@ DLResult GPUCommon::ProcessDLQueue() {
|
||||
return DLResult::Error;
|
||||
}
|
||||
|
||||
DEBUG_LOG(Log::G3D, "%s DL execution at %08x - stall = %08x (startingTicks=%d)",
|
||||
DEBUG_LOG(Log::G3D, "%s DL execution at %08x - stall = %08x (startingTicks=%lld)",
|
||||
list.pc == list.startpc ? "Starting" : "Resuming", list.pc, list.stall, startingTicks);
|
||||
|
||||
if (list.state == PSP_GE_DL_STATE_PAUSED) {
|
||||
|
||||
+1
-1
@@ -306,7 +306,7 @@ public:
|
||||
|
||||
static int EstimatePerVertexCost();
|
||||
|
||||
void Flush();
|
||||
void Flush() override;
|
||||
|
||||
#ifdef USE_CRT_DBG
|
||||
#undef new
|
||||
|
||||
+3
-6
@@ -175,10 +175,7 @@ void DevMenuScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
||||
scroll->Add(items);
|
||||
parent->Add(scroll);
|
||||
|
||||
RingbufferLogListener *ring = g_logManager.GetRingbufferListener();
|
||||
if (ring) {
|
||||
ring->SetEnabled(true);
|
||||
}
|
||||
g_logManager.EnableOutput(LogOutput::RingBuffer);
|
||||
}
|
||||
|
||||
UI::EventReturn DevMenuScreen::OnResetLimitedLogging(UI::EventParams &e) {
|
||||
@@ -236,7 +233,7 @@ void GPIGPOScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
||||
|
||||
void LogScreen::UpdateLog() {
|
||||
using namespace UI;
|
||||
RingbufferLogListener *ring = g_logManager.GetRingbufferListener();
|
||||
const RingbufferLog *ring = g_logManager.GetRingbuffer();
|
||||
if (!ring)
|
||||
return;
|
||||
vert_->Clear();
|
||||
@@ -331,7 +328,7 @@ void LogConfigScreen::CreateViews() {
|
||||
LinearLayout *row = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(cellSize - 50, WRAP_CONTENT));
|
||||
row->SetSpacing(0);
|
||||
row->Add(new CheckBox(&chan->enabled, "", "", new LinearLayoutParams(50, WRAP_CONTENT)));
|
||||
row->Add(new PopupMultiChoice((int *)&chan->level, chan->m_shortName, logLevelList, 1, 6, I18NCat::NONE, screenManager(), new LinearLayoutParams(1.0)));
|
||||
row->Add(new PopupMultiChoice((int *)&chan->level, LogManager::GetLogTypeName(type), logLevelList, 1, 6, I18NCat::NONE, screenManager(), new LinearLayoutParams(1.0)));
|
||||
grid->Add(row);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-35
@@ -193,32 +193,7 @@ WindowsAudioBackend *winAudioBackend;
|
||||
|
||||
std::thread *graphicsLoadThread;
|
||||
|
||||
class PrintfLogger : public LogListener {
|
||||
public:
|
||||
void Log(const LogMessage &message) override {
|
||||
// Log with simplified headers as Android already provides timestamp etc.
|
||||
switch (message.level) {
|
||||
case LogLevel::LVERBOSE:
|
||||
case LogLevel::LDEBUG:
|
||||
case LogLevel::LINFO:
|
||||
printf("INFO [%s] %s", message.log, message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LERROR:
|
||||
printf("ERR [%s] %s", message.log, message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LWARNING:
|
||||
printf("WARN [%s] %s", message.log, message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LNOTICE:
|
||||
default:
|
||||
printf("NOTE [%s] !!! %s", message.log, message.msg.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// globals
|
||||
static LogListener *logger = nullptr;
|
||||
Path boot_filename;
|
||||
|
||||
int NativeMix(short *audio, int numSamples, int sampleRateHz) {
|
||||
@@ -670,7 +645,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
}
|
||||
|
||||
if (fileToLog)
|
||||
g_logManager.ChangeFileLog(fileToLog);
|
||||
g_logManager.ChangeFileLog(Path(fileToLog));
|
||||
|
||||
if (forceLogLevel)
|
||||
g_logManager.SetAllLogLevels(logLevel);
|
||||
@@ -678,13 +653,11 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
PostLoadConfig();
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
logger = new AndroidLogger();
|
||||
g_logManager.AddListener(logger);
|
||||
g_logManager.EnableOutput(LogOutput::Android);
|
||||
#elif (defined(MOBILE_DEVICE) && !defined(_DEBUG))
|
||||
// Enable basic logging for any kind of mobile device, since LogManager doesn't.
|
||||
// The MOBILE_DEVICE/_DEBUG condition matches LogManager.cpp.
|
||||
logger = new PrintfLogger();
|
||||
g_logManager.AddListener(logger);
|
||||
g_logManager.EnableOutput(LogOutput::Printf);
|
||||
#endif
|
||||
|
||||
if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) {
|
||||
@@ -1489,11 +1462,6 @@ void NativeShutdown() {
|
||||
if (!restarting)
|
||||
g_logManager.Shutdown();
|
||||
|
||||
if (logger) {
|
||||
delete logger;
|
||||
logger = nullptr;
|
||||
}
|
||||
|
||||
g_threadManager.Teardown();
|
||||
|
||||
#if !(PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS))
|
||||
|
||||
@@ -75,7 +75,7 @@ PPSSPP_UWPMain::PPSSPP_UWPMain(App ^app, const std::shared_ptr<DX::DeviceResourc
|
||||
g_logManager.SetAllLogLevels(LogLevel::LDEBUG);
|
||||
|
||||
if (g_Config.bEnableLogging) {
|
||||
g_logManager.ChangeFileLog(GetLogFile().c_str());
|
||||
g_logManager.ChangeFileLog(Path(GetLogFile()));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -955,6 +955,9 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
||||
// This will be overridden by the actual config. But we do want to log during startup.
|
||||
g_Config.bEnableLogging = true;
|
||||
g_logManager.Init(&g_Config.bEnableLogging);
|
||||
if (IsDebuggerPresent()) {
|
||||
g_logManager.EnableOutput(LogOutput::WinConsole);
|
||||
}
|
||||
|
||||
// On Win32 it makes more sense to initialize the system directories here
|
||||
// because the next place it was called was in the EmuThread, and it's too late by then.
|
||||
|
||||
@@ -186,10 +186,6 @@ static std::map<SystemPermission, PermissionStatus> permissions;
|
||||
|
||||
static AndroidGraphicsContext *graphicsContext;
|
||||
|
||||
#ifndef LOG_APP_NAME
|
||||
#define LOG_APP_NAME "PPSSPP"
|
||||
#endif
|
||||
|
||||
#define MessageBox(a, b, c, d) __android_log_print(ANDROID_LOG_INFO, APP_NAME, "%s %s", (b), (c));
|
||||
|
||||
#if PPSSPP_ARCH(ARMV7)
|
||||
@@ -203,44 +199,6 @@ int utimensat(int fd, const char *path, const struct timespec times[2]) {
|
||||
|
||||
static void ProcessFrameCommands(JNIEnv *env);
|
||||
|
||||
void AndroidLogger::Log(const LogMessage &message) {
|
||||
int mode;
|
||||
switch (message.level) {
|
||||
case LogLevel::LWARNING:
|
||||
mode = ANDROID_LOG_WARN;
|
||||
break;
|
||||
case LogLevel::LERROR:
|
||||
mode = ANDROID_LOG_ERROR;
|
||||
break;
|
||||
default:
|
||||
mode = ANDROID_LOG_INFO;
|
||||
break;
|
||||
}
|
||||
|
||||
// Long log messages need splitting up.
|
||||
// Not sure what the actual limit is (seems to vary), but let's be conservative.
|
||||
const size_t maxLogLength = 512;
|
||||
if (message.msg.length() < maxLogLength) {
|
||||
// Log with simplified headers as Android already provides timestamp etc.
|
||||
__android_log_print(mode, LOG_APP_NAME, "[%s] %s", message.log, message.msg.c_str());
|
||||
} else {
|
||||
std::string msg = message.msg;
|
||||
|
||||
// Ideally we should split at line breaks, but it's at least fairly usable anyway.
|
||||
std::string first_part = msg.substr(0, maxLogLength);
|
||||
__android_log_print(mode, LOG_APP_NAME, "[%s] %s", message.log, first_part.c_str());
|
||||
msg = msg.substr(maxLogLength);
|
||||
|
||||
while (msg.length() > maxLogLength) {
|
||||
std::string first_part = msg.substr(0, maxLogLength);
|
||||
__android_log_print(mode, LOG_APP_NAME, "%s", first_part.c_str());
|
||||
msg = msg.substr(maxLogLength);
|
||||
}
|
||||
// Print the final part.
|
||||
__android_log_print(mode, LOG_APP_NAME, "%s", msg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv* getEnv() {
|
||||
JNIEnv *env;
|
||||
int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
|
||||
|
||||
@@ -21,10 +21,6 @@ std::string Android_GetInputDeviceDebugString();
|
||||
jclass findClass(const char* name);
|
||||
JNIEnv* getEnv();
|
||||
|
||||
class AndroidLogger : public LogListener {
|
||||
public:
|
||||
void Log(const LogMessage &message) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+1
-30
@@ -66,33 +66,6 @@ bool System_AudioRecordingIsAvailable() { return false; }
|
||||
bool System_AudioRecordingState() { return false; }
|
||||
#endif
|
||||
|
||||
class PrintfLogger : public LogListener {
|
||||
public:
|
||||
void Log(const LogMessage &message) override {
|
||||
switch (message.level) {
|
||||
case LogLevel::LVERBOSE:
|
||||
fprintf(stderr, "V %s", message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LDEBUG:
|
||||
fprintf(stderr, "D %s", message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LINFO:
|
||||
fprintf(stderr, "I %s", message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LERROR:
|
||||
fprintf(stderr, "E %s", message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LWARNING:
|
||||
fprintf(stderr, "W %s", message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LNOTICE:
|
||||
default:
|
||||
fprintf(stderr, "N %s", message.msg.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Temporary hacks around annoying linking errors.
|
||||
void NativeFrame(GraphicsContext *graphicsContext) { }
|
||||
void NativeResized() { }
|
||||
@@ -436,7 +409,6 @@ int main(int argc, const char* argv[])
|
||||
|
||||
g_Config.bEnableLogging = (fullLog || outputDebugStringLog);
|
||||
g_logManager.Init(&g_Config.bEnableLogging, outputDebugStringLog);
|
||||
PrintfLogger *printfLogger = new PrintfLogger();
|
||||
|
||||
for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; i++) {
|
||||
Log type = (Log)i;
|
||||
@@ -445,7 +417,7 @@ int main(int argc, const char* argv[])
|
||||
}
|
||||
if (fullLog) {
|
||||
// Only with --log, add the printfLogger.
|
||||
g_logManager.AddListener(printfLogger);
|
||||
g_logManager.EnableOutput(LogOutput::Printf);
|
||||
}
|
||||
|
||||
// Needs to be after log so we don't interfere with test output.
|
||||
@@ -629,7 +601,6 @@ int main(int argc, const char* argv[])
|
||||
|
||||
g_VFS.Clear();
|
||||
g_logManager.Shutdown();
|
||||
delete printfLogger;
|
||||
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
timeEndPeriod(1);
|
||||
|
||||
+22
-43
@@ -16,7 +16,6 @@
|
||||
#include "Common/TimeUtil.h"
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/Serialize/Serializer.h"
|
||||
#include "Common/Log/StdioListener.h"
|
||||
#include "Common/Input/InputState.h"
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
#include "Common/Thread/ThreadManager.h"
|
||||
@@ -292,41 +291,27 @@ namespace Libretro
|
||||
|
||||
using namespace Libretro;
|
||||
|
||||
class PrintfLogger : public LogListener
|
||||
{
|
||||
public:
|
||||
PrintfLogger(retro_log_callback log) : log_(log.log) {}
|
||||
void Log(const LogMessage &message)
|
||||
{
|
||||
switch (message.level)
|
||||
{
|
||||
case LogLevel::LVERBOSE:
|
||||
case LogLevel::LDEBUG:
|
||||
log_(RETRO_LOG_DEBUG, "[%s] %s",
|
||||
message.log, message.msg.c_str());
|
||||
break;
|
||||
void RetroLogCallback(const LogMessage &message, void *userdata) {
|
||||
retro_log_printf_t *fn = (retro_log_printf_t *)userdata;
|
||||
switch (message.level) {
|
||||
case LogLevel::LVERBOSE:
|
||||
case LogLevel::LDEBUG:
|
||||
(*fn)(RETRO_LOG_DEBUG, "[%s] %s", message.log, message.msg.c_str());
|
||||
break;
|
||||
|
||||
case LogLevel::LERROR:
|
||||
log_(RETRO_LOG_ERROR, "[%s] %s",
|
||||
message.log, message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LNOTICE:
|
||||
case LogLevel::LWARNING:
|
||||
log_(RETRO_LOG_WARN, "[%s] %s",
|
||||
message.log, message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LINFO:
|
||||
default:
|
||||
log_(RETRO_LOG_INFO, "[%s] %s",
|
||||
message.log, message.msg.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
retro_log_printf_t log_;
|
||||
};
|
||||
static PrintfLogger *printfLogger;
|
||||
case LogLevel::LERROR:
|
||||
(*fn)(RETRO_LOG_ERROR, "[%s] %s", message.log, message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LNOTICE:
|
||||
case LogLevel::LWARNING:
|
||||
(*fn)(RETRO_LOG_WARN, "[%s] %s", message.log, message.msg.c_str());
|
||||
break;
|
||||
case LogLevel::LINFO:
|
||||
default:
|
||||
(*fn)(RETRO_LOG_INFO, "[%s] %s", message.log, message.msg.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool set_variable_visibility(void)
|
||||
{
|
||||
@@ -1211,11 +1196,8 @@ void retro_init(void)
|
||||
{
|
||||
log_cb = log.log;
|
||||
g_logManager.Init(&g_Config.bEnableLogging);
|
||||
printfLogger = new PrintfLogger(log);
|
||||
g_logManager.RemoveListener(g_logManager.GetStdioListener());
|
||||
g_logManager.RemoveListener(g_logManager.GetDebuggerListener());
|
||||
g_logManager.ChangeFileLog(nullptr);
|
||||
g_logManager.AddListener(printfLogger);
|
||||
g_logManager.SetOutputsEnabled(LogOutput::ExternalCallback);
|
||||
g_logManager.SetExternalLogCallback(&RetroLogCallback, (void *)log_cb);
|
||||
}
|
||||
|
||||
VsyncSwapIntervalReset();
|
||||
@@ -1287,9 +1269,6 @@ void retro_deinit(void)
|
||||
g_logManager.Shutdown();
|
||||
log_cb = NULL;
|
||||
|
||||
delete printfLogger;
|
||||
printfLogger = nullptr;
|
||||
|
||||
libretro_supports_bitmasks = false;
|
||||
|
||||
VsyncSwapIntervalReset();
|
||||
|
||||
Reference in New Issue
Block a user