Send LOGICAL_ERRORs to sentry

This is like an assert() in the code, so it is useful to know about them
as well.

Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
This commit is contained in:
Azat Khuzhin 2024-03-27 15:07:40 +01:00
parent 53cef82acd
commit f4ad005249
4 changed files with 37 additions and 16 deletions

View File

@ -5,6 +5,7 @@
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
#include <base/demangle.h> #include <base/demangle.h>
#include <Common/AtomicLogger.h> #include <Common/AtomicLogger.h>
#include <Daemon/SentryWriter.h>
#include <Common/ErrorCodes.h> #include <Common/ErrorCodes.h>
#include <Common/Exception.h> #include <Common/Exception.h>
#include <Common/LockMemoryExceptionInThread.h> #include <Common/LockMemoryExceptionInThread.h>
@ -52,14 +53,20 @@ thread_local bool update_error_statistics = true;
/// - Increments error codes statistics. /// - Increments error codes statistics.
void handle_error_code([[maybe_unused]] const std::string & msg, int code, bool remote, const Exception::FramePointers & trace) void handle_error_code([[maybe_unused]] const std::string & msg, int code, bool remote, const Exception::FramePointers & trace)
{ {
if (code == ErrorCodes::LOGICAL_ERROR)
{
// In debug builds and builds with sanitizers, treat LOGICAL_ERROR as an assertion failure. // In debug builds and builds with sanitizers, treat LOGICAL_ERROR as an assertion failure.
// Log the message before we fail. // Log the message before we fail.
#ifdef ABORT_ON_LOGICAL_ERROR #ifdef ABORT_ON_LOGICAL_ERROR
if (code == ErrorCodes::LOGICAL_ERROR)
{
abortOnFailedAssertion(msg); abortOnFailedAssertion(msg);
} #else
/// In release builds send it to sentry (if it is configured)
SentryWriter::FramePointers frame_pointers;
for (size_t i = 0; i < trace.size(); ++i)
frame_pointers[i] = trace[i];
SentryWriter::onFault(-code, msg, frame_pointers, /* offset= */ 0, trace.size());
#endif #endif
}
if (!update_error_statistics) [[unlikely]] if (!update_error_statistics) [[unlikely]]
return; return;

View File

@ -497,7 +497,7 @@ private:
/// Send crash report to developers (if configured) /// Send crash report to developers (if configured)
if (sig != SanitizerTrap) if (sig != SanitizerTrap)
{ {
SentryWriter::onFault(sig, error_message, stack_trace); SentryWriter::onFault(sig, error_message, stack_trace.getFramePointers(), stack_trace.getOffset(), stack_trace.getSize());
/// Advice the user to send it manually. /// Advice the user to send it manually.
if (std::string_view(VERSION_OFFICIAL).contains("official build")) if (std::string_view(VERSION_OFFICIAL).contains("official build"))

View File

@ -139,14 +139,25 @@ void SentryWriter::shutdown()
sentry_shutdown(); sentry_shutdown();
} }
void SentryWriter::onFault(int sig, const std::string & error_message, const StackTrace & stack_trace) void SentryWriter::onFault(int sig_or_error, const std::string & error_message, const FramePointers & frame_pointers, size_t offset, size_t size)
{ {
auto logger = getLogger("SentryWriter"); auto logger = getLogger("SentryWriter");
if (initialized) if (initialized)
{ {
sentry_value_t event = sentry_value_new_message_event(SENTRY_LEVEL_FATAL, "fault", error_message.c_str()); sentry_value_t event = sentry_value_new_message_event(SENTRY_LEVEL_FATAL, "fault", error_message.c_str());
if (sig_or_error > 0)
{
int sig = sig_or_error;
sentry_set_tag("signal", strsignal(sig)); // NOLINT(concurrency-mt-unsafe) // not thread-safe but ok in this context sentry_set_tag("signal", strsignal(sig)); // NOLINT(concurrency-mt-unsafe) // not thread-safe but ok in this context
sentry_set_extra("signal_number", sentry_value_new_int32(sig)); sentry_set_extra("signal_number", sentry_value_new_int32(sig));
}
else
{
/// Can be only LOGICAL_ERROR, but just in case.
int code = -sig_or_error;
sentry_set_tag("exception", DB::ErrorCodes::getName(code).data());
sentry_set_extra("exception_code", sentry_value_new_int32(code));
}
#if defined(__ELF__) && !defined(OS_FREEBSD) #if defined(__ELF__) && !defined(OS_FREEBSD)
const String & build_id_hex = DB::SymbolIndex::instance().getBuildIDHex(); const String & build_id_hex = DB::SymbolIndex::instance().getBuildIDHex();
@ -157,11 +168,8 @@ void SentryWriter::onFault(int sig, const std::string & error_message, const Sta
/// Prepare data for https://develop.sentry.dev/sdk/event-payloads/stacktrace/ /// Prepare data for https://develop.sentry.dev/sdk/event-payloads/stacktrace/
sentry_value_t sentry_frames = sentry_value_new_list(); sentry_value_t sentry_frames = sentry_value_new_list();
size_t stack_size = stack_trace.getSize(); if (size > 0)
if (stack_size > 0)
{ {
ssize_t offset = stack_trace.getOffset();
char instruction_addr[19] char instruction_addr[19]
{ {
'0', 'x', '0', 'x',
@ -191,7 +199,7 @@ void SentryWriter::onFault(int sig, const std::string & error_message, const Sta
sentry_value_append(sentry_frames, sentry_frame); sentry_value_append(sentry_frames, sentry_frame);
}; };
StackTrace::forEachFrame(stack_trace.getFramePointers(), offset, stack_size, sentry_add_stack_trace, /* fatal= */ true); StackTrace::forEachFrame(frame_pointers, offset, size, sentry_add_stack_trace, /* fatal= */ true);
} }
/// Prepare data for https://develop.sentry.dev/sdk/event-payloads/threads/ /// Prepare data for https://develop.sentry.dev/sdk/event-payloads/threads/
@ -212,7 +220,7 @@ void SentryWriter::onFault(int sig, const std::string & error_message, const Sta
LOG_INFO(logger, "Sending crash report"); LOG_INFO(logger, "Sending crash report");
sentry_capture_event(event); sentry_capture_event(event);
shutdown(); /* shutdown(); */
} }
else else
{ {

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <Common/StackTrace.h>
namespace Poco { namespace Util { class LayeredConfiguration; }} namespace Poco { namespace Util { class LayeredConfiguration; }}
@ -19,9 +20,14 @@ namespace SentryWriter
void initialize(Poco::Util::LayeredConfiguration & config); void initialize(Poco::Util::LayeredConfiguration & config);
void shutdown(); void shutdown();
using FramePointers = StackTrace::FramePointers;
/// Not signal safe and can't be called from a signal handler /// Not signal safe and can't be called from a signal handler
/// @param sig_or_error - signal if >= 0, otherwise exception code
void onFault( void onFault(
int sig, int sig_or_error,
const std::string & error_message, const std::string & error_message,
const StackTrace & stack_trace); const FramePointers & frame_pointers,
size_t offset,
size_t size);
} }