From 64678e0114270c5aaceeff3c66ec45613472fc79 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Jun 2021 09:19:10 -0700 Subject: [PATCH] Reporting: Move message report interface to Common. This makes it so we can call reporting from Common. --- CMakeLists.txt | 2 + Common/Common.vcxproj | 2 + Common/Common.vcxproj.filters | 2 + Common/LogReporting.cpp | 92 +++++++++++++++++++++++++ Common/LogReporting.h | 65 +++++++++++++++++ Core/Reporting.cpp | 68 +++--------------- Core/Reporting.h | 36 +--------- UWP/CommonUWP/CommonUWP.vcxproj | 2 + UWP/CommonUWP/CommonUWP.vcxproj.filters | 2 + android/jni/Android.mk | 1 + libretro/Makefile.common | 1 + 11 files changed, 179 insertions(+), 94 deletions(-) create mode 100644 Common/LogReporting.cpp create mode 100644 Common/LogReporting.h 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