aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/sentryintegration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zencore/sentryintegration.cpp')
-rw-r--r--src/zencore/sentryintegration.cpp153
1 files changed, 80 insertions, 73 deletions
diff --git a/src/zencore/sentryintegration.cpp b/src/zencore/sentryintegration.cpp
index 636e182b4..c9c843dd6 100644
--- a/src/zencore/sentryintegration.cpp
+++ b/src/zencore/sentryintegration.cpp
@@ -4,29 +4,23 @@
#include <zencore/config.h>
#include <zencore/logging.h>
+#include <zencore/logging/registry.h>
+#include <zencore/logging/sink.h>
#include <zencore/session.h>
#include <zencore/uid.h>
#include <stdarg.h>
#include <stdio.h>
-#if ZEN_PLATFORM_LINUX
+#if ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC
# include <pwd.h>
+# include <unistd.h>
#endif
-#if ZEN_PLATFORM_MAC
-# include <pwd.h>
-#endif
-
-ZEN_THIRD_PARTY_INCLUDES_START
-#include <spdlog/spdlog.h>
-ZEN_THIRD_PARTY_INCLUDES_END
-
#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 {
@@ -37,6 +31,8 @@ namespace {
struct SentryAssertImpl : zen::AssertImpl
{
+ ZEN_DEBUG_SECTION ~SentryAssertImpl() override = default;
+
virtual void ZEN_FORCENOINLINE ZEN_DEBUG_SECTION OnAssert(const char* Filename,
int LineNumber,
const char* FunctionName,
@@ -44,71 +40,59 @@ struct SentryAssertImpl : zen::AssertImpl
const zen::CallstackFrames* Callstack) override;
};
-class sentry_sink final : public spdlog::sinks::base_sink<spdlog::details::null_mutex>
+static constexpr sentry_level_t MapToSentryLevel[zen::logging::LogLevelCount] = {SENTRY_LEVEL_DEBUG,
+ SENTRY_LEVEL_DEBUG,
+ SENTRY_LEVEL_INFO,
+ SENTRY_LEVEL_WARNING,
+ SENTRY_LEVEL_ERROR,
+ SENTRY_LEVEL_FATAL,
+ SENTRY_LEVEL_DEBUG};
+
+class SentrySink final : public zen::logging::Sink
{
public:
- sentry_sink();
- ~sentry_sink();
+ SentrySink() = default;
+ ~SentrySink() = default;
-protected:
- void sink_it_(const spdlog::details::log_msg& msg) override;
- void flush_() override;
+ void Log(const zen::logging::LogMessage& Msg) override
+ {
+ if (Msg.GetLevel() != zen::logging::Err && Msg.GetLevel() != zen::logging::Critical)
+ {
+ return;
+ }
+ try
+ {
+ const char* Filename = Msg.GetSource().Filename ? Msg.GetSource().Filename : "<unknown>";
+ std::string Message = fmt::format("{}\n{}({})", Msg.GetPayload(), Filename, Msg.GetSource().Line);
+ sentry_value_t Event = sentry_value_new_message_event(
+ /* level */ MapToSentryLevel[Msg.GetLevel()],
+ /* logger */ nullptr,
+ /* message */ Message.c_str());
+ sentry_event_value_add_stacktrace(Event, NULL, 0);
+ sentry_capture_event(Event);
+ }
+ catch (const std::exception&)
+ {
+ // If our logging with Message formatting fails we do a non-allocating version and just post the payload raw
+ char TmpBuffer[256];
+ size_t MaxCopy = zen::Min<size_t>(Msg.GetPayload().size(), size_t(255));
+ memcpy(TmpBuffer, Msg.GetPayload().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 Flush() override {}
+ void SetFormatter(std::unique_ptr<zen::logging::Formatter>) 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)
-{
- if (msg.level != spdlog::level::err && msg.level != spdlog::level::critical)
- {
- return;
- }
- 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 (const 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_()
-{
-}
-
void
SentryAssertImpl::OnAssert(const char* Filename,
int LineNumber,
@@ -147,6 +131,8 @@ namespace zen {
# if ZEN_USE_SENTRY
ZEN_DEFINE_LOG_CATEGORY_STATIC(LogSentry, "sentry-sdk");
+static std::atomic<bool> s_SentryLogEnabled{true};
+
static void
SentryLogFunction(sentry_level_t Level, const char* Message, va_list Args, [[maybe_unused]] void* Userdata)
{
@@ -166,14 +152,15 @@ SentryLogFunction(sentry_level_t Level, const char* Message, va_list Args, [[may
}
// SentryLogFunction can be called before the logging system is initialized
- // (during sentry_init which runs before InitializeLogging). Fall back to
- // console logging when the category logger is not yet available.
+ // (during sentry_init which runs before InitializeLogging), or after it has
+ // been shut down (during sentry_close on a background worker thread). Fall
+ // back to console logging when the category logger is not available.
//
// Since we want to default to WARN level but this runs before logging has
// been configured, we ignore the callbacks for DEBUG/INFO explicitly here
// which means users don't see every possible log message if they're trying
// to configure the levels using --log-debug=sentry-sdk
- if (!TheDefaultLogger)
+ if (!zen::logging::IsLoggingInitialized() || !s_SentryLogEnabled.load(std::memory_order_acquire))
{
switch (Level)
{
@@ -231,11 +218,21 @@ SentryIntegration::SentryIntegration()
SentryIntegration::~SentryIntegration()
{
+ Close();
+}
+
+void
+SentryIntegration::Close()
+{
if (m_IsInitialized && m_SentryErrorCode == 0)
{
logging::SetErrorLog("");
m_SentryAssert.reset();
+ // Disable spdlog forwarding before sentry_close() since its background
+ // worker thread may still log during shutdown via SentryLogFunction
+ s_SentryLogEnabled.store(false, std::memory_order_release);
sentry_close();
+ m_IsInitialized = false;
}
}
@@ -251,6 +248,14 @@ SentryIntegration::Initialize(const Config& Conf, const std::string& CommandLine
}
sentry_options_t* SentryOptions = sentry_options_new();
+ if (SentryOptions == nullptr)
+ {
+ // OOM — skip sentry entirely rather than crashing on the subsequent set calls
+ m_SentryErrorCode = -1;
+ m_IsInitialized = true;
+ return;
+ }
+
sentry_options_set_dsn(SentryOptions, Conf.Dsn.empty() ? sentry::DefaultDsn.c_str() : Conf.Dsn.c_str());
sentry_options_set_database_path(SentryOptions, SentryDatabasePath.c_str());
sentry_options_set_logger(SentryOptions, SentryLogFunction, this);
@@ -335,7 +340,9 @@ SentryIntegration::Initialize(const Config& Conf, const std::string& CommandLine
sentry_set_user(SentryUserObject);
- m_SentryLogger = spdlog::create<sentry::sentry_sink>("sentry");
+ logging::SinkPtr SentrySink(new sentry::SentrySink());
+ m_SentryLogger = Ref<logging::Logger>(new logging::Logger("sentry", std::vector<logging::SinkPtr>{SentrySink}));
+ logging::Registry::Instance().Register(m_SentryLogger);
logging::SetErrorLog("sentry");
m_SentryAssert = std::make_unique<sentry::SentryAssertImpl>();
@@ -349,7 +356,7 @@ SentryIntegration::LogStartupInformation()
{
// Initialize the sentry-sdk log category at Warn level to reduce startup noise.
// The level can be overridden via --log-debug=sentry-sdk or --log-info=sentry-sdk
- LogSentry.Logger().SetLogLevel(logging::level::Warn);
+ LogSentry.Logger().SetLogLevel(logging::Warn);
if (m_IsInitialized)
{