diff --git a/CMakeLists.txt b/CMakeLists.txt index fe4aba8..ca57dd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.0) project(Server) +add_subdirectory("include/sentry-native") + if (WIN32) message(STATUS "MSVC -> forcing use of statically-linked runtime.") STRING(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) @@ -19,13 +21,18 @@ elseif (UNIX) endif (SANITIZE) 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 include_directories("asio/asio/include") include_directories("rapidjson/include") include_directories("websocketpp") add_subdirectory("socket.io-client-cpp") add_subdirectory("include/commandline") -add_subdirectory("include/sentry-native") set(CMAKE_CXX_STANDARD 17) @@ -59,8 +66,10 @@ target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCL find_package(OpenSSL REQUIRED) 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) elseif (WIN32) + add_definitions(/DSECRET_SENTRY_URL="${BEAMMP_SECRET_SENTRY_URL}") include(FindLua) find_package(ZLIB REQUIRED) find_package(RapidJSON CONFIG REQUIRED) diff --git a/include/Common.h b/include/Common.h index 76d5012..c23ccdf 100644 --- a/include/Common.h +++ b/include/Common.h @@ -79,6 +79,9 @@ void RegisterThread(const std::string str); #define _line std::to_string(__LINE__) #define _in_lambda (std::string(__func__) == "operator()") +#include "Sentry.h" +extern TSentry Sentry; + // we would like the full function signature 'void a::foo() const' // on windows this is __FUNCSIG__, on GCC it's __PRETTY_FUNCTION__, // 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 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 debug(x) \ do { \ diff --git a/include/Sentry.h b/include/Sentry.h index 40006ee..4f491ec 100644 --- a/include/Sentry.h +++ b/include/Sentry.h @@ -1,14 +1,25 @@ #ifndef SENTRY_H #define SENTRY_H +#include #include +enum class Logger { + +}; + // singleton, dont make this twice -class Sentry final { +class TSentry final { public: - Sentry(const std::string& SentryUrl); - ~Sentry(); + TSentry(const std::string& SentryUrl); + ~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: + bool mValid { true }; }; #endif // SENTRY_H diff --git a/src/Sentry.cpp b/src/Sentry.cpp index ed593b8..2d92f5a 100644 --- a/src/Sentry.cpp +++ b/src/Sentry.cpp @@ -1,16 +1,35 @@ #include "Sentry.h" #include "Common.h" -#include "sentry.h" - -Sentry::Sentry(const std::string& SentryUrl) { - sentry_options_t* options = sentry_options_new(); - sentry_options_set_dsn(options, SentryUrl.c_str()); - auto ReleaseString = "BeamMP-Server@" + Application::ServerVersion(); - sentry_options_set_release(options, ReleaseString.c_str()); - sentry_init(options); +TSentry::TSentry(const std::string& SentryUrl) { + if (SentryUrl.empty()) { + mValid = false; + } else { + mValid = true; + sentry_options_t* options = sentry_options_new(); + sentry_options_set_dsn(options, SentryUrl.c_str()); + auto ReleaseString = "BeamMP-Server@" + Application::ServerVersion(); + sentry_options_set_release(options, ReleaseString.c_str()); + sentry_init(options); + } } -Sentry::~Sentry() { - sentry_close(); +TSentry::~TSentry() { + if (mValid) { + 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); } diff --git a/src/main.cpp b/src/main.cpp index 9d064f4..af7edd6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,7 +35,11 @@ void UnixSignalHandler(int sig) { } #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 #if DEBUG info("registering handlers for SIGINT, SIGTERM, SIGPIPE"); @@ -46,27 +50,12 @@ int main(int argc, char** argv) { signal(SIGINT, UnixSignalHandler); #endif // DEBUG #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"); bool Shutdown = false; Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; }); + TServer Server(argc, argv); TConfig Config; @@ -89,4 +78,7 @@ int main(int argc, char** argv) { while (!Shutdown) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } +} catch (const std::exception& e) { + error(e.what()); + Sentry.LogException(e, _file_basename, _line); }