From ce901d6bc66ad7dafdb3e4a33969aedd70a7f738 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 7 Jul 2026 14:53:08 +0200 Subject: [PATCH] feat(internal): add clean SDK integration points Add `sentry_integration_t` with `register`, `unregister`, and `free` functions, and `sentry__options_add_integration`. Finally, wire up the existing Qt integration through that path. --- CMakeLists.txt | 3 ++ src/CMakeLists.txt | 1 + src/integrations/sentry_integration_qt.cpp | 34 +++++++++++++-- src/integrations/sentry_integration_qt.h | 6 ++- src/sentry_core.c | 39 ++++++++++++++---- src/sentry_integration.h | 16 ++++++++ src/sentry_options.c | 48 ++++++++++++++++++++++ src/sentry_options.h | 12 ++++++ 8 files changed, 145 insertions(+), 14 deletions(-) create mode 100644 src/sentry_integration.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bacef22283..e085eecb62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -832,6 +832,8 @@ elseif(SENTRY_BACKEND_NATIVE) # Build sentry-crash executable for native backend # Get all sources that were added to sentry target get_target_property(SENTRY_SOURCES sentry SOURCES) + # Exclude integrations that are not needed in the daemon + list(FILTER SENTRY_SOURCES EXCLUDE REGEX "[/\\\\]integrations[/\\\\]") # Create daemon executable with same sources (already includes # sentry_crash_daemon.c and sentry_crash_ipc.c from src/CMakeLists.txt) @@ -846,6 +848,7 @@ elseif(SENTRY_BACKEND_NATIVE) if(SENTRY_COMPILE_DEFS) # The daemon is always a static executable, never a shared library list(REMOVE_ITEM SENTRY_COMPILE_DEFS "SENTRY_BUILD_SHARED") + list(FILTER SENTRY_COMPILE_DEFS EXCLUDE REGEX "^SENTRY_INTEGRATION_") target_compile_definitions(sentry-crash PRIVATE ${SENTRY_COMPILE_DEFS}) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 20a8036243..0a2f488397 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,7 @@ sentry_target_sources_cwd(sentry sentry_hint.c sentry_hint.h sentry_info.c + sentry_integration.h sentry_json.c sentry_json.h sentry_logger.c diff --git a/src/integrations/sentry_integration_qt.cpp b/src/integrations/sentry_integration_qt.cpp index c31c75bc44..0b0b1e3ebf 100644 --- a/src/integrations/sentry_integration_qt.cpp +++ b/src/integrations/sentry_integration_qt.cpp @@ -1,5 +1,9 @@ #include "sentry_integration_qt.h" -#include "sentry_boot.h" + +extern "C" { +#include "sentry_alloc.h" +#include "sentry_core.h" +} #include #include @@ -52,8 +56,32 @@ sentry_qt_messsage_handler( originalMessageHandler(type, context, message); } -void -sentry_integration_setup_qt(void) +static void +register_qt(void *UNUSED(data), sentry_scope_t *UNUSED(scope), + const sentry_options_t *UNUSED(options)) { + SENTRY_DEBUG("registering Qt integration"); originalMessageHandler = qInstallMessageHandler(sentry_qt_messsage_handler); } + +static void +unregister_qt(void *UNUSED(data), sentry_scope_t *UNUSED(scope), + const sentry_options_t *UNUSED(options)) +{ + qInstallMessageHandler(originalMessageHandler); + originalMessageHandler = nullptr; +} + +sentry_integration_t * +sentry_integration_qt_new(void) +{ + sentry_integration_t *integration = SENTRY_MAKE(sentry_integration_t); + if (!integration) { + return nullptr; + } + + integration->register_func = register_qt; + integration->unregister_func = unregister_qt; + + return integration; +} diff --git a/src/integrations/sentry_integration_qt.h b/src/integrations/sentry_integration_qt.h index 343abf3055..62c3a54efb 100644 --- a/src/integrations/sentry_integration_qt.h +++ b/src/integrations/sentry_integration_qt.h @@ -1,6 +1,8 @@ #ifndef SENTRY_INTEGRATION_QT_H_INCLUDED #define SENTRY_INTEGRATION_QT_H_INCLUDED +#include "sentry_integration.h" + #ifdef __cplusplus # define C_API extern "C" #else @@ -8,8 +10,8 @@ #endif /** - * This sets up the Qt integration. + * This creates the Qt integration. */ -C_API void sentry_integration_setup_qt(void); +C_API sentry_integration_t *sentry_integration_qt_new(void); #endif diff --git a/src/sentry_core.c b/src/sentry_core.c index 2dc25f3e8f..509066ea23 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -34,10 +34,6 @@ # include "sentry_screenshot.h" #endif -#ifdef SENTRY_INTEGRATION_QT -# include "integrations/sentry_integration_qt.h" -#endif - static sentry_options_t *g_options = NULL; #ifdef SENTRY__MUTEX_INIT_DYN SENTRY__MUTEX_INIT_DYN(g_options_lock) @@ -100,6 +96,28 @@ generate_propagation_context(sentry_value_t propagation_context) sentry_value_get_by_key(propagation_context, "trace")); } +static void +register_integrations(sentry_scope_t *scope, const sentry_options_t *options) +{ + for (size_t i = 0; i < options->num_integrations; i++) { + sentry_integration_t *integration = options->integrations[i]; + if (integration->register_func) { + integration->register_func(integration->data, scope, options); + } + } +} + +static void +unregister_integrations(sentry_scope_t *scope, const sentry_options_t *options) +{ + for (size_t i = 0; i < options->num_integrations; i++) { + sentry_integration_t *integration = options->integrations[i]; + if (integration->unregister_func) { + integration->unregister_func(integration->data, scope, options); + } + } +} + #if defined(SENTRY_PLATFORM_NX) || defined(SENTRY_PLATFORM_PS) \ || defined(SENTRY_PLATFORM_XBOX) int @@ -228,16 +246,13 @@ sentry_init(sentry_options_t *options) scope->breadcrumbs, options->max_breadcrumbs); sentry__scope_update_dsc(scope, options); + + register_integrations(scope, options); } if (backend && backend->user_consent_changed_func) { backend->user_consent_changed_func(backend); } -#ifdef SENTRY_INTEGRATION_QT - SENTRY_DEBUG("setting up Qt integration"); - sentry_integration_setup_qt(); -#endif - #if defined(SENTRY_PLATFORM_WINDOWS) \ && (!defined(SENTRY_BUILD_SHARED) || defined(SENTRY_PLATFORM_XBOX)) // This function must be positioned so that any dependents on its cached @@ -320,6 +335,12 @@ sentry_close(void) // flushed. This prevents a potential deadlock on the options during // envelope creation. SENTRY_WITH_OPTIONS (options) { + if (options->num_integrations) { + SENTRY_WITH_SCOPE_MUT_NO_FLUSH (scope) { + unregister_integrations(scope, options); + } + } + if (options->enable_logs) { sentry__logs_shutdown(options->shutdown_timeout); } diff --git a/src/sentry_integration.h b/src/sentry_integration.h new file mode 100644 index 0000000000..416974f93e --- /dev/null +++ b/src/sentry_integration.h @@ -0,0 +1,16 @@ +#ifndef SENTRY_INTEGRATION_H_INCLUDED +#define SENTRY_INTEGRATION_H_INCLUDED + +#include "sentry_boot.h" + +typedef struct sentry_integration_s { + void *data; + + void (*register_func)( + void *data, sentry_scope_t *scope, const sentry_options_t *options); + void (*unregister_func)( + void *data, sentry_scope_t *scope, const sentry_options_t *options); + void (*free_func)(void *data); +} sentry_integration_t; + +#endif diff --git a/src/sentry_options.c b/src/sentry_options.c index 01d1ab1f7b..f848a0487d 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -13,6 +13,10 @@ #include #include +#ifdef SENTRY_INTEGRATION_QT +# include "integrations/sentry_integration_qt.h" +#endif + static double normalize_sample_rate(double sample_rate, double default_value) { @@ -119,6 +123,9 @@ sentry_options_new(void) opts->http_retry = false; opts->send_client_reports = true; opts->enable_large_attachments = false; +#ifdef SENTRY_INTEGRATION_QT + sentry__options_add_integration(opts, sentry_integration_qt_new()); +#endif return opts; } @@ -132,6 +139,18 @@ sentry__options_incref(sentry_options_t *options) return options; } +static void +free_integration(sentry_integration_t *integration) +{ + if (!integration) { + return; + } + if (integration->free_func) { + integration->free_func(integration->data); + } + sentry_free(integration); +} + void sentry_options_free(sentry_options_t *opts) { @@ -155,6 +174,10 @@ sentry_options_free(sentry_options_t *opts) sentry__backend_free(opts->backend); sentry__attachments_free(opts->attachments); sentry__run_free(opts->run); + for (size_t i = 0; i < opts->num_integrations; i++) { + free_integration(opts->integrations[i]); + } + sentry_free(opts->integrations); sentry_free(opts); } @@ -930,6 +953,31 @@ sentry_options_set_backend(sentry_options_t *opts, sentry_backend_t *backend) opts->backend = backend; } +void +sentry__options_add_integration( + sentry_options_t *opts, sentry_integration_t *integration) +{ + if (!integration) { + return; + } + + size_t new_count = opts->num_integrations + 1; + sentry_integration_t **integrations + = sentry__calloc(new_count, sizeof(sentry_integration_t *)); + if (!integrations) { + free_integration(integration); + return; + } + + for (size_t i = 0; i < opts->num_integrations; i++) { + integrations[i] = opts->integrations[i]; + } + integrations[opts->num_integrations] = integration; + sentry_free(opts->integrations); + opts->integrations = integrations; + opts->num_integrations = new_count; +} + void sentry_options_set_enable_logs(sentry_options_t *opts, int enable_logs) { diff --git a/src/sentry_options.h b/src/sentry_options.h index 0947ef452a..ea357a8994 100644 --- a/src/sentry_options.h +++ b/src/sentry_options.h @@ -5,6 +5,7 @@ #include "sentry_attachment.h" #include "sentry_database.h" +#include "sentry_integration.h" #include "sentry_logger.h" #include "sentry_session.h" #include "sentry_utils.h" @@ -95,6 +96,8 @@ struct sentry_options_s { not exposed through the options API */ struct sentry_backend_s *backend; sentry_session_t *session; + sentry_integration_t **integrations; + size_t num_integrations; long refcount; uint64_t shutdown_timeout; @@ -124,4 +127,13 @@ sentry_options_t *sentry__options_incref(sentry_options_t *options); */ const char *sentry__options_get_org_id(const sentry_options_t *options); +/** + * Adds an integration to the options. + * + * Takes ownership of `integration`. If the integration owns `data`, it must + * provide `free_func`. + */ +void sentry__options_add_integration( + sentry_options_t *opts, sentry_integration_t *integration); + #endif