aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/sentryintegration.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-10-06 10:45:48 +0200
committerGitHub <[email protected]>2023-10-06 10:45:48 +0200
commitfb70324d37282910d7fa3047f4ec290d0c5a94b1 (patch)
treea1bc82fcfdb96eb5b461742b613fcbb63f816a54 /src/zenserver/sentryintegration.cpp
parentreject known bad bucket names in structured cache (#452) (diff)
downloadzen-fb70324d37282910d7fa3047f4ec290d0c5a94b1.tar.xz
zen-fb70324d37282910d7fa3047f4ec290d0c5a94b1.zip
zenserver project restructuring (#442)
Diffstat (limited to 'src/zenserver/sentryintegration.cpp')
-rw-r--r--src/zenserver/sentryintegration.cpp288
1 files changed, 288 insertions, 0 deletions
diff --git a/src/zenserver/sentryintegration.cpp b/src/zenserver/sentryintegration.cpp
new file mode 100644
index 000000000..2c51c3b36
--- /dev/null
+++ b/src/zenserver/sentryintegration.cpp
@@ -0,0 +1,288 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "sentryintegration.h"
+
+#include <zencore/config.h>
+#include <zencore/logging.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#if ZEN_PLATFORM_LINUX
+# include <pwd.h>
+#endif
+
+#if ZEN_PLATFORM_MAC
+# include <pwd.h>
+#endif
+
+#if ZEN_USE_SENTRY
+# define SENTRY_BUILD_STATIC 1
+ZEN_THIRD_PARTY_INCLUDES_START
+# include <sentry.h>
+# include <spdlog/sinks/base_sink.h>
+ZEN_THIRD_PARTY_INCLUDES_END
+
+namespace sentry {
+
+struct SentryAssertImpl : zen::AssertImpl
+{
+ ZEN_FORCENOINLINE ZEN_DEBUG_SECTION SentryAssertImpl();
+ virtual ZEN_FORCENOINLINE ZEN_DEBUG_SECTION ~SentryAssertImpl();
+ virtual void ZEN_FORCENOINLINE ZEN_DEBUG_SECTION OnAssert(const char* Filename,
+ int LineNumber,
+ const char* FunctionName,
+ const char* Msg) override;
+ AssertImpl* PrevAssertImpl;
+};
+
+class sentry_sink final : public spdlog::sinks::base_sink<spdlog::details::null_mutex>
+{
+public:
+ sentry_sink();
+ ~sentry_sink();
+
+protected:
+ void sink_it_(const spdlog::details::log_msg& msg) override;
+ void flush_() override;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+static constexpr sentry_level_t MapToSentryLevel[spdlog::level::level_enum::n_levels] = {SENTRY_LEVEL_DEBUG,
+ SENTRY_LEVEL_DEBUG,
+ SENTRY_LEVEL_INFO,
+ SENTRY_LEVEL_WARNING,
+ SENTRY_LEVEL_ERROR,
+ SENTRY_LEVEL_FATAL,
+ SENTRY_LEVEL_DEBUG};
+
+sentry_sink::sentry_sink()
+{
+}
+sentry_sink::~sentry_sink()
+{
+}
+
+void
+sentry_sink::sink_it_(const spdlog::details::log_msg& msg)
+{
+ try
+ {
+ std::string Message = fmt::format("{}\n{}({}) [{}]", msg.payload, msg.source.filename, msg.source.line, msg.source.funcname);
+ sentry_value_t event = sentry_value_new_message_event(
+ /* level */ MapToSentryLevel[msg.level],
+ /* logger */ nullptr,
+ /* message */ Message.c_str());
+ sentry_event_value_add_stacktrace(event, NULL, 0);
+ sentry_capture_event(event);
+ }
+ catch (std::exception&)
+ {
+ // If our logging with Message formatting fails we do a non-allocating version and just post the msg.payload raw
+ char TmpBuffer[256];
+ size_t MaxCopy = zen::Min<size_t>(msg.payload.size(), size_t(255));
+ memcpy(TmpBuffer, msg.payload.data(), MaxCopy);
+ TmpBuffer[MaxCopy] = '\0';
+ sentry_value_t event = sentry_value_new_message_event(
+ /* level */ SENTRY_LEVEL_ERROR,
+ /* logger */ nullptr,
+ /* message */ TmpBuffer);
+ sentry_event_value_add_stacktrace(event, NULL, 0);
+ sentry_capture_event(event);
+ }
+}
+void
+sentry_sink::flush_()
+{
+}
+
+SentryAssertImpl::SentryAssertImpl() : PrevAssertImpl(CurrentAssertImpl)
+{
+ CurrentAssertImpl = this;
+}
+
+SentryAssertImpl::~SentryAssertImpl()
+{
+ CurrentAssertImpl = PrevAssertImpl;
+}
+
+void
+SentryAssertImpl::OnAssert(const char* Filename, int LineNumber, const char* FunctionName, const char* Msg)
+{
+ try
+ {
+ std::string Message = fmt::format("ASSERT {}:({}) [{}]\n\"{}\"", Filename, LineNumber, FunctionName, Msg);
+ sentry_value_t event = sentry_value_new_message_event(
+ /* level */ SENTRY_LEVEL_ERROR,
+ /* logger */ nullptr,
+ /* message */ Message.c_str());
+ sentry_event_value_add_stacktrace(event, NULL, 0);
+ sentry_capture_event(event);
+ }
+ catch (std::exception&)
+ {
+ // If our logging with Message formatting fails we do a non-allocating version and just post the Msg raw
+ sentry_value_t event = sentry_value_new_message_event(
+ /* level */ SENTRY_LEVEL_ERROR,
+ /* logger */ nullptr,
+ /* message */ Msg);
+ sentry_event_value_add_stacktrace(event, NULL, 0);
+ sentry_capture_event(event);
+ }
+}
+
+} // namespace sentry
+
+namespace zen {
+
+# if ZEN_USE_SENTRY
+static void
+SentryLogFunction(sentry_level_t Level, const char* Message, va_list Args, [[maybe_unused]] void* Userdata)
+{
+ char LogMessageBuffer[160];
+ std::string LogMessage;
+ const char* MessagePtr = LogMessageBuffer;
+
+ int n = vsnprintf(LogMessageBuffer, sizeof LogMessageBuffer, Message, Args);
+
+ if (n >= int(sizeof LogMessageBuffer))
+ {
+ LogMessage.resize(n + 1);
+
+ n = vsnprintf(LogMessage.data(), LogMessage.size(), Message, Args);
+
+ MessagePtr = LogMessage.c_str();
+ }
+
+ switch (Level)
+ {
+ case SENTRY_LEVEL_DEBUG:
+ ConsoleLog().debug("sentry: {}", MessagePtr);
+ break;
+
+ case SENTRY_LEVEL_INFO:
+ ConsoleLog().info("sentry: {}", MessagePtr);
+ break;
+
+ case SENTRY_LEVEL_WARNING:
+ ConsoleLog().warn("sentry: {}", MessagePtr);
+ break;
+
+ case SENTRY_LEVEL_ERROR:
+ ConsoleLog().error("sentry: {}", MessagePtr);
+ break;
+
+ case SENTRY_LEVEL_FATAL:
+ ConsoleLog().critical("sentry: {}", MessagePtr);
+ break;
+ }
+}
+# endif
+
+SentryIntegration::SentryIntegration()
+{
+}
+
+SentryIntegration::~SentryIntegration()
+{
+ if (m_IsInitialized && m_SentryErrorCode == 0)
+ {
+ logging::SetErrorLog(std::shared_ptr<spdlog::logger>());
+ m_SentryAssert.reset();
+ sentry_close();
+ }
+}
+
+void
+SentryIntegration::Initialize(std::string SentryDatabasePath, std::string SentryAttachmentPath, bool AllowPII)
+{
+ m_AllowPII = AllowPII;
+
+ if (SentryDatabasePath.starts_with("\\\\?\\"))
+ {
+ SentryDatabasePath = SentryDatabasePath.substr(4);
+ }
+ sentry_options_t* SentryOptions = sentry_options_new();
+ sentry_options_set_dsn(SentryOptions, "https://[email protected]/5919284");
+ sentry_options_set_database_path(SentryOptions, SentryDatabasePath.c_str());
+ sentry_options_set_logger(SentryOptions, SentryLogFunction, this);
+ if (SentryAttachmentPath.starts_with("\\\\?\\"))
+ {
+ SentryAttachmentPath = SentryAttachmentPath.substr(4);
+ }
+ sentry_options_add_attachment(SentryOptions, SentryAttachmentPath.c_str());
+ sentry_options_set_release(SentryOptions, ZEN_CFG_VERSION);
+
+ // sentry_options_set_debug(SentryOptions, 1);
+
+ m_SentryErrorCode = sentry_init(SentryOptions);
+
+ if (m_SentryErrorCode == 0)
+ {
+ if (m_AllowPII)
+ {
+# if ZEN_PLATFORM_WINDOWS
+ CHAR UserNameBuffer[511 + 1];
+ DWORD UserNameLength = sizeof(UserNameBuffer) / sizeof(CHAR);
+ BOOL OK = GetUserNameA(UserNameBuffer, &UserNameLength);
+ if (OK && UserNameLength)
+ {
+ m_SentryUserName = std::string(UserNameBuffer, UserNameLength - 1);
+ }
+# endif // ZEN_PLATFORM_WINDOWS
+# if (ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC)
+ uid_t uid = geteuid();
+ struct passwd* pw = getpwuid(uid);
+ if (pw)
+ {
+ m_SentryUserName = std::string(pw->pw_name);
+ }
+# endif
+ sentry_value_t SentryUserObject = sentry_value_new_object();
+ sentry_value_set_by_key(SentryUserObject, "id", sentry_value_new_string(m_SentryUserName.c_str()));
+ sentry_value_set_by_key(SentryUserObject, "username", sentry_value_new_string(m_SentryUserName.c_str()));
+ sentry_value_set_by_key(SentryUserObject, "ip_address", sentry_value_new_string("{{auto}}"));
+ sentry_set_user(SentryUserObject);
+ }
+
+ auto SentrySink = spdlog::create<sentry::sentry_sink>("sentry");
+ logging::SetErrorLog(std::move(SentrySink));
+
+ m_SentryAssert = std::make_unique<sentry::SentryAssertImpl>();
+ }
+
+ m_IsInitialized = true;
+}
+
+void
+SentryIntegration::LogStartupInformation()
+{
+ if (m_IsInitialized)
+ {
+ if (m_SentryErrorCode == 0)
+ {
+ if (m_AllowPII)
+ {
+ ZEN_INFO("sentry initialized, username: '{}'", m_SentryUserName);
+ }
+ else
+ {
+ ZEN_INFO("sentry initialized with anonymous reports");
+ }
+ }
+ else
+ {
+ ZEN_WARN("sentry_init returned failure! (error code: {})", m_SentryErrorCode);
+ }
+ }
+}
+
+void
+SentryIntegration::ClearCaches()
+{
+ sentry_clear_modulecache();
+}
+
+} // namespace zen
+#endif