Reporting: Move message report interface to Common.

This makes it so we can call reporting from Common.
This commit is contained in:
Unknown W. Brackets 2021-06-06 09:19:10 -07:00
parent c8cf2ce5c6
commit 64678e0114
11 changed files with 179 additions and 94 deletions

View File

@ -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

View File

@ -469,6 +469,7 @@
<ClInclude Include="Render\Text\draw_text_qt.h" />
<ClInclude Include="Render\Text\draw_text_uwp.h" />
<ClInclude Include="Render\Text\draw_text_win.h" />
<ClInclude Include="LogReporting.h" />
<ClInclude Include="Serialize\SerializeDeque.h" />
<ClInclude Include="Serialize\SerializeFuncs.h" />
<ClInclude Include="Data\Convert\ColorConvNEON.h" />
@ -891,6 +892,7 @@
<ClCompile Include="Render\Text\draw_text_qt.cpp" />
<ClCompile Include="Render\Text\draw_text_uwp.cpp" />
<ClCompile Include="Render\Text\draw_text_win.cpp" />
<ClCompile Include="LogReporting.cpp" />
<ClCompile Include="Serialize\Serializer.cpp" />
<ClCompile Include="Data\Convert\ColorConv.cpp" />
<ClCompile Include="ConsoleListener.cpp" />

View File

@ -394,6 +394,7 @@
<ClInclude Include="File\Path.h">
<Filter>File</Filter>
</ClInclude>
<ClInclude Include="LogReporting.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ABI.cpp" />
@ -760,6 +761,7 @@
<ClCompile Include="File\Path.cpp">
<Filter>File</Filter>
</ClCompile>
<ClCompile Include="LogReporting.cpp" />
</ItemGroup>
<ItemGroup>
<Filter Include="Crypto">

92
Common/LogReporting.cpp Normal file
View File

@ -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 <cstdarg>
#include <cstdio>
#include <mutex>
#include <unordered_map>
#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<const char *, int> 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<std::mutex> lock(logNTimesLock);
auto iter = logNTimes.find(identifier);
if (iter == logNTimes.end()) {
logNTimes.insert(std::pair<const char*, int>(identifier, 1));
return true;
} else {
if (iter->second >= count) {
return false;
} else {
iter->second++;
return true;
}
}
}
void ResetCounts() {
std::lock_guard<std::mutex> 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);
}
}

65
Common/LogReporting.h Normal file
View File

@ -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);
}

View File

@ -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<const char *, int> 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<std::mutex> lock(logNTimesLock);
auto iter = logNTimes.find(identifier);
if (iter == logNTimes.end()) {
logNTimes.insert(std::pair<const char*, int>(identifier, 1));
return true;
} else {
if (iter->second >= count) {
return false;
} else {
iter->second++;
return true;
}
}
}
void ResetCounts() {
std::lock_guard<std::mutex> 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<std::mutex> 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;

View File

@ -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,

View File

@ -475,6 +475,7 @@
<ClInclude Include="..\..\Common\GraphicsContext.h" />
<ClInclude Include="..\..\Common\Log.h" />
<ClInclude Include="..\..\Common\LogManager.h" />
<ClInclude Include="..\..\Common\LogReporting.h" />
<ClInclude Include="..\..\Common\MemArena.h" />
<ClInclude Include="..\..\Common\MemoryUtil.h" />
<ClInclude Include="..\..\Common\MipsEmitter.h" />
@ -583,6 +584,7 @@
<ClCompile Include="..\..\Common\ExceptionHandlerSetup.cpp" />
<ClCompile Include="..\..\Common\Log.cpp" />
<ClCompile Include="..\..\Common\LogManager.cpp" />
<ClCompile Include="..\..\Common\LogReporting.cpp" />
<ClCompile Include="..\..\Common\MemArenaAndroid.cpp" />
<ClCompile Include="..\..\Common\MemArenaDarwin.cpp" />
<ClCompile Include="..\..\Common\MemArenaPosix.cpp" />

View File

@ -100,6 +100,7 @@
<ClCompile Include="..\..\Common\ExceptionHandlerSetup.cpp" />
<ClCompile Include="..\..\Common\Log.cpp" />
<ClCompile Include="..\..\Common\LogManager.cpp" />
<ClCompile Include="..\..\Common\LogReporting.cpp" />
<ClCompile Include="..\..\Common\MemArenaAndroid.cpp" />
<ClCompile Include="..\..\Common\MemArenaDarwin.cpp" />
<ClCompile Include="..\..\Common\MemArenaPosix.cpp" />
@ -398,6 +399,7 @@
<ClInclude Include="..\..\Common\GraphicsContext.h" />
<ClInclude Include="..\..\Common\Log.h" />
<ClInclude Include="..\..\Common\LogManager.h" />
<ClInclude Include="..\..\Common\LogReporting.h" />
<ClInclude Include="..\..\Common\MemArena.h" />
<ClInclude Include="..\..\Common\MemoryUtil.h" />
<ClInclude Include="..\..\Common\MipsEmitter.h" />

View File

@ -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 \

View File

@ -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