diff --git a/CMakeLists.txt b/CMakeLists.txt
index f6719dff7f..fb6cba591a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -647,6 +647,8 @@ add_library(Common STATIC
Common/Log.cpp
Common/LogManager.cpp
Common/LogManager.h
+ Common/LogReporting.cpp
+ Common/LogReporting.h
Common/MakeUnique.h
Common/MemArenaAndroid.cpp
Common/MemArenaDarwin.cpp
diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index 476039ff0f..08f36d1574 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -469,6 +469,7 @@
+
@@ -891,6 +892,7 @@
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index cd5146e2cf..bf90f1efc2 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -394,6 +394,7 @@
File
+
@@ -760,6 +761,7 @@
File
+
diff --git a/Common/LogReporting.cpp b/Common/LogReporting.cpp
new file mode 100644
index 0000000000..2189b1c7e2
--- /dev/null
+++ b/Common/LogReporting.cpp
@@ -0,0 +1,92 @@
+// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include
+#include
+#include
+#include
+#include "Common/LogReporting.h"
+
+namespace Reporting {
+
+// Keeps track of report-only-once identifiers. Since they're always constants, a pointer is okay.
+static std::unordered_map logNTimes;
+static std::mutex logNTimesLock;
+
+AllowedCallback allowedCallback = nullptr;
+MessageCallback messageCallback = nullptr;
+
+bool ShouldLogNTimes(const char *identifier, int count) {
+ // True if it wasn't there already -> so yes, log.
+ std::lock_guard lock(logNTimesLock);
+ auto iter = logNTimes.find(identifier);
+ if (iter == logNTimes.end()) {
+ logNTimes.insert(std::pair(identifier, 1));
+ return true;
+ } else {
+ if (iter->second >= count) {
+ return false;
+ } else {
+ iter->second++;
+ return true;
+ }
+ }
+}
+
+void ResetCounts() {
+ std::lock_guard lock(logNTimesLock);
+ logNTimes.clear();
+}
+
+void SetupCallbacks(AllowedCallback allowed, MessageCallback message) {
+ allowedCallback = allowed;
+ messageCallback = message;
+}
+
+void ReportMessage(const char *message, ...) {
+ if (!allowedCallback || !messageCallback) {
+ ERROR_LOG(SYSTEM, "Reporting not initialized, skipping: %s", message);
+ return;
+ }
+
+ if (!allowedCallback())
+ return;
+
+ const int MESSAGE_BUFFER_SIZE = 65536;
+ char temp[MESSAGE_BUFFER_SIZE];
+
+ va_list args;
+ va_start(args, message);
+ vsnprintf(temp, MESSAGE_BUFFER_SIZE - 1, message, args);
+ temp[MESSAGE_BUFFER_SIZE - 1] = '\0';
+ va_end(args);
+
+ messageCallback(message, temp);
+}
+
+void ReportMessageFormatted(const char *message, const char *formatted) {
+ if (!allowedCallback || !messageCallback) {
+ ERROR_LOG(SYSTEM, "Reporting not initialized, skipping: %s", message);
+ return;
+ }
+
+ if (!allowedCallback())
+ return;
+ messageCallback(message, formatted);
+}
+
+}
diff --git a/Common/LogReporting.h b/Common/LogReporting.h
new file mode 100644
index 0000000000..f4b0ea7903
--- /dev/null
+++ b/Common/LogReporting.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2012- PPSSPP 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 git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+
+#include "Common/CommonTypes.h"
+#include "Common/Log.h"
+
+#define DEBUG_LOG_REPORT(t,...) do { DEBUG_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false)
+#define ERROR_LOG_REPORT(t,...) do { ERROR_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false)
+#define WARN_LOG_REPORT(t,...) do { WARN_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false)
+#define NOTICE_LOG_REPORT(t,...) do { NOTICE_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false)
+#define INFO_LOG_REPORT(t,...) do { INFO_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false)
+
+#define DEBUG_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { DEBUG_LOG_REPORT(t, __VA_ARGS__); } } while (false)
+#define ERROR_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { ERROR_LOG_REPORT(t, __VA_ARGS__); } } while (false)
+#define WARN_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { WARN_LOG_REPORT(t, __VA_ARGS__); } } while (false)
+#define NOTICE_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { NOTICE_LOG_REPORT(t, __VA_ARGS__); } } while (false)
+#define INFO_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { INFO_LOG_REPORT(t, __VA_ARGS__); } } while (false)
+
+#define ERROR_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { ERROR_LOG(t, __VA_ARGS__); } } while (false)
+#define WARN_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { WARN_LOG(t, __VA_ARGS__); } } while (false)
+#define NOTICE_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { NOTICE_LOG(t, __VA_ARGS__); } } while (false)
+#define INFO_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { INFO_LOG(t, __VA_ARGS__); } } while (false)
+
+#define ERROR_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { ERROR_LOG(t, __VA_ARGS__); } } while (false)
+#define WARN_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { WARN_LOG(t, __VA_ARGS__); } } while (false)
+#define NOTICE_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { NOTICE_LOG(t, __VA_ARGS__); } } while (false)
+#define INFO_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { INFO_LOG(t, __VA_ARGS__); } } while (false)
+
+namespace Reporting {
+
+typedef bool(*AllowedCallback)();
+typedef void(*MessageCallback)(const char *message, const char *formatted);
+
+// Resets counts on any count-limited logs (see ShouldLogNTimes).
+void ResetCounts();
+
+// Returns true if that identifier has not been logged yet.
+bool ShouldLogNTimes(const char *identifier, int n);
+
+// Set callbacks for implementation of message reporting.
+void SetupCallbacks(AllowedCallback allowed, MessageCallback message);
+
+// Report a message string, using the format string as a key.
+void ReportMessage(const char *message, ...);
+
+// The same, but with a preformatted version (message is still the key.)
+void ReportMessageFormatted(const char *message, const char *formatted);
+
+}
diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp
index 72edac0ed6..4e69f353ee 100644
--- a/Core/Reporting.cpp
+++ b/Core/Reporting.cpp
@@ -60,9 +60,6 @@ namespace Reporting
static u32 spamProtectionCount = 0;
// Temporarily stores a reference to the hostname.
static std::string lastHostname;
- // Keeps track of report-only-once identifiers. Since they're always constants, a pointer is okay.
- static std::map logNTimes;
- static std::mutex logNTimesLock;
// Keeps track of whether a harmful setting was ever used.
static bool everUnsupported = false;
@@ -331,14 +328,18 @@ namespace Reporting
#endif
}
+ bool MessageAllowed();
+ void SendReportMessage(const char *message, const char *formatted);
+
void Init()
{
// New game, clean slate.
spamProtectionCount = 0;
- logNTimes.clear();
+ ResetCounts();
everUnsupported = false;
currentSupported = IsSupported();
pendingMessagesDone = false;
+ Reporting::SetupCallbacks(&MessageAllowed, &SendReportMessage);
}
void Shutdown()
@@ -377,29 +378,6 @@ namespace Reporting
everUnsupported = true;
}
- bool ShouldLogNTimes(const char *identifier, int count)
- {
- // True if it wasn't there already -> so yes, log.
- std::lock_guard lock(logNTimesLock);
- auto iter = logNTimes.find(identifier);
- if (iter == logNTimes.end()) {
- logNTimes.insert(std::pair(identifier, 1));
- return true;
- } else {
- if (iter->second >= count) {
- return false;
- } else {
- iter->second++;
- return true;
- }
- }
- }
-
- void ResetCounts() {
- std::lock_guard lock(logNTimesLock);
- logNTimes.clear();
- }
-
std::string CurrentGameID()
{
// TODO: Maybe ParamSFOData shouldn't include nulls in std::strings? Don't work to break savedata, though...
@@ -639,41 +617,13 @@ namespace Reporting
return 0;
}
- void ReportMessage(const char *message, ...)
- {
+ bool MessageAllowed() {
if (!IsEnabled() || CheckSpamLimited())
- return;
- int pos = NextFreePos();
- if (pos == -1)
- return;
-
- const int MESSAGE_BUFFER_SIZE = 65536;
- char temp[MESSAGE_BUFFER_SIZE];
-
- va_list args;
- va_start(args, message);
- vsnprintf(temp, MESSAGE_BUFFER_SIZE - 1, message, args);
- temp[MESSAGE_BUFFER_SIZE - 1] = '\0';
- va_end(args);
-
- Payload &payload = payloadBuffer[pos];
- payload.type = RequestType::MESSAGE;
- payload.string1 = message;
- payload.string2 = temp;
-
- std::lock_guard guard(pendingMessageLock);
- pendingMessages.push_back(pos);
- pendingMessageCond.notify_one();
-
- if (!messageThread.joinable()) {
- messageThread = std::thread(ProcessPending);
- }
+ return false;
+ return true;
}
- void ReportMessageFormatted(const char *message, const char *formatted)
- {
- if (!IsEnabled() || CheckSpamLimited())
- return;
+ void SendReportMessage(const char *message, const char *formatted) {
int pos = NextFreePos();
if (pos == -1)
return;
diff --git a/Core/Reporting.h b/Core/Reporting.h
index a1b04ab86f..fb16689bf8 100644
--- a/Core/Reporting.h
+++ b/Core/Reporting.h
@@ -22,29 +22,7 @@
#include "Common/CommonTypes.h"
#include "Common/File/Path.h"
-#include "Common/Log.h"
-
-#define DEBUG_LOG_REPORT(t,...) do { DEBUG_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false)
-#define ERROR_LOG_REPORT(t,...) do { ERROR_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false)
-#define WARN_LOG_REPORT(t,...) do { WARN_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false)
-#define NOTICE_LOG_REPORT(t,...) do { NOTICE_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false)
-#define INFO_LOG_REPORT(t,...) do { INFO_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } while (false)
-
-#define DEBUG_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { DEBUG_LOG_REPORT(t, __VA_ARGS__); } } while (false)
-#define ERROR_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { ERROR_LOG_REPORT(t, __VA_ARGS__); } } while (false)
-#define WARN_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { WARN_LOG_REPORT(t, __VA_ARGS__); } } while (false)
-#define NOTICE_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { NOTICE_LOG_REPORT(t, __VA_ARGS__); } } while (false)
-#define INFO_LOG_REPORT_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { INFO_LOG_REPORT(t, __VA_ARGS__); } } while (false)
-
-#define ERROR_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { ERROR_LOG(t, __VA_ARGS__); } } while (false)
-#define WARN_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { WARN_LOG(t, __VA_ARGS__); } } while (false)
-#define NOTICE_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { NOTICE_LOG(t, __VA_ARGS__); } } while (false)
-#define INFO_LOG_ONCE(n,t,...) do { if (Reporting::ShouldLogNTimes(#n, 1)) { INFO_LOG(t, __VA_ARGS__); } } while (false)
-
-#define ERROR_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { ERROR_LOG(t, __VA_ARGS__); } } while (false)
-#define WARN_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { WARN_LOG(t, __VA_ARGS__); } } while (false)
-#define NOTICE_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { NOTICE_LOG(t, __VA_ARGS__); } } while (false)
-#define INFO_LOG_N_TIMES(s,n,t,...) do { if (Reporting::ShouldLogNTimes(#s, n)) { INFO_LOG(t, __VA_ARGS__); } } while (false)
+#include "Common/LogReporting.h"
class PointerWrap;
@@ -54,9 +32,6 @@ namespace Reporting
void Init();
void Shutdown();
- // Resets counts on any count-limited logs (see ShouldLogNTimes).
- void ResetCounts();
-
// Check savestate compatibility, mostly needed on load.
void DoState(PointerWrap &p);
@@ -76,12 +51,6 @@ namespace Reporting
// Use the default reporting setting (per compiled settings) of host and enabled state.
void EnableDefault();
- // Report a message string, using the format string as a key.
- void ReportMessage(const char *message, ...);
-
- // The same, but with a preformatted version (message is still the key.)
- void ReportMessageFormatted(const char *message, const char *formatted);
-
// Report the compatibility of the current game / configuration.
void ReportCompatibility(const char *compat, int graphics, int speed, int gameplay, const std::string &screenshotFilename);
@@ -98,9 +67,6 @@ namespace Reporting
// To avoid stalling, call HasCRC() in update() or similar and call this if it returns true.
uint32_t RetrieveCRC(const Path &gamePath);
- // Returns true if that identifier has not been logged yet.
- bool ShouldLogNTimes(const char *identifier, int n);
-
enum class ReportStatus {
WORKING,
BUSY,
diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj
index c98fee5169..4f7f1939e2 100644
--- a/UWP/CommonUWP/CommonUWP.vcxproj
+++ b/UWP/CommonUWP/CommonUWP.vcxproj
@@ -475,6 +475,7 @@
+
@@ -583,6 +584,7 @@
+
diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters
index fc0d0a62cb..d055510d07 100644
--- a/UWP/CommonUWP/CommonUWP.vcxproj.filters
+++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters
@@ -100,6 +100,7 @@
+
@@ -398,6 +399,7 @@
+
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 1f0b6efd83..1df0e8c5f8 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -302,6 +302,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Common/FakeCPUDetect.cpp \
$(SRC)/Common/Log.cpp \
$(SRC)/Common/LogManager.cpp \
+ $(SRC)/Common/LogReporting.cpp \
$(SRC)/Common/MemArenaAndroid.cpp \
$(SRC)/Common/MemArenaDarwin.cpp \
$(SRC)/Common/MemArenaWin32.cpp \
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index 704993a645..f9d8df5bb3 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -299,6 +299,7 @@ SOURCES_CXX += \
$(COMMONDIR)/OSVersion.cpp \
$(COMMONDIR)/MemoryUtil.cpp \
$(COMMONDIR)/MipsCPUDetect.cpp \
+ $(COMMONDIR)/LogReporting.cpp \
$(COMMONDIR)/SysError.cpp \
$(COMMONDIR)/StringUtils.cpp \
$(COMMONDIR)/TimeUtil.cpp