diff --git a/src/Common/Exception.cpp b/src/Common/Exception.cpp index f0557f43c12..5d936bbb88c 100644 --- a/src/Common/Exception.cpp +++ b/src/Common/Exception.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -48,28 +47,23 @@ void abortOnFailedAssertion(const String & description) bool terminate_on_any_exception = false; static int terminate_status_code = 128 + SIGABRT; thread_local bool update_error_statistics = true; +std::function Exception::callback = {}; /// - Aborts the process if error code is LOGICAL_ERROR. /// - 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(const std::string & msg, int code, bool remote, const Exception::FramePointers & trace) { + // In debug builds and builds with sanitizers, treat LOGICAL_ERROR as an assertion failure. + // Log the message before we fail. +#ifdef ABORT_ON_LOGICAL_ERROR if (code == ErrorCodes::LOGICAL_ERROR) { - // In debug builds and builds with sanitizers, treat LOGICAL_ERROR as an assertion failure. - // Log the message before we fail. -#ifdef ABORT_ON_LOGICAL_ERROR abortOnFailedAssertion(msg); -#else - /// In release builds send it to sentry (if it is configured) - if (auto * sentry = SentryWriter::getInstance()) - { - SentryWriter::FramePointers frame_pointers; - for (size_t i = 0; i < trace.size(); ++i) - frame_pointers[i] = trace[i]; - sentry->onFault(-code, msg, frame_pointers, /* offset= */ 0, trace.size()); - } -#endif } +#endif + + if (Exception::callback) + Exception::callback(msg, code, remote, trace); if (!update_error_statistics) [[unlikely]] return; diff --git a/src/Common/Exception.h b/src/Common/Exception.h index 97af8d1ffc3..1b4dabec113 100644 --- a/src/Common/Exception.h +++ b/src/Common/Exception.h @@ -72,6 +72,8 @@ public: /// Collect call stacks of all previous jobs' schedulings leading to this thread job's execution static thread_local bool enable_job_stack_trace; static thread_local std::vector thread_frame_pointers; + /// Callback for any exception + static std::function callback; protected: // used to remove the sensitive information from exceptions if query_masking_rules is configured diff --git a/src/Daemon/BaseDaemon.cpp b/src/Daemon/BaseDaemon.cpp index 14e45c8e25f..01a49df2e82 100644 --- a/src/Daemon/BaseDaemon.cpp +++ b/src/Daemon/BaseDaemon.cpp @@ -80,6 +80,7 @@ namespace DB extern const int CANNOT_SET_SIGNAL_HANDLER; extern const int CANNOT_SEND_SIGNAL; extern const int SYSTEM_ERROR; + extern const int LOGICAL_ERROR; } } @@ -1016,6 +1017,20 @@ extern const char * GIT_HASH; void BaseDaemon::initializeTerminationAndSignalProcessing() { SentryWriter::initializeInstance(config()); + /// In release builds send it to sentry (if it is configured) + if (auto * sentry = SentryWriter::getInstance()) + { + Exception::callback = [sentry](const std::string & msg, int code, bool remote, const Exception::FramePointers & trace) + { + if (!remote && code == ErrorCodes::LOGICAL_ERROR) + { + SentryWriter::FramePointers frame_pointers; + for (size_t i = 0; i < trace.size(); ++i) + frame_pointers[i] = trace[i]; + sentry->onFault(-code, msg, frame_pointers, /* offset= */ 0, trace.size()); + } + }; + } std::set_terminate(terminate_handler); /// We want to avoid SIGPIPE when working with sockets and pipes, and just handle return value/errno instead.