ClickHouse/base/daemon/SentryWriter.cpp

233 lines
8.2 KiB
C++
Raw Normal View History

#include <daemon/SentryWriter.h>
2020-05-29 19:48:32 +00:00
#include <Poco/Util/Application.h>
#include <Poco/Util/LayeredConfiguration.h>
2020-05-29 19:48:32 +00:00
2021-10-02 07:13:14 +00:00
#include <base/defines.h>
#include <base/getFQDNOrHostName.h>
#include <base/getMemoryAmount.h>
#include <base/logger_useful.h>
2021-04-09 00:28:24 +00:00
#include <Common/formatReadable.h>
2020-07-31 20:16:31 +00:00
#include <Common/SymbolIndex.h>
#include <Common/StackTrace.h>
#include <Common/getNumberOfPhysicalCPUCores.h>
2021-08-18 12:15:31 +00:00
#include <Core/ServerUUID.h>
2021-10-10 18:54:15 +00:00
#include <Common/hex.h>
#if !defined(ARCADIA_BUILD)
2020-05-29 21:36:47 +00:00
# include "Common/config_version.h"
# include <Common/config.h>
#endif
2020-05-27 20:15:33 +00:00
#if USE_SENTRY
2020-05-30 10:54:57 +00:00
# include <sentry.h> // Y_IGNORE
2020-06-11 18:12:48 +00:00
# include <stdio.h>
2020-06-16 12:56:28 +00:00
# include <filesystem>
2020-05-27 20:15:33 +00:00
2021-05-22 18:24:13 +00:00
namespace fs = std::filesystem;
2020-05-29 21:36:47 +00:00
namespace
{
2020-06-02 07:33:11 +00:00
2020-06-01 18:25:25 +00:00
bool initialized = false;
bool anonymize = false;
std::string server_data_path;
2020-05-27 20:15:33 +00:00
2020-05-29 21:36:47 +00:00
void setExtras()
{
2020-05-30 08:02:13 +00:00
if (!anonymize)
sentry_set_extra("server_name", sentry_value_new_string(getFQDNOrHostName().c_str()));
2021-08-17 13:24:14 +00:00
DB::UUID server_uuid = DB::ServerUUID::get();
2021-08-16 18:30:53 +00:00
if (server_uuid != DB::UUIDHelpers::Nil)
{
std::string server_uuid_str = DB::toString(server_uuid);
sentry_set_extra("server_uuid", sentry_value_new_string(server_uuid_str.c_str()));
}
2020-06-16 12:56:28 +00:00
sentry_set_tag("version", VERSION_STRING);
2020-05-29 21:36:47 +00:00
sentry_set_extra("version_githash", sentry_value_new_string(VERSION_GITHASH));
sentry_set_extra("version_describe", sentry_value_new_string(VERSION_DESCRIBE));
sentry_set_extra("version_integer", sentry_value_new_int32(VERSION_INTEGER));
sentry_set_extra("version_revision", sentry_value_new_int32(VERSION_REVISION));
sentry_set_extra("version_major", sentry_value_new_int32(VERSION_MAJOR));
sentry_set_extra("version_minor", sentry_value_new_int32(VERSION_MINOR));
sentry_set_extra("version_patch", sentry_value_new_int32(VERSION_PATCH));
sentry_set_extra("version_official", sentry_value_new_string(VERSION_OFFICIAL));
2020-11-29 08:34:42 +00:00
/// Sentry does not support 64-bit integers.
sentry_set_extra("total_ram", sentry_value_new_string(formatReadableSizeWithBinarySuffix(getMemoryAmountOrZero()).c_str()));
sentry_set_extra("physical_cpu_cores", sentry_value_new_int32(getNumberOfPhysicalCPUCores()));
if (!server_data_path.empty())
2021-05-22 18:24:13 +00:00
sentry_set_extra("disk_free_space", sentry_value_new_string(formatReadableSizeWithBinarySuffix(fs::space(server_data_path).free).c_str()));
2020-05-29 21:36:47 +00:00
}
2020-06-11 18:12:48 +00:00
}
2020-05-29 21:36:47 +00:00
void SentryWriter::initialize(Poco::Util::LayeredConfiguration & config)
{
2020-05-27 20:15:33 +00:00
bool enabled = false;
bool debug = config.getBool("send_crash_reports.debug", false);
2020-06-01 18:25:25 +00:00
auto * logger = &Poco::Logger::get("SentryWriter");
2021-10-10 01:10:52 +00:00
2020-05-27 20:15:33 +00:00
if (config.getBool("send_crash_reports.enabled", false))
{
2021-05-08 14:43:03 +00:00
if (debug || (strlen(VERSION_OFFICIAL) > 0)) //-V560
2020-05-27 20:15:33 +00:00
enabled = true;
}
2021-10-10 01:10:52 +00:00
2020-05-27 20:15:33 +00:00
if (enabled)
{
server_data_path = config.getString("path", "");
2021-05-22 18:24:13 +00:00
const std::filesystem::path & default_tmp_path = fs::path(config.getString("tmp_path", fs::temp_directory_path())) / "sentry";
2020-05-29 21:36:47 +00:00
const std::string & endpoint
2020-06-16 20:01:15 +00:00
= config.getString("send_crash_reports.endpoint");
2020-05-29 21:36:47 +00:00
const std::string & temp_folder_path
2020-06-16 12:56:28 +00:00
= config.getString("send_crash_reports.tmp_path", default_tmp_path);
2021-05-22 18:24:13 +00:00
fs::create_directories(temp_folder_path);
2020-05-29 19:48:32 +00:00
2020-06-16 12:56:28 +00:00
sentry_options_t * options = sentry_options_new(); /// will be freed by sentry_init or sentry_shutdown
sentry_options_set_release(options, VERSION_STRING_SHORT);
if (debug)
{
sentry_options_set_debug(options, 1);
}
2020-05-27 20:15:33 +00:00
sentry_options_set_dsn(options, endpoint.c_str());
2020-05-29 19:48:32 +00:00
sentry_options_set_database_path(options, temp_folder_path.c_str());
2020-05-29 21:36:47 +00:00
if (strstr(VERSION_DESCRIBE, "-stable") || strstr(VERSION_DESCRIBE, "-lts"))
{
2020-05-27 20:15:33 +00:00
sentry_options_set_environment(options, "prod");
2020-05-29 21:36:47 +00:00
}
else
{
2020-05-27 20:15:33 +00:00
sentry_options_set_environment(options, "test");
}
2020-05-30 08:02:13 +00:00
2020-05-30 08:24:21 +00:00
const std::string & http_proxy = config.getString("send_crash_reports.http_proxy", "");
if (!http_proxy.empty())
{
sentry_options_set_http_proxy(options, http_proxy.c_str());
}
2020-05-29 19:48:32 +00:00
int init_status = sentry_init(options);
if (!init_status)
{
initialized = true;
2020-05-30 08:02:13 +00:00
anonymize = config.getBool("send_crash_reports.anonymize", false);
2020-05-29 19:48:32 +00:00
LOG_INFO(
2020-06-01 14:15:14 +00:00
logger,
2020-05-30 08:02:13 +00:00
"Sending crash reports is initialized with {} endpoint and {} temp folder{}",
2020-05-29 19:48:32 +00:00
endpoint,
2020-05-30 08:02:13 +00:00
temp_folder_path,
2020-06-16 12:56:28 +00:00
anonymize ? " (anonymized)" : "");
2020-05-29 19:48:32 +00:00
}
else
{
2020-06-16 12:56:28 +00:00
LOG_WARNING(logger, "Sending crash reports failed to initialize with {} status", init_status);
2020-05-29 19:48:32 +00:00
}
}
else
{
2020-06-01 14:15:14 +00:00
LOG_INFO(logger, "Sending crash reports is disabled");
2020-05-27 20:15:33 +00:00
}
}
2020-05-29 21:36:47 +00:00
void SentryWriter::shutdown()
{
if (initialized)
2020-05-27 20:15:33 +00:00
sentry_shutdown();
}
2020-07-31 20:16:31 +00:00
void SentryWriter::onFault(int sig, const std::string & error_message, const StackTrace & stack_trace)
{
2020-06-01 18:25:25 +00:00
auto * logger = &Poco::Logger::get("SentryWriter");
2020-05-27 20:15:33 +00:00
if (initialized)
{
2020-05-27 20:15:33 +00:00
sentry_value_t event = sentry_value_new_message_event(SENTRY_LEVEL_FATAL, "fault", error_message.c_str());
sentry_set_tag("signal", strsignal(sig));
sentry_set_extra("signal_number", sentry_value_new_int32(sig));
2020-07-31 20:16:31 +00:00
#if defined(__ELF__) && !defined(__FreeBSD__)
2020-11-30 14:30:55 +00:00
const String & build_id_hex = DB::SymbolIndex::instance()->getBuildIDHex();
sentry_set_tag("build_id", build_id_hex.c_str());
2020-07-31 20:16:31 +00:00
#endif
2020-05-27 20:15:33 +00:00
setExtras();
/// Prepare data for https://develop.sentry.dev/sdk/event-payloads/stacktrace/
2020-06-10 16:48:08 +00:00
sentry_value_t sentry_frames = sentry_value_new_list();
2020-05-27 20:15:33 +00:00
size_t stack_size = stack_trace.getSize();
if (stack_size > 0)
{
2020-06-16 12:56:28 +00:00
ssize_t offset = stack_trace.getOffset();
2021-10-10 18:54:15 +00:00
char instruction_addr[19]
{
'0', 'x',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
'\0'
};
2020-06-10 14:51:25 +00:00
StackTrace::Frames frames;
2020-06-23 21:15:54 +00:00
StackTrace::symbolize(stack_trace.getFramePointers(), offset, stack_size, frames);
2021-10-10 18:54:15 +00:00
2020-06-16 12:56:28 +00:00
for (ssize_t i = stack_size - 1; i >= offset; --i)
{
2020-06-10 14:51:25 +00:00
const StackTrace::Frame & current_frame = frames[i];
2020-06-10 16:48:08 +00:00
sentry_value_t sentry_frame = sentry_value_new_object();
2020-06-01 20:48:42 +00:00
UInt64 frame_ptr = reinterpret_cast<UInt64>(current_frame.virtual_addr);
2020-06-16 12:56:28 +00:00
2021-10-10 18:54:15 +00:00
writeHexUIntLowercase(frame_ptr, instruction_addr + 2);
sentry_value_set_by_key(sentry_frame, "instruction_addr", sentry_value_new_string(instruction_addr));
2020-05-27 20:15:33 +00:00
if (current_frame.symbol.has_value())
2020-06-10 16:48:08 +00:00
sentry_value_set_by_key(sentry_frame, "function", sentry_value_new_string(current_frame.symbol.value().c_str()));
2020-05-27 20:15:33 +00:00
if (current_frame.file.has_value())
2020-06-10 16:48:08 +00:00
sentry_value_set_by_key(sentry_frame, "filename", sentry_value_new_string(current_frame.file.value().c_str()));
2020-05-27 20:15:33 +00:00
if (current_frame.line.has_value())
2020-06-10 16:48:08 +00:00
sentry_value_set_by_key(sentry_frame, "lineno", sentry_value_new_int32(current_frame.line.value()));
2020-05-27 20:15:33 +00:00
2020-06-10 16:48:08 +00:00
sentry_value_append(sentry_frames, sentry_frame);
}
}
2020-05-27 20:15:33 +00:00
/// Prepare data for https://develop.sentry.dev/sdk/event-payloads/threads/
2020-06-16 12:56:28 +00:00
/// Stacktrace is filled only for a single thread that failed
2020-05-27 20:15:33 +00:00
sentry_value_t stacktrace = sentry_value_new_object();
2020-06-10 16:48:08 +00:00
sentry_value_set_by_key(stacktrace, "frames", sentry_frames);
2020-05-27 20:15:33 +00:00
sentry_value_t thread = sentry_value_new_object();
sentry_value_set_by_key(thread, "stacktrace", stacktrace);
2020-05-27 20:15:33 +00:00
sentry_value_t values = sentry_value_new_list();
sentry_value_append(values, thread);
2020-05-27 20:15:33 +00:00
sentry_value_t threads = sentry_value_new_object();
sentry_value_set_by_key(threads, "values", values);
2020-05-27 20:15:33 +00:00
sentry_value_set_by_key(event, "threads", threads);
2020-06-01 14:15:14 +00:00
LOG_INFO(logger, "Sending crash report");
2020-05-27 20:15:33 +00:00
sentry_capture_event(event);
shutdown();
}
2020-05-29 19:48:32 +00:00
else
{
2020-06-01 14:15:14 +00:00
LOG_INFO(logger, "Not sending crash report");
2020-05-29 19:48:32 +00:00
}
}
2020-06-02 05:29:13 +00:00
#else
void SentryWriter::initialize(Poco::Util::LayeredConfiguration &) {}
void SentryWriter::shutdown() {}
2020-07-31 20:16:31 +00:00
void SentryWriter::onFault(int, const std::string &, const StackTrace &) {}
2020-05-27 20:15:33 +00:00
#endif