sentry: various fixes. Upload last log lines with the minidump
This commit is contained in:
parent
4d77ce5a66
commit
1e0a875fa3
|
@ -23,7 +23,8 @@ option(USE_OPENGL "Use OpenGL API" ON)
|
|||
option(USE_VIDEOCORE "RPI: use the legacy Broadcom GLES libraries" OFF)
|
||||
option(APPLE_BREAKPAD "macOS: Build breakpad client and dump symbols" OFF)
|
||||
option(ENABLE_GDB_SERVER "Build with GDB debugging support" OFF)
|
||||
option(SENTRY_UPLOAD_URL "Sentry upload URL" "")
|
||||
|
||||
set(SENTRY_UPLOAD_URL "" CACHE STRING "Sentry upload URL")
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/shell/cmake")
|
||||
|
||||
|
@ -195,8 +196,8 @@ if(IOS)
|
|||
GLES_SILENCE_DEPRECATION)
|
||||
endif()
|
||||
|
||||
if(NOT ${SENTRY_UPLOAD_URL} STREQUAL "")
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE SENTRY_UPLOAD=${SENTRY_UPLOAD_URL})
|
||||
if(NOT "${SENTRY_UPLOAD_URL}" STREQUAL "")
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE SENTRY_UPLOAD="${SENTRY_UPLOAD_URL}")
|
||||
endif()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE core core/deps core/deps/stb core/khronos core/deps/json)
|
||||
|
|
|
@ -298,7 +298,7 @@ std::vector<std::string> find_system_data_dirs()
|
|||
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
|
||||
{
|
||||
if (succeeded)
|
||||
registerCrash(descriptor.directory(), descriptor.path());
|
||||
registerCrash(descriptor.directory().c_str(), descriptor.path());
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Copyright 2022 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LogManager.h"
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
class InMemoryListener : public LogListener
|
||||
{
|
||||
public:
|
||||
InMemoryListener() {
|
||||
instance = this;
|
||||
}
|
||||
~InMemoryListener() override {
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
void Log(LogTypes::LOG_LEVELS, const char* msg) override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
lines.emplace_back(msg);
|
||||
if (lines.size() > MaxLines)
|
||||
lines.pop_front();
|
||||
}
|
||||
|
||||
std::vector<std::string> getLog()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
std::vector<std::string> v(lines.begin(), lines.end());
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static InMemoryListener *getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex;
|
||||
std::deque<std::string> lines;
|
||||
|
||||
static constexpr int MaxLines = 10;
|
||||
static InMemoryListener *instance;
|
||||
};
|
|
@ -14,6 +14,7 @@
|
|||
#include <fstream>
|
||||
|
||||
#include "ConsoleListener.h"
|
||||
#include "InMemoryListener.h"
|
||||
#include "Log.h"
|
||||
#include "StringUtil.h"
|
||||
#include "cfg/cfg.h"
|
||||
|
@ -150,6 +151,8 @@ LogManager::LogManager()
|
|||
}
|
||||
EnableListener(LogListener::CONSOLE_LISTENER, cfgLoadBool("log", "LogToConsole", true));
|
||||
// EnableListener(LogListener::LOG_WINDOW_LISTENER, Config::Get(LOGGER_WRITE_TO_WINDOW));
|
||||
RegisterListener(LogListener::IN_MEMORY_LISTENER, new InMemoryListener());
|
||||
EnableListener(LogListener::IN_MEMORY_LISTENER, true);
|
||||
|
||||
for (LogContainer& container : m_log)
|
||||
{
|
||||
|
@ -164,6 +167,7 @@ LogManager::~LogManager()
|
|||
// The log window listener pointer is owned by the GUI code.
|
||||
delete m_listeners[LogListener::CONSOLE_LISTENER];
|
||||
delete m_listeners[LogListener::FILE_LISTENER];
|
||||
delete m_listeners[LogListener::IN_MEMORY_LISTENER];
|
||||
}
|
||||
|
||||
// Return the current time formatted as Minutes:Seconds:Milliseconds
|
||||
|
@ -265,3 +269,6 @@ void LogManager::Shutdown()
|
|||
delete s_log_manager;
|
||||
s_log_manager = nullptr;
|
||||
}
|
||||
|
||||
// Another singleton
|
||||
InMemoryListener *InMemoryListener::instance;
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
FILE_LISTENER = 0,
|
||||
CONSOLE_LISTENER,
|
||||
LOG_WINDOW_LISTENER,
|
||||
IN_MEMORY_LISTENER,
|
||||
|
||||
NUMBER_OF_LISTENERS // Must be last
|
||||
};
|
||||
|
|
|
@ -153,17 +153,41 @@ std::string getBiosFontPath()
|
|||
|
||||
#include "rend/boxart/http_client.h"
|
||||
#include "version.h"
|
||||
#include "log/InMemoryListener.h"
|
||||
|
||||
#define FLYCAST_CRASH_LIST "flycast-crashes.txt"
|
||||
|
||||
void registerCrash(const std::string& directory, const char *path)
|
||||
void registerCrash(const char *directory, const char *path)
|
||||
{
|
||||
FILE *f = nowide::fopen((directory + "/" FLYCAST_CRASH_LIST).c_str(), "at");
|
||||
char list[256];
|
||||
// Register .dmp in crash list
|
||||
snprintf(list, sizeof(list), "%s/%s", directory, FLYCAST_CRASH_LIST);
|
||||
FILE *f = nowide::fopen(list, "at");
|
||||
if (f != nullptr)
|
||||
{
|
||||
fprintf(f, "%s", path);
|
||||
fprintf(f, "%s\n", path);
|
||||
fclose(f);
|
||||
}
|
||||
// Save last log lines
|
||||
InMemoryListener *listener = InMemoryListener::getInstance();
|
||||
if (listener != nullptr)
|
||||
{
|
||||
strncpy(list, path, sizeof(list) - 1);
|
||||
list[sizeof(list) - 1] = '\0';
|
||||
char *p = strrchr(list, '.');
|
||||
if (p != nullptr && (p - list) < (int)sizeof(list) - 4)
|
||||
{
|
||||
strcpy(p + 1, "log");
|
||||
FILE *f = nowide::fopen(list, "wt");
|
||||
if (f != nullptr)
|
||||
{
|
||||
std::vector<std::string> log = listener->getLog();
|
||||
for (const auto& line : log)
|
||||
fprintf(f, "%s", line.c_str());
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uploadCrashes(const std::string& directory)
|
||||
|
@ -181,26 +205,34 @@ void uploadCrashes(const std::string& directory)
|
|||
*p = '\0';
|
||||
if (file_exists(line))
|
||||
{
|
||||
std::string dmpfile(line);
|
||||
std::string logfile = get_file_basename(dmpfile) + ".log";
|
||||
#ifdef SENTRY_UPLOAD
|
||||
#define STRINGIZE(x) #x
|
||||
if (config::UploadCrashLogs)
|
||||
{
|
||||
NOTICE_LOG(COMMON, "Uploading minidump %s", line);
|
||||
std::vector<http::PostField> fields;
|
||||
fields.emplace_back("upload_file_minidump", std::string(line), "application/octet-stream");
|
||||
fields.emplace_back("upload_file_minidump", dmpfile, "application/octet-stream");
|
||||
fields.emplace_back("flycast_version", std::string(GIT_VERSION));
|
||||
// TODO log, config, gpu/driver
|
||||
int rc = http::post(STRINGIZE(SENTRY_UPLOAD), fields);
|
||||
if (rc >= 200 && rc < 300)
|
||||
nowide::remove(line);
|
||||
if (file_exists(logfile))
|
||||
fields.emplace_back("flycast_log", logfile, "text/plain");
|
||||
// TODO config, gpu/driver, ...
|
||||
int rc = http::post(SENTRY_UPLOAD, fields);
|
||||
if (rc >= 200 && rc < 300) {
|
||||
nowide::remove(dmpfile.c_str());
|
||||
nowide::remove(logfile.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
NOTICE_LOG(COMMON, "Upload failed: HTTP error %d", rc);
|
||||
uploadFailure = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
#undef STRINGIZE
|
||||
#endif
|
||||
{
|
||||
nowide::remove(line);
|
||||
nowide::remove(dmpfile.c_str());
|
||||
nowide::remove(logfile.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +244,7 @@ void uploadCrashes(const std::string& directory)
|
|||
|
||||
#else
|
||||
|
||||
void registerCrash(const std::string& directory, const char *path) {}
|
||||
void registerCrash(const char *directory, const char *path) {}
|
||||
void uploadCrashes(const std::string& directory) {}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -135,5 +135,5 @@ static inline void freeAligned(void *p)
|
|||
#endif
|
||||
}
|
||||
|
||||
void registerCrash(const std::string& directory, const char *path);
|
||||
void registerCrash(const char *directory, const char *path);
|
||||
void uploadCrashes(const std::string& directory);
|
||||
|
|
|
@ -739,7 +739,7 @@ static bool dumpCallback(const wchar_t* dump_path,
|
|||
if (path.convert(minidump_id))
|
||||
{
|
||||
std::string fullPath = directory + '\\' + std::string(path.c_str()) + ".dmp";
|
||||
registerCrash(directory, fullPath.c_str());
|
||||
registerCrash(directory.c_str(), fullPath.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
|
|||
if (succeeded)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_ERROR, "Flycast", "Minidump saved to '%s'\n", descriptor.path());
|
||||
registerCrash(descriptor.directory(), descriptor.path());
|
||||
registerCrash(descriptor.directory().c_str(), descriptor.path());
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue