Sentry: implement basic exception reporting, error breadcrumbs

This commit is contained in:
Lion Kortlepel 2021-08-08 01:32:25 +02:00 committed by Lion
parent 550c658ac5
commit 2b4fec6d11
5 changed files with 66 additions and 32 deletions

View File

@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(Server) project(Server)
add_subdirectory("include/sentry-native")
if (WIN32) if (WIN32)
message(STATUS "MSVC -> forcing use of statically-linked runtime.") message(STATUS "MSVC -> forcing use of statically-linked runtime.")
STRING(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) STRING(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
@ -19,13 +21,18 @@ elseif (UNIX)
endif (SANITIZE) endif (SANITIZE)
endif () endif ()
# this is set by the build system.
# if you're building from source, just leave this empty
if (NOT DEFINED BEAMMP_SECRET_SENTRY_URL)
set(BEAMMP_SECRET_SENTRY_URL "")
endif()
# this has to happen before -DDEBUG since it wont compile properly with -DDEBUG # this has to happen before -DDEBUG since it wont compile properly with -DDEBUG
include_directories("asio/asio/include") include_directories("asio/asio/include")
include_directories("rapidjson/include") include_directories("rapidjson/include")
include_directories("websocketpp") include_directories("websocketpp")
add_subdirectory("socket.io-client-cpp") add_subdirectory("socket.io-client-cpp")
add_subdirectory("include/commandline") add_subdirectory("include/commandline")
add_subdirectory("include/sentry-native")
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
@ -59,8 +66,10 @@ target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCL
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
if (UNIX) if (UNIX)
add_definitions(-DSECRET_SENTRY_URL="${BEAMMP_SECRET_SENTRY_URL}")
target_link_libraries(BeamMP-Server z pthread stdc++fs ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls sentry) target_link_libraries(BeamMP-Server z pthread stdc++fs ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls sentry)
elseif (WIN32) elseif (WIN32)
add_definitions(/DSECRET_SENTRY_URL="${BEAMMP_SECRET_SENTRY_URL}")
include(FindLua) include(FindLua)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
find_package(RapidJSON CONFIG REQUIRED) find_package(RapidJSON CONFIG REQUIRED)

View File

@ -79,6 +79,9 @@ void RegisterThread(const std::string str);
#define _line std::to_string(__LINE__) #define _line std::to_string(__LINE__)
#define _in_lambda (std::string(__func__) == "operator()") #define _in_lambda (std::string(__func__) == "operator()")
#include "Sentry.h"
extern TSentry Sentry;
// we would like the full function signature 'void a::foo() const' // we would like the full function signature 'void a::foo() const'
// on windows this is __FUNCSIG__, on GCC it's __PRETTY_FUNCTION__, // on windows this is __FUNCSIG__, on GCC it's __PRETTY_FUNCTION__,
// feel free to add more // feel free to add more
@ -108,7 +111,7 @@ void RegisterThread(const std::string str);
#define warn(x) Application::Console().Write(_this_location + std::string("[WARN] ") + (x)) #define warn(x) Application::Console().Write(_this_location + std::string("[WARN] ") + (x))
#define info(x) Application::Console().Write(_this_location + std::string("[INFO] ") + (x)) #define info(x) Application::Console().Write(_this_location + std::string("[INFO] ") + (x))
#define error(x) Application::Console().Write(_this_location + std::string("[ERROR] ") + (x)) #define error(x) do { Application::Console().Write(_this_location + std::string("[ERROR] ") + (x)); Sentry.AddErrorBreadcrumb((x), _file_basename, _line); } while (false)
#define luaprint(x) Application::Console().Write(_this_location + std::string("[LUA] ") + (x)) #define luaprint(x) Application::Console().Write(_this_location + std::string("[LUA] ") + (x))
#define debug(x) \ #define debug(x) \
do { \ do { \

View File

@ -1,14 +1,25 @@
#ifndef SENTRY_H #ifndef SENTRY_H
#define SENTRY_H #define SENTRY_H
#include <sentry.h>
#include <string> #include <string>
enum class Logger {
};
// singleton, dont make this twice // singleton, dont make this twice
class Sentry final { class TSentry final {
public: public:
Sentry(const std::string& SentryUrl); TSentry(const std::string& SentryUrl);
~Sentry(); ~TSentry();
void Log(sentry_level_t level, const std::string& logger, const std::string& text);
void LogException(const std::exception& e, const std::string& file, const std::string& line);
void AddErrorBreadcrumb(const std::string& msg, const std::string& file, const std::string& line);
private: private:
bool mValid { true };
}; };
#endif // SENTRY_H #endif // SENTRY_H

View File

@ -1,16 +1,35 @@
#include "Sentry.h" #include "Sentry.h"
#include "Common.h" #include "Common.h"
#include "sentry.h" TSentry::TSentry(const std::string& SentryUrl) {
if (SentryUrl.empty()) {
Sentry::Sentry(const std::string& SentryUrl) { mValid = false;
} else {
mValid = true;
sentry_options_t* options = sentry_options_new(); sentry_options_t* options = sentry_options_new();
sentry_options_set_dsn(options, SentryUrl.c_str()); sentry_options_set_dsn(options, SentryUrl.c_str());
auto ReleaseString = "BeamMP-Server@" + Application::ServerVersion(); auto ReleaseString = "BeamMP-Server@" + Application::ServerVersion();
sentry_options_set_release(options, ReleaseString.c_str()); sentry_options_set_release(options, ReleaseString.c_str());
sentry_init(options); sentry_init(options);
}
} }
Sentry::~Sentry() { TSentry::~TSentry() {
if (mValid) {
sentry_close(); sentry_close();
}
}
void TSentry::Log(sentry_level_t level, const std::string& logger, const std::string& text) {
sentry_capture_event(sentry_value_new_message_event(level, logger.c_str(), text.c_str()));
}
void TSentry::LogException(const std::exception& e, const std::string& file, const std::string& line) {
Log(SENTRY_LEVEL_ERROR, "exceptions", std::string(e.what()) + " @ " + file + ":" + line);
}
void TSentry::AddErrorBreadcrumb(const std::string& msg, const std::string& file, const std::string& line) {
auto crumb = sentry_value_new_breadcrumb("default", (msg + " @ " + file + ":" + line).c_str());
sentry_value_set_by_key(crumb, "level", sentry_value_new_string("error"));
sentry_add_breadcrumb(crumb);
} }

View File

@ -35,7 +35,11 @@ void UnixSignalHandler(int sig) {
} }
#endif // __unix #endif // __unix
int main(int argc, char** argv) { // this is provided by the build system, leave empty for source builds
// global, yes, this is ugly, no, it cant be done another way
TSentry Sentry { SECRET_SENTRY_URL };
int main(int argc, char** argv) try {
#ifdef __unix #ifdef __unix
#if DEBUG #if DEBUG
info("registering handlers for SIGINT, SIGTERM, SIGPIPE"); info("registering handlers for SIGINT, SIGTERM, SIGPIPE");
@ -46,27 +50,12 @@ int main(int argc, char** argv) {
signal(SIGINT, UnixSignalHandler); signal(SIGINT, UnixSignalHandler);
#endif // DEBUG #endif // DEBUG
#endif // __unix #endif // __unix
// FIXME: this is not prod ready, needs to be compile-time value
char* sentry_url = getenv("SENTRY_URL");
if (!sentry_url) {
error("no sentry url supplied in environment, this is not a fatal error");
} else {
info("sentry url has length " + std::to_string(std::string(sentry_url).size()));
}
Sentry sentry(sentry_url);
sentry_capture_event(sentry_value_new_message_event(
/* level */ SENTRY_LEVEL_INFO,
/* logger */ "custom",
/* message */ "It works!"));
setlocale(LC_ALL, "C"); setlocale(LC_ALL, "C");
bool Shutdown = false; bool Shutdown = false;
Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; }); Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; });
TServer Server(argc, argv); TServer Server(argc, argv);
TConfig Config; TConfig Config;
@ -89,4 +78,7 @@ int main(int argc, char** argv) {
while (!Shutdown) { while (!Shutdown) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
} }
} catch (const std::exception& e) {
error(e.what());
Sentry.LogException(e, _file_basename, _line);
} }