Rework the log manager to be more robust

This commit is contained in:
Henrik Rydgård
2024-12-16 10:49:02 +01:00
parent 4a861dfdbe
commit 96cab3f267
17 changed files with 341 additions and 403 deletions
+1
View File
@@ -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"
+5 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+40 -22
View File
@@ -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;
}
}
+10 -9
View File
@@ -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);
+11 -4
View File
@@ -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
View File
@@ -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
View File
@@ -306,7 +306,7 @@ public:
static int EstimatePerVertexCost();
void Flush();
void Flush() override;
#ifdef USE_CRT_DBG
#undef new
+3 -6
View File
@@ -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
View File
@@ -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))
+1 -1
View File
@@ -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
+3
View File
@@ -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.
-42
View File
@@ -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);
-4
View File
@@ -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
View File
@@ -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
View File
@@ -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();