From 469420402e4717906783a744f8e2fb156168ec25 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 21 Feb 2023 10:54:43 +0100 Subject: [PATCH] feat: Send SDK Integration List, add missing packages (#2179) Co-authored-by: Roman Zavarnitsyn Co-authored-by: Sentry Github Bot Co-authored-by: Lukas Bloder Co-authored-by: Alexander Dinauer Co-authored-by: Alexander Dinauer --- CHANGELOG.md | 1 + buildSrc/src/main/java/Config.kt | 8 ++ .../core/ActivityLifecycleIntegration.java | 1 + .../sentry/android/core/AnrIntegration.java | 1 + .../AppComponentsBreadcrumbsIntegration.java | 1 + .../android/core/AppLifecycleIntegration.java | 1 + .../sentry/android/core/NdkIntegration.java | 1 + .../PhoneStateBreadcrumbsIntegration.java | 1 + .../core/SendCachedEnvelopeIntegration.java | 1 - .../SystemEventsBreadcrumbsIntegration.java | 1 + .../TempSensorBreadcrumbsIntegration.java | 1 + .../core/UserInteractionIntegration.java | 1 + .../android/core/SentryAndroidOptionsTest.kt | 4 +- .../fragment/FragmentLifecycleIntegration.kt | 4 + .../api/sentry-android-navigation.api | 2 +- .../navigation/SentryNavigationListener.kt | 10 ++- .../sentry/android/ndk/SentryNdkUtilTest.kt | 4 +- .../api/sentry-android-okhttp.api | 2 +- .../android/okhttp/SentryOkHttpInterceptor.kt | 10 ++- .../android/timber/SentryTimberIntegration.kt | 5 +- .../timber/SentryTimberIntegrationTest.kt | 14 +++- sentry-apollo-3/api/sentry-apollo-3.api | 8 +- sentry-apollo-3/build.gradle.kts | 7 ++ .../apollo3/SentryApollo3HttpInterceptor.kt | 13 +++- .../apollo3/SentryApollo3InterceptorTest.kt | 27 +++++-- sentry-apollo/api/sentry-apollo.api | 7 +- sentry-apollo/build.gradle.kts | 7 ++ .../sentry/apollo/SentryApolloInterceptor.kt | 9 ++- .../apollo/SentryApolloInterceptorTest.kt | 25 +++++-- .../api/sentry-compose-helper.api | 7 ++ sentry-compose-helper/build.gradle.kts | 10 +++ .../gestures/ComposeGestureTargetLocator.java | 8 ++ .../compose/SentryNavigationIntegration.kt | 13 +++- sentry-graphql/api/sentry-graphql.api | 5 ++ sentry-graphql/build.gradle.kts | 8 ++ .../sentry/graphql/SentryInstrumentation.java | 4 + .../graphql/SentryInstrumentationTest.kt | 10 +++ sentry-jdbc/api/sentry-jdbc.api | 5 ++ sentry-jdbc/build.gradle.kts | 8 ++ .../sentry/jdbc/SentryJdbcEventListener.java | 8 ++ .../jdbc/SentryJdbcEventListenerTest.kt | 21 +++++- .../java/io/sentry/jul/SentryHandler.java | 9 ++- .../kotlin/io/sentry/jul/SentryHandlerTest.kt | 6 +- .../java/io/sentry/log4j2/SentryAppender.java | 10 ++- .../io/sentry/log4j2/SentryAppenderTest.kt | 4 +- .../io/sentry/logback/SentryAppender.java | 10 ++- .../io/sentry/logback/SentryAppenderTest.kt | 4 +- ...ryAutoConfigurationCustomizerProvider.java | 62 ++++++++++++--- .../api/sentry-servlet-jakarta.api | 5 ++ sentry-servlet-jakarta/build.gradle.kts | 8 ++ .../SentryServletContainerInitializer.java | 4 + sentry-servlet/api/sentry-servlet.api | 5 ++ sentry-servlet/build.gradle.kts | 8 ++ .../SentryServletContainerInitializer.java | 4 + .../build.gradle.kts | 2 +- .../boot/jakarta/SentryAutoConfiguration.java | 13 +++- .../jakarta/SentryAutoConfigurationTest.kt | 10 ++- .../spring/boot/SentryAutoConfiguration.java | 10 ++- .../boot/SentryAutoConfigurationTest.kt | 5 +- sentry-spring-jakarta/build.gradle.kts | 2 +- .../spring/jakarta/SentryHubRegistrar.java | 13 +++- .../sentry/spring/jakarta/EnableSentryTest.kt | 10 ++- .../io/sentry/spring/SentryHubRegistrar.java | 10 ++- .../io/sentry/spring/EnableSentryTest.kt | 4 +- sentry/api/sentry.api | 20 ++++- .../src/main/java/io/sentry/Integration.java | 2 +- .../main/java/io/sentry/IntegrationName.java | 15 ++++ ...achedEnvelopeFireAndForgetIntegration.java | 3 +- .../SentryIntegrationPackageStorage.java | 75 +++++++++++++++++++ .../main/java/io/sentry/SentryOptions.java | 7 +- .../io/sentry/ShutdownHookIntegration.java | 1 + .../UncaughtExceptionHandlerIntegration.java | 1 + .../file/FileIOSpanManager.java | 2 + .../java/io/sentry/protocol/SdkVersion.java | 72 ++++++++++++------ .../io/sentry/protocol/SentryPackage.java | 14 ++++ .../test/java/io/sentry/JsonSerializerTest.kt | 15 +--- ...hedEnvelopeFireAndForgetIntegrationTest.kt | 24 +++++- .../test/java/io/sentry/SentryOptionsTest.kt | 2 +- .../io/sentry/ShutdownHookIntegrationTest.kt | 12 +++ .../protocol/SdkVersionSerializationTest.kt | 21 ++++++ .../resources/envelope_session_sdkversion.txt | 2 +- 81 files changed, 667 insertions(+), 123 deletions(-) create mode 100644 sentry/src/main/java/io/sentry/IntegrationName.java create mode 100644 sentry/src/main/java/io/sentry/SentryIntegrationPackageStorage.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f88b508ebb..16c77066dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - If set to `true`, performance is enabled, even if no `tracesSampleRate` or `tracesSampler` have been configured. - If set to `false` performance is disabled, regardless of `tracesSampleRate` and `tracesSampler` options. - Detect dependencies by listing MANIFEST.MF files at runtime ([#2538](https://github.com/getsentry/sentry-java/pull/2538)) +- Report integrations in use, report packages in use more consistently ([#2179](https://github.com/getsentry/sentry-java/pull/2179)) ### Fixes diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 47d80f0d93..87abd3987e 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -210,9 +210,17 @@ object Config { val SENTRY_JUL_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.jul" val SENTRY_LOG4J2_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.log4j2" val SENTRY_SPRING_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring" + val SENTRY_SPRING_JAKARTA_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring.jakarta" val SENTRY_SPRING_BOOT_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot" val SENTRY_SPRING_BOOT_JAKARTA_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot.jakarta" val SENTRY_OPENTELEMETRY_AGENT_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.opentelemetry.agent" + val SENTRY_APOLLO3_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.apollo3" + val SENTRY_APOLLO_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.apollo" + val SENTRY_GRAPHQL_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.graphql" + val SENTRY_JDBC_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.jdbc" + val SENTRY_SERVLET_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.servlet" + val SENTRY_SERVLET_JAKARTA_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.servlet.jakarta" + val SENTRY_COMPOSE_HELPER_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.compose.helper" val group = "io.sentry" val description = "SDK for sentry.io" val versionNameProp = "versionName" diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java index 87dd24abfb..2d84617138 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java @@ -121,6 +121,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio if (this.options.isEnableActivityLifecycleBreadcrumbs() || performanceEnabled) { application.registerActivityLifecycleCallbacks(this); this.options.getLogger().log(SentryLevel.DEBUG, "ActivityLifecycleIntegration installed."); + addIntegrationToSdkVersion(); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java index 0c28124a36..b39e2a6c88 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java @@ -73,6 +73,7 @@ private void register(final @NotNull IHub hub, final @NotNull SentryAndroidOptio anrWatchDog.start(); options.getLogger().log(SentryLevel.DEBUG, "AnrIntegration installed."); + addIntegrationToSdkVersion(); } } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java index 088bf1505a..c9a552a5b7 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java @@ -53,6 +53,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio options .getLogger() .log(SentryLevel.DEBUG, "AppComponentsBreadcrumbsIntegration installed."); + addIntegrationToSdkVersion(); } catch (Throwable e) { this.options.setEnableAppComponentBreadcrumbs(false); options.getLogger().log(SentryLevel.INFO, e, "ComponentCallbacks2 is not available."); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java index 28aad388f4..401d2afb22 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java @@ -94,6 +94,7 @@ private void addObserver(final @NotNull IHub hub) { try { ProcessLifecycleOwner.get().getLifecycle().addObserver(watcher); options.getLogger().log(SentryLevel.DEBUG, "AppLifecycleIntegration installed."); + addIntegrationToSdkVersion(); } catch (Throwable e) { // This is to handle a potential 'AbstractMethodError' gracefully. The error is triggered in // connection with conflicting dependencies of the androidx.lifecycle. diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/NdkIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/NdkIntegration.java index 929d2dacb3..4757c96879 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/NdkIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/NdkIntegration.java @@ -53,6 +53,7 @@ public final void register(final @NotNull IHub hub, final @NotNull SentryOptions method.invoke(null, args); this.options.getLogger().log(SentryLevel.DEBUG, "NdkIntegration installed."); + addIntegrationToSdkVersion(); } catch (NoSuchMethodException e) { disableNdkIntegration(this.options); this.options diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegration.java index 52f721407a..be23c668c7 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/PhoneStateBreadcrumbsIntegration.java @@ -53,6 +53,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio telephonyManager.listen(listener, android.telephony.PhoneStateListener.LISTEN_CALL_STATE); options.getLogger().log(SentryLevel.DEBUG, "PhoneStateBreadcrumbsIntegration installed."); + addIntegrationToSdkVersion(); } catch (Throwable e) { this.options .getLogger() diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java index 61ec47618d..4f15090796 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java @@ -73,7 +73,6 @@ public void register(@NotNull IHub hub, @NotNull SentryOptions options) { .log(SentryLevel.DEBUG, "Synchronous send timed out, continuing in the background."); } } - androidOptions.getLogger().log(SentryLevel.DEBUG, "SendCachedEnvelopeIntegration installed."); } catch (Throwable e) { androidOptions diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java index 18cf714129..26f8e2bfb5 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java @@ -103,6 +103,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio this.options .getLogger() .log(SentryLevel.DEBUG, "SystemEventsBreadcrumbsIntegration installed."); + addIntegrationToSdkVersion(); } catch (Throwable e) { this.options.setEnableSystemEventBreadcrumbs(false); this.options diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/TempSensorBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/TempSensorBreadcrumbsIntegration.java index 49014c1fec..e4577b43ec 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/TempSensorBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/TempSensorBreadcrumbsIntegration.java @@ -62,6 +62,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio options .getLogger() .log(SentryLevel.DEBUG, "TempSensorBreadcrumbsIntegration installed."); + addIntegrationToSdkVersion(); } else { this.options .getLogger() diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/UserInteractionIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/UserInteractionIntegration.java index b23d6fcbb2..dda5627272 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/UserInteractionIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/UserInteractionIntegration.java @@ -119,6 +119,7 @@ public void register(@NotNull IHub hub, @NotNull SentryOptions options) { if (isAndroidXAvailable) { application.registerActivityLifecycleCallbacks(this); this.options.getLogger().log(SentryLevel.DEBUG, "UserInteractionIntegration installed."); + addIntegrationToSdkVersion(); } else { options .getLogger() diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt index f5068c7762..5cee3e792d 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt @@ -33,14 +33,14 @@ class SentryAndroidOptionsTest { assertEquals(BuildConfig.VERSION_NAME, sdkVersion.version) assertTrue( - sdkVersion.packages!!.any { + sdkVersion.packageSet.any { it.name == "maven:io.sentry:sentry-android-core" && it.version == BuildConfig.VERSION_NAME } ) assertTrue( - sdkVersion.packages!!.any { + sdkVersion.packageSet.any { it.name == "maven:io.sentry:sentry" && it.version == BuildConfig.VERSION_NAME } diff --git a/sentry-android-fragment/src/main/java/io/sentry/android/fragment/FragmentLifecycleIntegration.kt b/sentry-android-fragment/src/main/java/io/sentry/android/fragment/FragmentLifecycleIntegration.kt index 521292f8a8..81f0e7e505 100644 --- a/sentry-android-fragment/src/main/java/io/sentry/android/fragment/FragmentLifecycleIntegration.kt +++ b/sentry-android-fragment/src/main/java/io/sentry/android/fragment/FragmentLifecycleIntegration.kt @@ -7,6 +7,7 @@ import android.os.Bundle import androidx.fragment.app.FragmentActivity import io.sentry.IHub import io.sentry.Integration +import io.sentry.SentryIntegrationPackageStorage import io.sentry.SentryLevel.DEBUG import io.sentry.SentryOptions import java.io.Closeable @@ -47,6 +48,9 @@ class FragmentLifecycleIntegration( application.registerActivityLifecycleCallbacks(this) options.logger.log(DEBUG, "FragmentLifecycleIntegration installed.") + addIntegrationToSdkVersion() + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-android-fragment", BuildConfig.VERSION_NAME) } override fun close() { diff --git a/sentry-android-navigation/api/sentry-android-navigation.api b/sentry-android-navigation/api/sentry-android-navigation.api index 1ae144d5dd..d97de32cd6 100644 --- a/sentry-android-navigation/api/sentry-android-navigation.api +++ b/sentry-android-navigation/api/sentry-android-navigation.api @@ -6,7 +6,7 @@ public final class io/sentry/android/navigation/BuildConfig { public fun ()V } -public final class io/sentry/android/navigation/SentryNavigationListener : androidx/navigation/NavController$OnDestinationChangedListener { +public final class io/sentry/android/navigation/SentryNavigationListener : androidx/navigation/NavController$OnDestinationChangedListener, io/sentry/IntegrationName { public static final field Companion Lio/sentry/android/navigation/SentryNavigationListener$Companion; public static final field NAVIGATION_OP Ljava/lang/String; public fun ()V diff --git a/sentry-android-navigation/src/main/java/io/sentry/android/navigation/SentryNavigationListener.kt b/sentry-android-navigation/src/main/java/io/sentry/android/navigation/SentryNavigationListener.kt index 182d272df5..9661ee1925 100644 --- a/sentry-android-navigation/src/main/java/io/sentry/android/navigation/SentryNavigationListener.kt +++ b/sentry-android-navigation/src/main/java/io/sentry/android/navigation/SentryNavigationListener.kt @@ -9,6 +9,8 @@ import io.sentry.Hint import io.sentry.HubAdapter import io.sentry.IHub import io.sentry.ITransaction +import io.sentry.IntegrationName +import io.sentry.SentryIntegrationPackageStorage import io.sentry.SentryLevel.DEBUG import io.sentry.SentryLevel.INFO import io.sentry.SentryOptions @@ -32,7 +34,7 @@ class SentryNavigationListener @JvmOverloads constructor( private val hub: IHub = HubAdapter.getInstance(), private val enableNavigationBreadcrumbs: Boolean = true, private val enableNavigationTracing: Boolean = true -) : NavController.OnDestinationChangedListener { +) : NavController.OnDestinationChangedListener, IntegrationName { private var previousDestinationRef: WeakReference? = null private var previousArgs: Bundle? = null @@ -41,6 +43,12 @@ class SentryNavigationListener @JvmOverloads constructor( private var activeTransaction: ITransaction? = null + init { + addIntegrationToSdkVersion() + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-android-navigation", BuildConfig.VERSION_NAME) + } + override fun onDestinationChanged( controller: NavController, destination: NavDestination, diff --git a/sentry-android-ndk/src/test/java/io/sentry/android/ndk/SentryNdkUtilTest.kt b/sentry-android-ndk/src/test/java/io/sentry/android/ndk/SentryNdkUtilTest.kt index b93fd932fd..5456653bf1 100644 --- a/sentry-android-ndk/src/test/java/io/sentry/android/ndk/SentryNdkUtilTest.kt +++ b/sentry-android-ndk/src/test/java/io/sentry/android/ndk/SentryNdkUtilTest.kt @@ -12,7 +12,7 @@ class SentryNdkUtilTest { val options = SentryOptions() SentryNdkUtil.addPackage(options.sdkVersion) assertTrue( - options.sdkVersion!!.packages!!.any { + options.sdkVersion!!.packageSet.any { it.name == "maven:io.sentry:sentry-android-ndk" it.version == BuildConfig.VERSION_NAME } @@ -26,6 +26,6 @@ class SentryNdkUtilTest { } SentryNdkUtil.addPackage(options.sdkVersion) - assertNull(options.sdkVersion?.packages) + assertNull(options.sdkVersion?.packageSet) } } diff --git a/sentry-android-okhttp/api/sentry-android-okhttp.api b/sentry-android-okhttp/api/sentry-android-okhttp.api index 7a472922c1..897755948a 100644 --- a/sentry-android-okhttp/api/sentry-android-okhttp.api +++ b/sentry-android-okhttp/api/sentry-android-okhttp.api @@ -6,7 +6,7 @@ public final class io/sentry/android/okhttp/BuildConfig { public fun ()V } -public final class io/sentry/android/okhttp/SentryOkHttpInterceptor : okhttp3/Interceptor { +public final class io/sentry/android/okhttp/SentryOkHttpInterceptor : io/sentry/IntegrationName, okhttp3/Interceptor { public fun ()V public fun (Lio/sentry/IHub;)V public fun (Lio/sentry/IHub;Lio/sentry/android/okhttp/SentryOkHttpInterceptor$BeforeSpanCallback;ZLjava/util/List;Ljava/util/List;)V diff --git a/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpInterceptor.kt b/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpInterceptor.kt index 0e28e6f460..bbe6364375 100644 --- a/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpInterceptor.kt +++ b/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpInterceptor.kt @@ -7,7 +7,9 @@ import io.sentry.HttpStatusCodeRange import io.sentry.HubAdapter import io.sentry.IHub import io.sentry.ISpan +import io.sentry.IntegrationName import io.sentry.SentryEvent +import io.sentry.SentryIntegrationPackageStorage import io.sentry.SpanStatus import io.sentry.TypeCheckHint.OKHTTP_REQUEST import io.sentry.TypeCheckHint.OKHTTP_RESPONSE @@ -45,12 +47,18 @@ class SentryOkHttpInterceptor( HttpStatusCodeRange(HttpStatusCodeRange.DEFAULT_MIN, HttpStatusCodeRange.DEFAULT_MAX) ), private val failedRequestTargets: List = listOf(".*") -) : Interceptor { +) : Interceptor, IntegrationName { constructor() : this(HubAdapter.getInstance()) constructor(hub: IHub) : this(hub, null) constructor(beforeSpan: BeforeSpanCallback) : this(HubAdapter.getInstance(), beforeSpan) + init { + addIntegrationToSdkVersion() + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-android-okhttp", BuildConfig.VERSION_NAME) + } + override fun intercept(chain: Interceptor.Chain): Response { var request = chain.request() diff --git a/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberIntegration.kt b/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberIntegration.kt index 5299950225..6477a2531a 100644 --- a/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberIntegration.kt +++ b/sentry-android-timber/src/main/java/io/sentry/android/timber/SentryTimberIntegration.kt @@ -3,6 +3,7 @@ package io.sentry.android.timber import io.sentry.IHub import io.sentry.ILogger import io.sentry.Integration +import io.sentry.SentryIntegrationPackageStorage import io.sentry.SentryLevel import io.sentry.SentryOptions import io.sentry.android.timber.BuildConfig.VERSION_NAME @@ -20,14 +21,14 @@ class SentryTimberIntegration( private lateinit var logger: ILogger override fun register(hub: IHub, options: SentryOptions) { - options.sdkVersion?.addPackage("maven:io.sentry:sentry-android-timber", VERSION_NAME) - logger = options.logger tree = SentryTimberTree(hub, minEventLevel, minBreadcrumbLevel) Timber.plant(tree) logger.log(SentryLevel.DEBUG, "SentryTimberIntegration installed.") + SentryIntegrationPackageStorage.getInstance().addPackage("maven:io.sentry:sentry-android-timber", VERSION_NAME) + addIntegrationToSdkVersion() } override fun close() { diff --git a/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberIntegrationTest.kt b/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberIntegrationTest.kt index 2c2b248c5d..a57853e059 100644 --- a/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberIntegrationTest.kt +++ b/sentry-android-timber/src/test/java/io/sentry/android/timber/SentryTimberIntegrationTest.kt @@ -91,15 +91,25 @@ class SentryTimberIntegrationTest { } @Test - fun `Integrations adds itself to the package list`() { + fun `Integration adds itself to the package list`() { val sut = fixture.getSut() sut.register(fixture.hub, fixture.options) assertTrue( - fixture.options.sdkVersion!!.packages!!.any { + fixture.options.sdkVersion!!.packageSet.any { it.name == "maven:io.sentry:sentry-android-timber" && it.version == BuildConfig.VERSION_NAME } ) } + + @Test + fun `Integration adds itself to the integration list`() { + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + + assertTrue( + fixture.options.sdkVersion!!.integrationSet.contains("Timber") + ) + } } diff --git a/sentry-apollo-3/api/sentry-apollo-3.api b/sentry-apollo-3/api/sentry-apollo-3.api index a41facc18a..34cfe52ce5 100644 --- a/sentry-apollo-3/api/sentry-apollo-3.api +++ b/sentry-apollo-3/api/sentry-apollo-3.api @@ -1,4 +1,9 @@ -public final class io/sentry/apollo3/SentryApollo3HttpInterceptor : com/apollographql/apollo3/network/http/HttpInterceptor { +public final class io/sentry/apollo3/BuildConfig { + public static final field SENTRY_APOLLO3_SDK_NAME Ljava/lang/String; + public static final field VERSION_NAME Ljava/lang/String; +} + +public final class io/sentry/apollo3/SentryApollo3HttpInterceptor : com/apollographql/apollo3/network/http/HttpInterceptor, io/sentry/IntegrationName { public static final field Companion Lio/sentry/apollo3/SentryApollo3HttpInterceptor$Companion; public static final field SENTRY_APOLLO_3_OPERATION_NAME Ljava/lang/String; public static final field SENTRY_APOLLO_3_OPERATION_TYPE Ljava/lang/String; @@ -8,6 +13,7 @@ public final class io/sentry/apollo3/SentryApollo3HttpInterceptor : com/apollogr public fun (Lio/sentry/IHub;Lio/sentry/apollo3/SentryApollo3HttpInterceptor$BeforeSpanCallback;)V public synthetic fun (Lio/sentry/IHub;Lio/sentry/apollo3/SentryApollo3HttpInterceptor$BeforeSpanCallback;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun dispose ()V + public fun getIntegrationName ()Ljava/lang/String; public fun intercept (Lcom/apollographql/apollo3/api/http/HttpRequest;Lcom/apollographql/apollo3/network/http/HttpInterceptorChain;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } diff --git a/sentry-apollo-3/build.gradle.kts b/sentry-apollo-3/build.gradle.kts index a04a9bd91f..03bd3bb84f 100644 --- a/sentry-apollo-3/build.gradle.kts +++ b/sentry-apollo-3/build.gradle.kts @@ -77,3 +77,10 @@ tasks.withType().configureEach { option("NullAway:AnnotatedPackages", "io.sentry") } } + +buildConfig { + useJavaOutput() + packageName("io.sentry.apollo3") + buildConfigField("String", "SENTRY_APOLLO3_SDK_NAME", "\"${Config.Sentry.SENTRY_APOLLO3_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") +} diff --git a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt index 71b8c5adcb..46db8f7914 100644 --- a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt +++ b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt @@ -13,6 +13,8 @@ import io.sentry.Hint import io.sentry.HubAdapter import io.sentry.IHub import io.sentry.ISpan +import io.sentry.IntegrationName +import io.sentry.SentryIntegrationPackageStorage import io.sentry.SentryLevel import io.sentry.SpanStatus import io.sentry.TypeCheckHint @@ -20,7 +22,12 @@ import io.sentry.util.PropagationTargetsUtils import io.sentry.util.UrlUtils class SentryApollo3HttpInterceptor @JvmOverloads constructor(private val hub: IHub = HubAdapter.getInstance(), private val beforeSpan: BeforeSpanCallback? = null) : - HttpInterceptor { + HttpInterceptor, IntegrationName { + + init { + addIntegrationToSdkVersion() + SentryIntegrationPackageStorage.getInstance().addPackage("maven:io.sentry:sentry-apollo-3", BuildConfig.VERSION_NAME) + } override suspend fun intercept( request: HttpRequest, @@ -76,6 +83,10 @@ class SentryApollo3HttpInterceptor @JvmOverloads constructor(private val hub: IH } } + override fun getIntegrationName(): String { + return super.getIntegrationName().replace("Http", "") + } + private fun removeSentryInternalHeaders(headers: List): List { return headers.filterNot { it.name == SENTRY_APOLLO_3_VARIABLES || it.name == SENTRY_APOLLO_3_OPERATION_NAME || it.name == SENTRY_APOLLO_3_OPERATION_TYPE } } diff --git a/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt b/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt index b5cd806299..f38d77d012 100644 --- a/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt +++ b/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt @@ -14,6 +14,7 @@ import io.sentry.TraceContext import io.sentry.TracesSamplingDecision import io.sentry.TransactionContext import io.sentry.apollo3.SentryApollo3HttpInterceptor.BeforeSpanCallback +import io.sentry.protocol.SdkVersion import io.sentry.protocol.SentryTransaction import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -35,7 +36,15 @@ class SentryApollo3InterceptorTest { class Fixture { val server = MockWebServer() - val hub = mock() + val hub = mock().apply { + whenever(options).thenReturn( + SentryOptions().apply { + dsn = "https://key@sentry.io/proj" + isTraceSampling = true + sdkVersion = SdkVersion("test", "1.2.3") + } + ) + } private var httpInterceptor = SentryApollo3HttpInterceptor(hub) @SuppressWarnings("LongParameterList") @@ -59,13 +68,6 @@ class SentryApollo3InterceptorTest { addThirdPartyBaggageHeader: Boolean = false, beforeSpan: BeforeSpanCallback? = null ): ApolloClient { - whenever(hub.options).thenReturn( - SentryOptions().apply { - dsn = "https://key@sentry.io/proj" - isTraceSampling = true - } - ) - server.enqueue( MockResponse() .setBody(responseBody) @@ -244,6 +246,15 @@ class SentryApollo3InterceptorTest { ) } + @Test + fun `sets SDKVersion Info`() { + assertNotNull(fixture.hub.options.sdkVersion) + assert(fixture.hub.options.sdkVersion!!.integrationSet.contains("Apollo3")) + val packageInfo = fixture.hub.options.sdkVersion!!.packageSet.firstOrNull { pkg -> pkg.name == "maven:io.sentry:sentry-apollo-3" } + assertNotNull(packageInfo) + assert(packageInfo.version == BuildConfig.VERSION_NAME) + } + private fun assertTransactionDetails(it: SentryTransaction) { assertEquals(1, it.spans.size) val httpClientSpan = it.spans.first() diff --git a/sentry-apollo/api/sentry-apollo.api b/sentry-apollo/api/sentry-apollo.api index 5bdb1df0c3..bf1ab6abed 100644 --- a/sentry-apollo/api/sentry-apollo.api +++ b/sentry-apollo/api/sentry-apollo.api @@ -1,4 +1,9 @@ -public final class io/sentry/apollo/SentryApolloInterceptor : com/apollographql/apollo/interceptor/ApolloInterceptor { +public final class io/sentry/apollo/BuildConfig { + public static final field SENTRY_APOLLO_SDK_NAME Ljava/lang/String; + public static final field VERSION_NAME Ljava/lang/String; +} + +public final class io/sentry/apollo/SentryApolloInterceptor : com/apollographql/apollo/interceptor/ApolloInterceptor, io/sentry/IntegrationName { public fun ()V public fun (Lio/sentry/IHub;)V public fun (Lio/sentry/IHub;Lio/sentry/apollo/SentryApolloInterceptor$BeforeSpanCallback;)V diff --git a/sentry-apollo/build.gradle.kts b/sentry-apollo/build.gradle.kts index 3304e431c7..f2838d5247 100644 --- a/sentry-apollo/build.gradle.kts +++ b/sentry-apollo/build.gradle.kts @@ -78,3 +78,10 @@ tasks.withType().configureEach { option("NullAway:AnnotatedPackages", "io.sentry") } } + +buildConfig { + useJavaOutput() + packageName("io.sentry.apollo") + buildConfigField("String", "SENTRY_APOLLO_SDK_NAME", "\"${Config.Sentry.SENTRY_APOLLO_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") +} diff --git a/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt b/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt index 1ccb55ba5d..a5bb3d7ab8 100644 --- a/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt +++ b/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt @@ -17,6 +17,8 @@ import io.sentry.Hint import io.sentry.HubAdapter import io.sentry.IHub import io.sentry.ISpan +import io.sentry.IntegrationName +import io.sentry.SentryIntegrationPackageStorage import io.sentry.SentryLevel import io.sentry.SpanStatus import io.sentry.TypeCheckHint.APOLLO_REQUEST @@ -26,11 +28,16 @@ import java.util.concurrent.Executor class SentryApolloInterceptor( private val hub: IHub = HubAdapter.getInstance(), private val beforeSpan: BeforeSpanCallback? = null -) : ApolloInterceptor { +) : ApolloInterceptor, IntegrationName { constructor(hub: IHub) : this(hub, null) constructor(beforeSpan: BeforeSpanCallback) : this(HubAdapter.getInstance(), beforeSpan) + init { + addIntegrationToSdkVersion() + SentryIntegrationPackageStorage.getInstance().addPackage("maven:io.sentry:sentry-apollo", BuildConfig.VERSION_NAME) + } + override fun interceptAsync(request: InterceptorRequest, chain: ApolloInterceptorChain, dispatcher: Executor, callBack: CallBack) { val activeSpan = hub.span if (activeSpan == null) { diff --git a/sentry-apollo/src/test/java/io/sentry/apollo/SentryApolloInterceptorTest.kt b/sentry-apollo/src/test/java/io/sentry/apollo/SentryApolloInterceptorTest.kt index cd80f5a871..d0a883b7c6 100644 --- a/sentry-apollo/src/test/java/io/sentry/apollo/SentryApolloInterceptorTest.kt +++ b/sentry-apollo/src/test/java/io/sentry/apollo/SentryApolloInterceptorTest.kt @@ -13,6 +13,7 @@ import io.sentry.SpanStatus import io.sentry.TraceContext import io.sentry.TracesSamplingDecision import io.sentry.TransactionContext +import io.sentry.protocol.SdkVersion import io.sentry.protocol.SentryTransaction import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -33,7 +34,14 @@ class SentryApolloInterceptorTest { class Fixture { val server = MockWebServer() - val hub = mock() + val hub = mock().apply { + whenever(options).thenReturn( + SentryOptions().apply { + dsn = "https://key@sentry.io/proj" + sdkVersion = SdkVersion("test", "1.2.3") + } + ) + } private var interceptor = SentryApolloInterceptor(hub) @SuppressWarnings("LongParameterList") @@ -56,12 +64,6 @@ class SentryApolloInterceptorTest { socketPolicy: SocketPolicy = SocketPolicy.KEEP_OPEN, beforeSpan: SentryApolloInterceptor.BeforeSpanCallback? = null ): ApolloClient { - whenever(hub.options).thenReturn( - SentryOptions().apply { - dsn = "http://key@localhost/proj" - } - ) - server.enqueue( MockResponse() .setBody(responseBody) @@ -191,6 +193,15 @@ class SentryApolloInterceptorTest { ) } + @Test + fun `sets SDKVersion Info`() { + assertNotNull(fixture.hub.options.sdkVersion) + assert(fixture.hub.options.sdkVersion!!.integrationSet.contains("Apollo")) + val packageInfo = fixture.hub.options.sdkVersion!!.packageSet.firstOrNull { pkg -> pkg.name == "maven:io.sentry:sentry-apollo" } + assertNotNull(packageInfo) + assert(packageInfo.version == BuildConfig.VERSION_NAME) + } + private fun assertTransactionDetails(it: SentryTransaction) { assertEquals(1, it.spans.size) val httpClientSpan = it.spans.first() diff --git a/sentry-compose-helper/api/sentry-compose-helper.api b/sentry-compose-helper/api/sentry-compose-helper.api index b9fe8287fc..3903641972 100644 --- a/sentry-compose-helper/api/sentry-compose-helper.api +++ b/sentry-compose-helper/api/sentry-compose-helper.api @@ -3,3 +3,10 @@ public final class io/sentry/compose/gestures/ComposeGestureTargetLocator : io/s public fun locate (Ljava/lang/Object;FFLio/sentry/internal/gestures/UiElement$Type;)Lio/sentry/internal/gestures/UiElement; } +public final class io/sentry/compose/helper/BuildConfig { + public static final field $stable I + public static final field INSTANCE Lio/sentry/compose/helper/BuildConfig; + public static final field SENTRY_COMPOSE_HELPER_SDK_NAME Ljava/lang/String; + public static final field VERSION_NAME Ljava/lang/String; +} + diff --git a/sentry-compose-helper/build.gradle.kts b/sentry-compose-helper/build.gradle.kts index 734fd1143f..b28ac4cbcc 100644 --- a/sentry-compose-helper/build.gradle.kts +++ b/sentry-compose-helper/build.gradle.kts @@ -42,3 +42,13 @@ val embeddedJar by configurations.creating { artifacts { add("embeddedJar", File("$buildDir/libs/sentry-compose-helper-jvm-$version.jar")) } + +buildConfig { + sourceSets.getByName("jvmMain") { + useKotlinOutput() + className("BuildConfig") + packageName("io.sentry.compose.helper") + buildConfigField("String", "SENTRY_COMPOSE_HELPER_SDK_NAME", "\"${Config.Sentry.SENTRY_COMPOSE_HELPER_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") + } +} diff --git a/sentry-compose-helper/src/jvmMain/java/io/sentry/compose/gestures/ComposeGestureTargetLocator.java b/sentry-compose-helper/src/jvmMain/java/io/sentry/compose/gestures/ComposeGestureTargetLocator.java index d6a6e79ed6..db45a48e00 100644 --- a/sentry-compose-helper/src/jvmMain/java/io/sentry/compose/gestures/ComposeGestureTargetLocator.java +++ b/sentry-compose-helper/src/jvmMain/java/io/sentry/compose/gestures/ComposeGestureTargetLocator.java @@ -7,6 +7,8 @@ import androidx.compose.ui.semantics.SemanticsConfiguration; import androidx.compose.ui.semantics.SemanticsModifier; import androidx.compose.ui.semantics.SemanticsPropertyKey; +import io.sentry.SentryIntegrationPackageStorage; +import io.sentry.compose.helper.BuildConfig; import io.sentry.internal.gestures.GestureTargetLocator; import io.sentry.internal.gestures.UiElement; import java.util.LinkedList; @@ -19,6 +21,12 @@ @SuppressWarnings("KotlinInternalInJava") public final class ComposeGestureTargetLocator implements GestureTargetLocator { + public ComposeGestureTargetLocator() { + SentryIntegrationPackageStorage.getInstance().addIntegration("ComposeUserInteraction"); + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-compose", BuildConfig.VERSION_NAME); + } + @Override public @Nullable UiElement locate( @NotNull Object root, float x, float y, UiElement.Type targetType) { diff --git a/sentry-compose/src/androidMain/kotlin/io/sentry/compose/SentryNavigationIntegration.kt b/sentry-compose/src/androidMain/kotlin/io/sentry/compose/SentryNavigationIntegration.kt index 7112e7ff77..2c12d628a0 100644 --- a/sentry-compose/src/androidMain/kotlin/io/sentry/compose/SentryNavigationIntegration.kt +++ b/sentry-compose/src/androidMain/kotlin/io/sentry/compose/SentryNavigationIntegration.kt @@ -13,6 +13,8 @@ import androidx.navigation.NavController import androidx.navigation.NavHostController import io.sentry.Breadcrumb import io.sentry.ITransaction +import io.sentry.IntegrationName +import io.sentry.SentryIntegrationPackageStorage import io.sentry.SentryOptions import io.sentry.android.navigation.SentryNavigationListener @@ -20,7 +22,12 @@ internal class SentryLifecycleObserver( private val navController: NavController, private val navListener: NavController.OnDestinationChangedListener = SentryNavigationListener() -) : LifecycleEventObserver { +) : LifecycleEventObserver, IntegrationName { + + init { + addIntegrationToSdkVersion() + SentryIntegrationPackageStorage.getInstance().addPackage("maven:io.sentry:sentry-compose", BuildConfig.VERSION_NAME) + } override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { if (event == Lifecycle.Event.ON_RESUME) { @@ -30,6 +37,10 @@ internal class SentryLifecycleObserver( } } + override fun getIntegrationName(): String { + return "ComposeNavigation" + } + fun dispose() { navController.removeOnDestinationChangedListener(navListener) } diff --git a/sentry-graphql/api/sentry-graphql.api b/sentry-graphql/api/sentry-graphql.api index 851ea57019..c39cccdb49 100644 --- a/sentry-graphql/api/sentry-graphql.api +++ b/sentry-graphql/api/sentry-graphql.api @@ -1,3 +1,8 @@ +public final class io/sentry/graphql/BuildConfig { + public static final field SENTRY_GRAPHQL_SDK_NAME Ljava/lang/String; + public static final field VERSION_NAME Ljava/lang/String; +} + public final class io/sentry/graphql/SentryDataFetcherExceptionHandler : graphql/execution/DataFetcherExceptionHandler { public fun (Lgraphql/execution/DataFetcherExceptionHandler;)V public fun (Lio/sentry/IHub;Lgraphql/execution/DataFetcherExceptionHandler;)V diff --git a/sentry-graphql/build.gradle.kts b/sentry-graphql/build.gradle.kts index c9fb4a6004..5e20682a8d 100644 --- a/sentry-graphql/build.gradle.kts +++ b/sentry-graphql/build.gradle.kts @@ -7,6 +7,7 @@ plugins { jacoco id(Config.QualityPlugins.errorProne) id(Config.QualityPlugins.gradleVersions) + id(Config.BuildPlugins.buildConfig) version Config.BuildPlugins.buildConfigVersion } configure { @@ -74,3 +75,10 @@ tasks.withType().configureEach { option("NullAway:AnnotatedPackages", "io.sentry") } } + +buildConfig { + useJavaOutput() + packageName("io.sentry.graphql") + buildConfigField("String", "SENTRY_GRAPHQL_SDK_NAME", "\"${Config.Sentry.SENTRY_GRAPHQL_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") +} diff --git a/sentry-graphql/src/main/java/io/sentry/graphql/SentryInstrumentation.java b/sentry-graphql/src/main/java/io/sentry/graphql/SentryInstrumentation.java index bc6323d5b5..b66f6c9c89 100644 --- a/sentry-graphql/src/main/java/io/sentry/graphql/SentryInstrumentation.java +++ b/sentry-graphql/src/main/java/io/sentry/graphql/SentryInstrumentation.java @@ -14,6 +14,7 @@ import io.sentry.HubAdapter; import io.sentry.IHub; import io.sentry.ISpan; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SpanStatus; import io.sentry.util.Objects; import java.util.concurrent.CompletableFuture; @@ -28,6 +29,9 @@ public SentryInstrumentation( final @NotNull IHub hub, final @Nullable BeforeSpanCallback beforeSpan) { this.hub = Objects.requireNonNull(hub, "hub is required"); this.beforeSpan = beforeSpan; + SentryIntegrationPackageStorage.getInstance().addIntegration("GraphQL"); + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-graphql", BuildConfig.VERSION_NAME); } public SentryInstrumentation(final @Nullable BeforeSpanCallback beforeSpan) { diff --git a/sentry-graphql/src/test/kotlin/io/sentry/graphql/SentryInstrumentationTest.kt b/sentry-graphql/src/test/kotlin/io/sentry/graphql/SentryInstrumentationTest.kt index 900a83a6dd..6507576de0 100644 --- a/sentry-graphql/src/test/kotlin/io/sentry/graphql/SentryInstrumentationTest.kt +++ b/sentry-graphql/src/test/kotlin/io/sentry/graphql/SentryInstrumentationTest.kt @@ -133,5 +133,15 @@ class SentryInstrumentationTest { assertTrue(span.isFinished) } + @Test + fun `Integration adds itself to integration and package list`() { + val sut = fixture.getSut() + assertNotNull(fixture.hub.options.sdkVersion) + assert(fixture.hub.options.sdkVersion!!.integrationSet.contains("GraphQL")) + val packageInfo = fixture.hub.options.sdkVersion!!.packageSet.firstOrNull { pkg -> pkg.name == "maven:io.sentry:sentry-graphql" } + assertNotNull(packageInfo) + assert(packageInfo.version == BuildConfig.VERSION_NAME) + } + data class Show(val id: Int) } diff --git a/sentry-jdbc/api/sentry-jdbc.api b/sentry-jdbc/api/sentry-jdbc.api index 266666783b..a1df685bc3 100644 --- a/sentry-jdbc/api/sentry-jdbc.api +++ b/sentry-jdbc/api/sentry-jdbc.api @@ -1,3 +1,8 @@ +public final class io/sentry/jdbc/BuildConfig { + public static final field SENTRY_JDBC_SDK_NAME Ljava/lang/String; + public static final field VERSION_NAME Ljava/lang/String; +} + public class io/sentry/jdbc/SentryJdbcEventListener : com/p6spy/engine/event/SimpleJdbcEventListener { public fun ()V public fun (Lio/sentry/IHub;)V diff --git a/sentry-jdbc/build.gradle.kts b/sentry-jdbc/build.gradle.kts index 3e3688cead..ba3bfffc10 100644 --- a/sentry-jdbc/build.gradle.kts +++ b/sentry-jdbc/build.gradle.kts @@ -7,6 +7,7 @@ plugins { jacoco id(Config.QualityPlugins.errorProne) id(Config.QualityPlugins.gradleVersions) + id(Config.BuildPlugins.buildConfig) version Config.BuildPlugins.buildConfigVersion } configure { @@ -72,3 +73,10 @@ tasks.withType().configureEach { option("NullAway:AnnotatedPackages", "io.sentry") } } + +buildConfig { + useJavaOutput() + packageName("io.sentry.jdbc") + buildConfigField("String", "SENTRY_JDBC_SDK_NAME", "\"${Config.Sentry.SENTRY_JDBC_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") +} diff --git a/sentry-jdbc/src/main/java/io/sentry/jdbc/SentryJdbcEventListener.java b/sentry-jdbc/src/main/java/io/sentry/jdbc/SentryJdbcEventListener.java index f8062a097e..99e4aa5501 100644 --- a/sentry-jdbc/src/main/java/io/sentry/jdbc/SentryJdbcEventListener.java +++ b/sentry-jdbc/src/main/java/io/sentry/jdbc/SentryJdbcEventListener.java @@ -6,6 +6,7 @@ import io.sentry.HubAdapter; import io.sentry.IHub; import io.sentry.ISpan; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.Span; import io.sentry.SpanStatus; import io.sentry.util.Objects; @@ -21,6 +22,7 @@ public class SentryJdbcEventListener extends SimpleJdbcEventListener { public SentryJdbcEventListener(final @NotNull IHub hub) { this.hub = Objects.requireNonNull(hub, "hub is required"); + addPackageAndIntegrationInfo(); } public SentryJdbcEventListener() { @@ -53,4 +55,10 @@ public void onAfterAnyExecute( CURRENT_SPAN.set(null); } } + + private void addPackageAndIntegrationInfo() { + SentryIntegrationPackageStorage.getInstance().addIntegration("JDBC"); + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-jdbc", BuildConfig.VERSION_NAME); + } } diff --git a/sentry-jdbc/src/test/kotlin/io/sentry/jdbc/SentryJdbcEventListenerTest.kt b/sentry-jdbc/src/test/kotlin/io/sentry/jdbc/SentryJdbcEventListenerTest.kt index 58aa95709a..bab781bab0 100644 --- a/sentry-jdbc/src/test/kotlin/io/sentry/jdbc/SentryJdbcEventListenerTest.kt +++ b/sentry-jdbc/src/test/kotlin/io/sentry/jdbc/SentryJdbcEventListenerTest.kt @@ -6,6 +6,7 @@ import io.sentry.SentryOptions import io.sentry.SentryTracer import io.sentry.SpanStatus import io.sentry.TransactionContext +import io.sentry.protocol.SdkVersion import org.hsqldb.jdbc.JDBCDataSource import org.mockito.kotlin.mock import org.mockito.kotlin.whenever @@ -13,17 +14,23 @@ import javax.sql.DataSource import kotlin.test.AfterTest import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertNotNull import kotlin.test.assertTrue class SentryJdbcEventListenerTest { class Fixture { - private val hub = mock() + val hub = mock().apply { + whenever(options).thenReturn( + SentryOptions().apply { + sdkVersion = SdkVersion("test", "1.2.3") + } + ) + } lateinit var tx: SentryTracer val actualDataSource = JDBCDataSource() fun getSut(withRunningTransaction: Boolean = true, existingRow: Int? = null): DataSource { - whenever(hub.options).thenReturn(SentryOptions()) tx = SentryTracer(TransactionContext("name", "op"), hub) if (withRunningTransaction) { whenever(hub.span).thenReturn(tx) @@ -103,4 +110,14 @@ class SentryJdbcEventListenerTest { assertTrue(fixture.tx.children.isEmpty()) } + + @Test + fun `sets SDKVersion Info`() { + val sut = fixture.getSut() + assertNotNull(fixture.hub.options.sdkVersion) + assert(fixture.hub.options.sdkVersion!!.integrationSet.contains("JDBC")) + val packageInfo = fixture.hub.options.sdkVersion!!.packageSet.firstOrNull { pkg -> pkg.name == "maven:io.sentry:sentry-jdbc" } + assertNotNull(packageInfo) + assert(packageInfo.version == BuildConfig.VERSION_NAME) + } } diff --git a/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java b/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java index ef8a445fae..6d3775a9c2 100644 --- a/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java +++ b/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java @@ -9,6 +9,7 @@ import io.sentry.HubAdapter; import io.sentry.Sentry; import io.sentry.SentryEvent; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.protocol.Message; @@ -70,6 +71,7 @@ public SentryHandler(final @NotNull SentryOptions options) { options.setSdkVersion(createSdkVersion(options)); Sentry.init(options); } + addPackageAndIntegrationInfo(); } @Override @@ -276,11 +278,16 @@ public void close() throws SecurityException { final String version = BuildConfig.VERSION_NAME; sdkVersion = SdkVersion.updateSdkVersion(sdkVersion, name, version); - sdkVersion.addPackage("maven:io.sentry:sentry-jul", version); return sdkVersion; } + private void addPackageAndIntegrationInfo() { + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-jul", BuildConfig.VERSION_NAME); + SentryIntegrationPackageStorage.getInstance().addIntegration("Jul"); + } + public void setPrintfStyle(final boolean printfStyle) { this.printfStyle = printfStyle; } diff --git a/sentry-jul/src/test/kotlin/io/sentry/jul/SentryHandlerTest.kt b/sentry-jul/src/test/kotlin/io/sentry/jul/SentryHandlerTest.kt index 6b857ced5a..d7883a15c5 100644 --- a/sentry-jul/src/test/kotlin/io/sentry/jul/SentryHandlerTest.kt +++ b/sentry-jul/src/test/kotlin/io/sentry/jul/SentryHandlerTest.kt @@ -386,13 +386,15 @@ class SentryHandlerTest { assertNotNull(event.sdk) { assertEquals(BuildConfig.SENTRY_JUL_SDK_NAME, it.name) assertEquals(BuildConfig.VERSION_NAME, it.version) - assertNotNull(it.packages) assertTrue( - it.packages!!.any { pkg -> + it.packageSet.any { pkg -> "maven:io.sentry:sentry-jul" == pkg.name && BuildConfig.VERSION_NAME == pkg.version } ) + assertTrue( + it.integrationSet.contains("Jul") + ) } }, anyOrNull() diff --git a/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java b/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java index e35a24708c..1fdd55e997 100644 --- a/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java +++ b/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java @@ -12,6 +12,7 @@ import io.sentry.ITransportFactory; import io.sentry.Sentry; import io.sentry.SentryEvent; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.protocol.Message; @@ -133,6 +134,7 @@ public void start() { LOGGER.info("Failed to init Sentry during appender initialization: " + e.getMessage()); } } + addPackageAndIntegrationInfo(); super.start(); } @@ -261,8 +263,12 @@ public void append(final @NotNull LogEvent eventObject) { final String version = BuildConfig.VERSION_NAME; sdkVersion = SdkVersion.updateSdkVersion(sdkVersion, name, version); - sdkVersion.addPackage("maven:io.sentry:sentry-log4j2", version); - return sdkVersion; } + + private void addPackageAndIntegrationInfo() { + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-log4j2", BuildConfig.VERSION_NAME); + SentryIntegrationPackageStorage.getInstance().addIntegration("Log4j"); + } } diff --git a/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt b/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt index 80413ba847..b9ea77c490 100644 --- a/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt +++ b/sentry-log4j2/src/test/kotlin/io/sentry/log4j2/SentryAppenderTest.kt @@ -332,13 +332,13 @@ class SentryAppenderTest { assertNotNull(event.sdk) { assertEquals(BuildConfig.SENTRY_LOG4J2_SDK_NAME, it.name) assertEquals(BuildConfig.VERSION_NAME, it.version) - assertNotNull(it.packages) assertTrue( - it.packages!!.any { pkg -> + it.packageSet.any { pkg -> "maven:io.sentry:sentry-log4j2" == pkg.name && BuildConfig.VERSION_NAME == pkg.version } ) + assertTrue(it.integrationSet.contains("Log4j")) } }, anyOrNull() diff --git a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java index ae476e2036..40a2c72e11 100644 --- a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java +++ b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java @@ -16,6 +16,7 @@ import io.sentry.ITransportFactory; import io.sentry.Sentry; import io.sentry.SentryEvent; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.protocol.Message; @@ -63,6 +64,7 @@ public void start() { .log(SentryLevel.WARNING, "DSN is null. SentryAppender is not being initialized"); } } + addPackageAndIntegrationInfo(); super.start(); } @@ -203,11 +205,15 @@ private String formatted(@NotNull ILoggingEvent loggingEvent) { final String version = BuildConfig.VERSION_NAME; sdkVersion = SdkVersion.updateSdkVersion(sdkVersion, name, version); - sdkVersion.addPackage("maven:io.sentry:sentry-logback", version); - return sdkVersion; } + private void addPackageAndIntegrationInfo() { + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-logback", BuildConfig.VERSION_NAME); + SentryIntegrationPackageStorage.getInstance().addIntegration("Logback"); + } + public void setOptions(final @Nullable SentryOptions options) { if (options != null) { this.options = options; diff --git a/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt index b10b74ce50..3e908b1f71 100644 --- a/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt +++ b/sentry-logback/src/test/kotlin/io/sentry/logback/SentryAppenderTest.kt @@ -368,13 +368,13 @@ class SentryAppenderTest { assertNotNull(event.sdk) { assertEquals(BuildConfig.SENTRY_LOGBACK_SDK_NAME, it.name) assertEquals(BuildConfig.VERSION_NAME, it.version) - assertNotNull(it.packages) assertTrue( - it.packages!!.any { pkg -> + it.packageSet.any { pkg -> "maven:io.sentry:sentry-logback" == pkg.name && BuildConfig.VERSION_NAME == pkg.version } ) + assertTrue(it.integrationSet.contains("Logback")) } }, anyOrNull() diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java index 86c5bab31b..e808db8fcf 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java +++ b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java @@ -6,12 +6,16 @@ import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import io.sentry.Instrumenter; import io.sentry.Sentry; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOptions; import io.sentry.protocol.SdkVersion; +import io.sentry.protocol.SentryPackage; import java.io.IOException; import java.net.URL; +import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.jar.Attributes; import java.util.jar.Manifest; @@ -23,19 +27,29 @@ public final class SentryAutoConfigurationCustomizerProvider @Override public void customize(AutoConfigurationCustomizer autoConfiguration) { + final @Nullable VersionInfoHolder versionInfoHolder = createVersionInfo(); if (isSentryAutoInitEnabled()) { Sentry.init( options -> { options.setEnableExternalConfiguration(true); options.setInstrumenter(Instrumenter.OTEL); options.addEventProcessor(new OpenTelemetryLinkErrorEventProcessor()); - final @Nullable SdkVersion sdkVersion = createSdkVersion(options); + final @Nullable SdkVersion sdkVersion = createSdkVersion(options, versionInfoHolder); if (sdkVersion != null) { options.setSdkVersion(sdkVersion); } }); } + if (versionInfoHolder != null) { + for (SentryPackage pkg : versionInfoHolder.packages) { + SentryIntegrationPackageStorage.getInstance().addPackage(pkg.getName(), pkg.getVersion()); + } + for (String integration : versionInfoHolder.integrations) { + SentryIntegrationPackageStorage.getInstance().addIntegration(integration); + } + } + autoConfiguration .addTracerProviderCustomizer(this::configureSdkTracerProvider) .addPropertiesSupplier(this::getDefaultProperties); @@ -54,9 +68,8 @@ private boolean isSentryAutoInitEnabled() { } } - private @Nullable SdkVersion createSdkVersion(final @NotNull SentryOptions sentryOptions) { - SdkVersion sdkVersion = sentryOptions.getSdkVersion(); - + private @Nullable VersionInfoHolder createVersionInfo() { + VersionInfoHolder infoHolder = null; try { final @NotNull Enumeration resources = ClassLoader.getSystemClassLoader().getResources("META-INF/MANIFEST.MF"); @@ -69,20 +82,28 @@ private boolean isSentryAutoInitEnabled() { final @Nullable String version = mainAttributes.getValue("Sentry-Version-Name"); if (name != null && version != null) { - sdkVersion = SdkVersion.updateSdkVersion(sdkVersion, name, version); - sdkVersion.addPackage("maven:io.sentry:sentry-opentelemetry-agent", version); + infoHolder = new VersionInfoHolder(); + infoHolder.sdkName = name; + infoHolder.sdkVersion = version; + infoHolder.packages.add( + new SentryPackage("maven:io.sentry:sentry-opentelemetry-agent", version)); final @Nullable String otelVersion = mainAttributes.getValue("Sentry-Opentelemetry-Version-Name"); if (otelVersion != null) { - sdkVersion.addPackage("maven:io.opentelemetry:opentelemetry-sdk", otelVersion); + infoHolder.packages.add( + new SentryPackage("maven:io.opentelemetry:opentelemetry-sdk", otelVersion)); + infoHolder.integrations.add("OpenTelemetry"); } final @Nullable String otelJavaagentVersion = mainAttributes.getValue("Sentry-Opentelemetry-Javaagent-Version-Name"); if (otelJavaagentVersion != null) { - sdkVersion.addPackage( - "maven:io.opentelemetry.javaagent:opentelemetry-javaagent", - otelJavaagentVersion); + infoHolder.packages.add( + new SentryPackage( + "maven:io.opentelemetry.javaagent:opentelemetry-javaagent", + otelJavaagentVersion)); + infoHolder.integrations.add("OpenTelemetry-Agent"); } + break; } } } catch (Exception e) { @@ -92,10 +113,31 @@ private boolean isSentryAutoInitEnabled() { } catch (IOException e) { // ignore } + return infoHolder; + } + + private @Nullable SdkVersion createSdkVersion( + final @NotNull SentryOptions sentryOptions, + final @Nullable VersionInfoHolder versionInfoHolder) { + SdkVersion sdkVersion = sentryOptions.getSdkVersion(); + if (versionInfoHolder != null + && versionInfoHolder.sdkName != null + && versionInfoHolder.sdkVersion != null) { + sdkVersion = + SdkVersion.updateSdkVersion( + sdkVersion, versionInfoHolder.sdkName, versionInfoHolder.sdkVersion); + } return sdkVersion; } + private static class VersionInfoHolder { + private @Nullable String sdkName; + private @Nullable String sdkVersion; + private List packages = new ArrayList<>(); + private List integrations = new ArrayList<>(); + } + private SdkTracerProviderBuilder configureSdkTracerProvider( SdkTracerProviderBuilder tracerProvider, ConfigProperties config) { return tracerProvider.addSpanProcessor(new SentrySpanProcessor()); diff --git a/sentry-servlet-jakarta/api/sentry-servlet-jakarta.api b/sentry-servlet-jakarta/api/sentry-servlet-jakarta.api index 66e0c48b48..d0367e5195 100644 --- a/sentry-servlet-jakarta/api/sentry-servlet-jakarta.api +++ b/sentry-servlet-jakarta/api/sentry-servlet-jakarta.api @@ -1,3 +1,8 @@ +public final class io/sentry/servlet/jakarta/BuildConfig { + public static final field SENTRY_SERVLET_JAKARTA_SDK_NAME Ljava/lang/String; + public static final field VERSION_NAME Ljava/lang/String; +} + public class io/sentry/servlet/jakarta/SentryServletContainerInitializer : jakarta/servlet/ServletContainerInitializer { public fun ()V public fun onStartup (Ljava/util/Set;Ljakarta/servlet/ServletContext;)V diff --git a/sentry-servlet-jakarta/build.gradle.kts b/sentry-servlet-jakarta/build.gradle.kts index 5716ed3b7b..ceb7bd50a3 100644 --- a/sentry-servlet-jakarta/build.gradle.kts +++ b/sentry-servlet-jakarta/build.gradle.kts @@ -11,6 +11,7 @@ plugins { id(Config.QualityPlugins.gradleVersions) id(Config.BuildPlugins.springBoot) version Config.springBootVersion apply false id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion + id(Config.BuildPlugins.buildConfig) version Config.BuildPlugins.buildConfigVersion } the().apply { @@ -96,3 +97,10 @@ tasks.withType().configureEach { option("NullAway:AnnotatedPackages", "io.sentry") } } + +buildConfig { + useJavaOutput() + packageName("io.sentry.servlet.jakarta") + buildConfigField("String", "SENTRY_SERVLET_JAKARTA_SDK_NAME", "\"${Config.Sentry.SENTRY_SERVLET_JAKARTA_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") +} diff --git a/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryServletContainerInitializer.java b/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryServletContainerInitializer.java index 6d77b69d5c..d5b39e82c7 100644 --- a/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryServletContainerInitializer.java +++ b/sentry-servlet-jakarta/src/main/java/io/sentry/servlet/jakarta/SentryServletContainerInitializer.java @@ -1,6 +1,7 @@ package io.sentry.servlet.jakarta; import com.jakewharton.nopen.annotation.Open; +import io.sentry.SentryIntegrationPackageStorage; import jakarta.servlet.ServletContainerInitializer; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; @@ -18,5 +19,8 @@ public class SentryServletContainerInitializer implements ServletContainerInitia public void onStartup(@Nullable Set> c, @NotNull ServletContext ctx) throws ServletException { ctx.addListener(SentryServletRequestListener.class); + SentryIntegrationPackageStorage.getInstance().addIntegration("Servlet-Jakarta"); + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-servlet-jakarta", BuildConfig.VERSION_NAME); } } diff --git a/sentry-servlet/api/sentry-servlet.api b/sentry-servlet/api/sentry-servlet.api index 63ad3dd168..a0a2a1e0d2 100644 --- a/sentry-servlet/api/sentry-servlet.api +++ b/sentry-servlet/api/sentry-servlet.api @@ -1,3 +1,8 @@ +public final class io/sentry/servlet/BuildConfig { + public static final field SENTRY_SERVLET_SDK_NAME Ljava/lang/String; + public static final field VERSION_NAME Ljava/lang/String; +} + public class io/sentry/servlet/SentryServletContainerInitializer : javax/servlet/ServletContainerInitializer { public fun ()V public fun onStartup (Ljava/util/Set;Ljavax/servlet/ServletContext;)V diff --git a/sentry-servlet/build.gradle.kts b/sentry-servlet/build.gradle.kts index bbdfbeee98..6f76e749d9 100644 --- a/sentry-servlet/build.gradle.kts +++ b/sentry-servlet/build.gradle.kts @@ -11,6 +11,7 @@ plugins { id(Config.QualityPlugins.gradleVersions) id(Config.BuildPlugins.springBoot) version Config.springBootVersion apply false id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion + id(Config.BuildPlugins.buildConfig) version Config.BuildPlugins.buildConfigVersion } the().apply { @@ -97,3 +98,10 @@ tasks.withType().configureEach { option("NullAway:AnnotatedPackages", "io.sentry") } } + +buildConfig { + useJavaOutput() + packageName("io.sentry.servlet") + buildConfigField("String", "SENTRY_SERVLET_SDK_NAME", "\"${Config.Sentry.SENTRY_SERVLET_SDK_NAME}\"") + buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") +} diff --git a/sentry-servlet/src/main/java/io/sentry/servlet/SentryServletContainerInitializer.java b/sentry-servlet/src/main/java/io/sentry/servlet/SentryServletContainerInitializer.java index 37e3487a35..26869b186e 100644 --- a/sentry-servlet/src/main/java/io/sentry/servlet/SentryServletContainerInitializer.java +++ b/sentry-servlet/src/main/java/io/sentry/servlet/SentryServletContainerInitializer.java @@ -1,6 +1,7 @@ package io.sentry.servlet; import com.jakewharton.nopen.annotation.Open; +import io.sentry.SentryIntegrationPackageStorage; import java.util.Set; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; @@ -18,5 +19,8 @@ public class SentryServletContainerInitializer implements ServletContainerInitia public void onStartup(@Nullable Set> c, @NotNull ServletContext ctx) throws ServletException { ctx.addListener(SentryServletRequestListener.class); + SentryIntegrationPackageStorage.getInstance().addIntegration("Servlet"); + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-servlet", BuildConfig.VERSION_NAME); } } diff --git a/sentry-spring-boot-starter-jakarta/build.gradle.kts b/sentry-spring-boot-starter-jakarta/build.gradle.kts index 5279f3080f..d2e1aad40e 100644 --- a/sentry-spring-boot-starter-jakarta/build.gradle.kts +++ b/sentry-spring-boot-starter-jakarta/build.gradle.kts @@ -133,7 +133,7 @@ task("jakartaMainClassTransformation", JavaExec::class) { buildConfig { useJavaOutput() packageName("io.sentry.spring.boot.jakarta") - buildConfigField("String", "SENTRY_SPRING_BOOT_SDK_NAME", "\"${Config.Sentry.SENTRY_SPRING_BOOT_JAKARTA_SDK_NAME}\"") + buildConfigField("String", "SENTRY_SPRING_BOOT_JAKARTA_SDK_NAME", "\"${Config.Sentry.SENTRY_SPRING_BOOT_JAKARTA_SDK_NAME}\"") buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") } diff --git a/sentry-spring-boot-starter-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java b/sentry-spring-boot-starter-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java index 223b20eada..a79ec8b17f 100644 --- a/sentry-spring-boot-starter-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java +++ b/sentry-spring-boot-starter-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java @@ -7,6 +7,7 @@ import io.sentry.ITransportFactory; import io.sentry.Integration; import io.sentry.Sentry; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOptions; import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor; import io.sentry.protocol.SdkVersion; @@ -113,8 +114,9 @@ static class HubConfiguration { } }); - options.setSentryClientName(BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME); + options.setSentryClientName(BuildConfig.SENTRY_SPRING_BOOT_JAKARTA_SDK_NAME); options.setSdkVersion(createSdkVersion(options)); + addPackageAndIntegrationInfo(); if (options.getTracesSampleRate() == null && options.getEnableTracing() == null) { options.setTracesSampleRate(0.0); } @@ -316,14 +318,17 @@ static class ApacheHttpClientTransportFactoryAutoconfiguration { final @NotNull SentryOptions sentryOptions) { SdkVersion sdkVersion = sentryOptions.getSdkVersion(); - final String name = BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME; + final String name = BuildConfig.SENTRY_SPRING_BOOT_JAKARTA_SDK_NAME; final String version = BuildConfig.VERSION_NAME; sdkVersion = SdkVersion.updateSdkVersion(sdkVersion, name, version); - sdkVersion.addPackage("maven:io.sentry:sentry-spring-boot-starter", version); - return sdkVersion; } + + private static void addPackageAndIntegrationInfo() { + SentryIntegrationPackageStorage.getInstance().addPackage("maven:io.sentry:sentry-spring-boot-starter-jakarta", BuildConfig.VERSION_NAME); + SentryIntegrationPackageStorage.getInstance().addIntegration("SpringBoot3"); + } } static final class SentryTracingCondition extends AnyNestedCondition { diff --git a/sentry-spring-boot-starter-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt b/sentry-spring-boot-starter-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt index 5c4cc85b33..e17942f4eb 100644 --- a/sentry-spring-boot-starter-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot-starter-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt @@ -59,6 +59,7 @@ import jakarta.servlet.Filter import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse +import kotlin.test.assertNotNull import kotlin.test.assertTrue class SentryAutoConfigurationTest { @@ -257,13 +258,14 @@ class SentryAutoConfigurationTest { val transport = it.getBean(ITransport::class.java) verify(transport).send( checkEvent { event -> - assertThat(event.sdk).isNotNull() + assertThat(event.sdk).isNotNull val sdk = event.sdk!! assertThat(sdk.version).isEqualTo(BuildConfig.VERSION_NAME) - assertThat(sdk.name).isEqualTo(BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME) - assertThat(sdk.packages).anyMatch { pkg -> - pkg.name == "maven:io.sentry:sentry-spring-boot-starter" && pkg.version == BuildConfig.VERSION_NAME + assertThat(sdk.name).isEqualTo(BuildConfig.SENTRY_SPRING_BOOT_JAKARTA_SDK_NAME) + assertThat(sdk.packageSet).anyMatch { pkg -> + pkg.name == "maven:io.sentry:sentry-spring-boot-starter-jakarta" && pkg.version == BuildConfig.VERSION_NAME } + assertTrue(sdk.integrationSet.contains("SpringBoot3")) }, anyOrNull() ) diff --git a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java index d83e7a5f84..6e252c7eb2 100644 --- a/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java +++ b/sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java @@ -7,6 +7,7 @@ import io.sentry.ITransportFactory; import io.sentry.Integration; import io.sentry.Sentry; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOptions; import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor; import io.sentry.protocol.SdkVersion; @@ -116,6 +117,7 @@ static class HubConfiguration { options.setSentryClientName(BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME); options.setSdkVersion(createSdkVersion(options)); + addPackageAndIntegrationInfo(); if (options.getTracesSampleRate() == null && options.getEnableTracing() == null) { options.setTracesSampleRate(0.0); } @@ -321,10 +323,14 @@ static class ApacheHttpClientTransportFactoryAutoconfiguration { final String version = BuildConfig.VERSION_NAME; sdkVersion = SdkVersion.updateSdkVersion(sdkVersion, name, version); - sdkVersion.addPackage("maven:io.sentry:sentry-spring-boot-starter", version); - return sdkVersion; } + + private static void addPackageAndIntegrationInfo() { + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-spring-boot-starter", BuildConfig.VERSION_NAME); + SentryIntegrationPackageStorage.getInstance().addIntegration("SpringBoot"); + } } static final class SentryTracingCondition extends AnyNestedCondition { diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt index 96e5dd1b19..abddd107d7 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt @@ -257,13 +257,14 @@ class SentryAutoConfigurationTest { val transport = it.getBean(ITransport::class.java) verify(transport).send( checkEvent { event -> - assertThat(event.sdk).isNotNull() + assertThat(event.sdk).isNotNull val sdk = event.sdk!! assertThat(sdk.version).isEqualTo(BuildConfig.VERSION_NAME) assertThat(sdk.name).isEqualTo(BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME) - assertThat(sdk.packages).anyMatch { pkg -> + assertThat(sdk.packageSet).anyMatch { pkg -> pkg.name == "maven:io.sentry:sentry-spring-boot-starter" && pkg.version == BuildConfig.VERSION_NAME } + assertTrue(sdk.integrationSet.contains("SpringBoot")) }, anyOrNull() ) diff --git a/sentry-spring-jakarta/build.gradle.kts b/sentry-spring-jakarta/build.gradle.kts index c854db7793..003a219df2 100644 --- a/sentry-spring-jakarta/build.gradle.kts +++ b/sentry-spring-jakarta/build.gradle.kts @@ -125,7 +125,7 @@ task("jakartaTestTransformation", JavaExec::class) { buildConfig { useJavaOutput() packageName("io.sentry.spring.jakarta") - buildConfigField("String", "SENTRY_SPRING_SDK_NAME", "\"${Config.Sentry.SENTRY_SPRING_SDK_NAME}\"") + buildConfigField("String", "SENTRY_SPRING_JAKARTA_SDK_NAME", "\"${Config.Sentry.SENTRY_SPRING_JAKARTA_SDK_NAME}\"") buildConfigField("String", "VERSION_NAME", "\"${project.version}\"") } diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/SentryHubRegistrar.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/SentryHubRegistrar.java index 44d9bf0525..11b4ecc755 100644 --- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/SentryHubRegistrar.java +++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/SentryHubRegistrar.java @@ -2,6 +2,7 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.HubAdapter; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOptions; import io.sentry.protocol.SdkVersion; import io.sentry.spring.jakarta.tracing.SpringMvcTransactionNameProvider; @@ -43,8 +44,9 @@ private void registerSentryOptions( } builder.addPropertyValue("dsn", annotationAttributes.getString("dsn")); builder.addPropertyValue("enableExternalConfiguration", true); - builder.addPropertyValue("sentryClientName", BuildConfig.SENTRY_SPRING_SDK_NAME); + builder.addPropertyValue("sentryClientName", BuildConfig.SENTRY_SPRING_JAKARTA_SDK_NAME); builder.addPropertyValue("sdkVersion", createSdkVersion()); + addPackageAndIntegrationInfo(); if (annotationAttributes.containsKey("sendDefaultPii")) { builder.addPropertyValue("sendDefaultPii", annotationAttributes.getBoolean("sendDefaultPii")); } @@ -81,12 +83,15 @@ private void registerSentryExceptionResolver( final SentryOptions defaultOptions = new SentryOptions(); SdkVersion sdkVersion = defaultOptions.getSdkVersion(); - final String name = BuildConfig.SENTRY_SPRING_SDK_NAME; + final String name = BuildConfig.SENTRY_SPRING_JAKARTA_SDK_NAME; final String version = BuildConfig.VERSION_NAME; sdkVersion = SdkVersion.updateSdkVersion(sdkVersion, name, version); - sdkVersion.addPackage("maven:io.sentry:sentry-spring", version); - return sdkVersion; } + + private static void addPackageAndIntegrationInfo() { + SentryIntegrationPackageStorage.getInstance().addPackage("maven:io.sentry:sentry-spring-jakarta", BuildConfig.VERSION_NAME); + SentryIntegrationPackageStorage.getInstance().addIntegration("Spring6"); + } } diff --git a/sentry-spring-jakarta/src/test/kotlin/io/sentry/spring/jakarta/EnableSentryTest.kt b/sentry-spring-jakarta/src/test/kotlin/io/sentry/spring/jakarta/EnableSentryTest.kt index 29d86c92e4..1e4cd45cf6 100644 --- a/sentry-spring-jakarta/src/test/kotlin/io/sentry/spring/jakarta/EnableSentryTest.kt +++ b/sentry-spring-jakarta/src/test/kotlin/io/sentry/spring/jakarta/EnableSentryTest.kt @@ -12,6 +12,8 @@ import org.springframework.boot.context.annotation.UserConfigurations import org.springframework.boot.test.context.runner.ApplicationContextRunner import org.springframework.context.annotation.Bean import kotlin.test.Test +import kotlin.test.assertNotNull +import kotlin.test.assertTrue class EnableSentryTest { private val contextRunner = ApplicationContextRunner() @@ -43,12 +45,12 @@ class EnableSentryTest { contextRunner.run { assertThat(it).hasSingleBean(SentryOptions::class.java) val options = it.getBean(SentryOptions::class.java) - assertThat(options.sentryClientName).isEqualTo("sentry.java.spring") + assertThat(options.sentryClientName).isEqualTo("sentry.java.spring.jakarta") assertThat(options.sdkVersion).isNotNull - assertThat(options.sdkVersion!!.name).isEqualTo("sentry.java.spring") + assertThat(options.sdkVersion!!.name).isEqualTo("sentry.java.spring.jakarta") assertThat(options.sdkVersion!!.version).isEqualTo(BuildConfig.VERSION_NAME) - assertThat(options.sdkVersion!!.packages).isNotNull - assertThat(options.sdkVersion!!.packages!!.map { pkg -> pkg.name }).contains("maven:io.sentry:sentry-spring") + assertThat(options.sdkVersion!!.packageSet.map { pkg -> pkg.name }).contains("maven:io.sentry:sentry-spring-jakarta") + assertThat(options.sdkVersion!!.integrationSet).contains("Spring6") } } diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java b/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java index b0e1c583e5..e597d175b6 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java @@ -2,6 +2,7 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.HubAdapter; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOptions; import io.sentry.protocol.SdkVersion; import io.sentry.spring.tracing.SpringMvcTransactionNameProvider; @@ -45,6 +46,7 @@ private void registerSentryOptions( builder.addPropertyValue("enableExternalConfiguration", true); builder.addPropertyValue("sentryClientName", BuildConfig.SENTRY_SPRING_SDK_NAME); builder.addPropertyValue("sdkVersion", createSdkVersion()); + addPackageAndIntegrationInfo(); if (annotationAttributes.containsKey("sendDefaultPii")) { builder.addPropertyValue("sendDefaultPii", annotationAttributes.getBoolean("sendDefaultPii")); } @@ -85,8 +87,12 @@ private void registerSentryExceptionResolver( final String version = BuildConfig.VERSION_NAME; sdkVersion = SdkVersion.updateSdkVersion(sdkVersion, name, version); - sdkVersion.addPackage("maven:io.sentry:sentry-spring", version); - return sdkVersion; } + + private static void addPackageAndIntegrationInfo() { + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry-spring", BuildConfig.VERSION_NAME); + SentryIntegrationPackageStorage.getInstance().addIntegration("Spring"); + } } diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt index c661435642..2d7cabae3e 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/EnableSentryTest.kt @@ -47,8 +47,8 @@ class EnableSentryTest { assertThat(options.sdkVersion).isNotNull assertThat(options.sdkVersion!!.name).isEqualTo("sentry.java.spring") assertThat(options.sdkVersion!!.version).isEqualTo(BuildConfig.VERSION_NAME) - assertThat(options.sdkVersion!!.packages).isNotNull - assertThat(options.sdkVersion!!.packages!!.map { pkg -> pkg.name }).contains("maven:io.sentry:sentry-spring") + assertThat(options.sdkVersion!!.packageSet.map { pkg -> pkg.name }).contains("maven:io.sentry:sentry-spring") + assertThat(options.sdkVersion!!.integrationSet).contains("Spring") } } diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index a0cb32da10..e87d693ab7 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -602,10 +602,15 @@ public final class io/sentry/Instrumenter : java/lang/Enum { public static fun values ()[Lio/sentry/Instrumenter; } -public abstract interface class io/sentry/Integration { +public abstract interface class io/sentry/Integration : io/sentry/IntegrationName { public abstract fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V } +public abstract interface class io/sentry/IntegrationName { + public fun addIntegrationToSdkVersion ()V + public fun getIntegrationName ()Ljava/lang/String; +} + public final class io/sentry/IpAddressUtils { public static fun isDefault (Ljava/lang/String;)Z } @@ -1450,6 +1455,15 @@ public final class io/sentry/SentryInstantDateProvider : io/sentry/SentryDatePro public fun now ()Lio/sentry/SentryDate; } +public final class io/sentry/SentryIntegrationPackageStorage { + public fun addIntegration (Ljava/lang/String;)V + public fun addPackage (Ljava/lang/String;Ljava/lang/String;)V + public fun clearStorage ()V + public static fun getInstance ()Lio/sentry/SentryIntegrationPackageStorage; + public fun getIntegrations ()Ljava/util/Set; + public fun getPackages ()Ljava/util/Set; +} + public final class io/sentry/SentryItemType : java/lang/Enum, io/sentry/JsonSerializable { public static final field Attachment Lio/sentry/SentryItemType; public static final field ClientReport Lio/sentry/SentryItemType; @@ -3106,8 +3120,10 @@ public final class io/sentry/protocol/SdkVersion : io/sentry/JsonSerializable, i public fun (Ljava/lang/String;Ljava/lang/String;)V public fun addIntegration (Ljava/lang/String;)V public fun addPackage (Ljava/lang/String;Ljava/lang/String;)V + public fun getIntegrationSet ()Ljava/util/Set; public fun getIntegrations ()Ljava/util/List; public fun getName ()Ljava/lang/String; + public fun getPackageSet ()Ljava/util/Set; public fun getPackages ()Ljava/util/List; public fun getUnknown ()Ljava/util/Map; public fun getVersion ()Ljava/lang/String; @@ -3186,9 +3202,11 @@ public final class io/sentry/protocol/SentryId$Deserializer : io/sentry/JsonDese public final class io/sentry/protocol/SentryPackage : io/sentry/JsonSerializable, io/sentry/JsonUnknown { public fun (Ljava/lang/String;Ljava/lang/String;)V + public fun equals (Ljava/lang/Object;)Z public fun getName ()Ljava/lang/String; public fun getUnknown ()Ljava/util/Map; public fun getVersion ()Ljava/lang/String; + public fun hashCode ()I public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V public fun setName (Ljava/lang/String;)V public fun setUnknown (Ljava/util/Map;)V diff --git a/sentry/src/main/java/io/sentry/Integration.java b/sentry/src/main/java/io/sentry/Integration.java index 54b17e4d51..110a8ea516 100644 --- a/sentry/src/main/java/io/sentry/Integration.java +++ b/sentry/src/main/java/io/sentry/Integration.java @@ -6,7 +6,7 @@ * Code that provides middlewares, bindings or hooks into certain frameworks or environments, along * with code that inserts those bindings and activates them. */ -public interface Integration { +public interface Integration extends IntegrationName { /** * Registers an integration * diff --git a/sentry/src/main/java/io/sentry/IntegrationName.java b/sentry/src/main/java/io/sentry/IntegrationName.java new file mode 100644 index 0000000000..585eea34d8 --- /dev/null +++ b/sentry/src/main/java/io/sentry/IntegrationName.java @@ -0,0 +1,15 @@ +package io.sentry; + +public interface IntegrationName { + default String getIntegrationName() { + return this.getClass() + .getSimpleName() + .replace("Sentry", "") + .replace("Integration", "") + .replace("Interceptor", ""); + } + + default void addIntegrationToSdkVersion() { + SentryIntegrationPackageStorage.getInstance().addIntegration(getIntegrationName()); + } +} diff --git a/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java b/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java index 8cd1fa350e..2646d9be39 100644 --- a/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java +++ b/sentry/src/main/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegration.java @@ -24,7 +24,7 @@ public interface SendFireAndForgetFactory { SendFireAndForget create(@NotNull IHub hub, @NotNull SentryOptions options); default boolean hasValidPath(final @Nullable String dirPath, final @NotNull ILogger logger) { - if (dirPath == null) { + if (dirPath == null || dirPath.isEmpty()) { logger.log(SentryLevel.INFO, "No cached dir path is defined in options."); return false; } @@ -87,6 +87,7 @@ public final void register(final @NotNull IHub hub, final @NotNull SentryOptions options .getLogger() .log(SentryLevel.DEBUG, "SendCachedEventFireAndForgetIntegration installed."); + addIntegrationToSdkVersion(); } catch (Throwable e) { options .getLogger() diff --git a/sentry/src/main/java/io/sentry/SentryIntegrationPackageStorage.java b/sentry/src/main/java/io/sentry/SentryIntegrationPackageStorage.java new file mode 100644 index 0000000000..e2ca7e9ac6 --- /dev/null +++ b/sentry/src/main/java/io/sentry/SentryIntegrationPackageStorage.java @@ -0,0 +1,75 @@ +package io.sentry; + +import io.sentry.protocol.SentryPackage; +import io.sentry.util.Objects; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; + +@ApiStatus.Internal +public final class SentryIntegrationPackageStorage { + private static volatile @Nullable SentryIntegrationPackageStorage INSTANCE; + + public static @NotNull SentryIntegrationPackageStorage getInstance() { + if (INSTANCE == null) { + synchronized (SentryIntegrationPackageStorage.class) { + if (INSTANCE == null) { + INSTANCE = new SentryIntegrationPackageStorage(); + } + } + } + + return INSTANCE; + } + + /** + * List of integrations that are enabled in the SDK. _Optional._ + * + *

The list should have all enabled integrations, including default integrations. Default + * integrations are included because different SDK releases may contain different default + * integrations. + */ + private final Set integrations = new CopyOnWriteArraySet<>(); + + /** + * List of installed and loaded SDK packages. _Optional._ + * + *

A list of packages that were installed as part of this SDK or the activated integrations. + * Each package consists of a name in the format `source:identifier` and `version`. If the source + * is a Git repository, the `source` should be `git`, the identifier should be a checkout link and + * the version should be a Git reference (branch, tag or SHA). + */ + private final Set packages = new CopyOnWriteArraySet<>(); + + private SentryIntegrationPackageStorage() {} + + public void addIntegration(final @NotNull String integration) { + Objects.requireNonNull(integration, "integration is required."); + integrations.add(integration); + } + + public @NotNull Set getIntegrations() { + return integrations; + } + + public void addPackage(final @NotNull String name, final @NotNull String version) { + Objects.requireNonNull(name, "name is required."); + Objects.requireNonNull(version, "version is required."); + + SentryPackage newPackage = new SentryPackage(name, version); + packages.add(newPackage); + } + + public @NotNull Set getPackages() { + return packages; + } + + @TestOnly + public void clearStorage() { + integrations.clear(); + packages.clear(); + } +} diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index abc2492116..8679be6034 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -2139,6 +2139,7 @@ private SentryOptions(final boolean empty) { setSentryClientName(BuildConfig.SENTRY_JAVA_SDK_NAME + "/" + BuildConfig.VERSION_NAME); setSdkVersion(createSdkVersion()); + addPackageInfo(); } } @@ -2229,11 +2230,15 @@ public void merge(final @NotNull ExternalOptions options) { final SdkVersion sdkVersion = new SdkVersion(BuildConfig.SENTRY_JAVA_SDK_NAME, version); sdkVersion.setVersion(version); - sdkVersion.addPackage("maven:io.sentry:sentry", version); return sdkVersion; } + private void addPackageInfo() { + SentryIntegrationPackageStorage.getInstance() + .addPackage("maven:io.sentry:sentry", BuildConfig.VERSION_NAME); + } + public static final class Proxy { private @Nullable String host; private @Nullable String port; diff --git a/sentry/src/main/java/io/sentry/ShutdownHookIntegration.java b/sentry/src/main/java/io/sentry/ShutdownHookIntegration.java index e3c7a29f9b..c6a8785e46 100644 --- a/sentry/src/main/java/io/sentry/ShutdownHookIntegration.java +++ b/sentry/src/main/java/io/sentry/ShutdownHookIntegration.java @@ -33,6 +33,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio thread = new Thread(() -> hub.flush(options.getFlushTimeoutMillis())); runtime.addShutdownHook(thread); options.getLogger().log(SentryLevel.DEBUG, "ShutdownHookIntegration installed."); + addIntegrationToSdkVersion(); } else { options.getLogger().log(SentryLevel.INFO, "enableShutdownHook is disabled."); } diff --git a/sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java b/sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java index c13e6ce580..746be67971 100644 --- a/sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java +++ b/sentry/src/main/java/io/sentry/UncaughtExceptionHandlerIntegration.java @@ -81,6 +81,7 @@ public final void register(final @NotNull IHub hub, final @NotNull SentryOptions this.options .getLogger() .log(SentryLevel.DEBUG, "UncaughtExceptionHandlerIntegration installed."); + addIntegrationToSdkVersion(); } } diff --git a/sentry/src/main/java/io/sentry/instrumentation/file/FileIOSpanManager.java b/sentry/src/main/java/io/sentry/instrumentation/file/FileIOSpanManager.java index 224bb3bf09..0ace5d8b63 100644 --- a/sentry/src/main/java/io/sentry/instrumentation/file/FileIOSpanManager.java +++ b/sentry/src/main/java/io/sentry/instrumentation/file/FileIOSpanManager.java @@ -2,6 +2,7 @@ import io.sentry.IHub; import io.sentry.ISpan; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOptions; import io.sentry.SentryStackTraceFactory; import io.sentry.SpanStatus; @@ -40,6 +41,7 @@ final class FileIOSpanManager { this.options = options; this.stackTraceFactory = new SentryStackTraceFactory(options.getInAppExcludes(), options.getInAppIncludes()); + SentryIntegrationPackageStorage.getInstance().addIntegration("FileIO"); } /** diff --git a/sentry/src/main/java/io/sentry/protocol/SdkVersion.java b/sentry/src/main/java/io/sentry/protocol/SdkVersion.java index 2595287091..e8dda2e655 100644 --- a/sentry/src/main/java/io/sentry/protocol/SdkVersion.java +++ b/sentry/src/main/java/io/sentry/protocol/SdkVersion.java @@ -6,6 +6,7 @@ import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryLevel; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; @@ -14,6 +15,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,6 +47,7 @@ public final class SdkVersion implements JsonUnknown, JsonSerializable { *

Examples: `0.1.0`, `1.0.0`, `4.3.12` */ private @NotNull String version; + /** * List of installed and loaded SDK packages. _Optional._ * @@ -51,7 +56,7 @@ public final class SdkVersion implements JsonUnknown, JsonSerializable { * is a Git repository, the `source` should be `git`, the identifier should be a checkout link and * the version should be a Git reference (branch, tag or SHA). */ - private @Nullable List packages; + private @Nullable Set deserializedPackages; /** * List of integrations that are enabled in the SDK. _Optional._ * @@ -59,7 +64,7 @@ public final class SdkVersion implements JsonUnknown, JsonSerializable { * integrations are included because different SDK releases may contain different default * integrations. */ - private @Nullable List integrations; + private @Nullable Set deserializedIntegrations; @SuppressWarnings("unused") private @Nullable Map unknown; @@ -86,31 +91,51 @@ public void setName(final @NotNull String name) { } public void addPackage(final @NotNull String name, final @NotNull String version) { - Objects.requireNonNull(name, "name is required."); - Objects.requireNonNull(version, "version is required."); - - SentryPackage newPackage = new SentryPackage(name, version); - if (packages == null) { - packages = new ArrayList<>(); - } - packages.add(newPackage); + SentryIntegrationPackageStorage.getInstance().addPackage(name, version); } public void addIntegration(final @NotNull String integration) { - Objects.requireNonNull(integration, "integration is required."); - - if (integrations == null) { - integrations = new ArrayList<>(); - } - integrations.add(integration); + SentryIntegrationPackageStorage.getInstance().addIntegration(integration); } + /** + * Gets installed Sentry packages as list + * + * @deprecated use {@link SdkVersion#getPackageSet()} ()} + */ + @Deprecated public @Nullable List getPackages() { - return packages; + final Set packages = + deserializedPackages != null + ? deserializedPackages + : SentryIntegrationPackageStorage.getInstance().getPackages(); + return new CopyOnWriteArrayList<>(packages); + } + + public @NotNull Set getPackageSet() { + return deserializedPackages != null + ? deserializedPackages + : SentryIntegrationPackageStorage.getInstance().getPackages(); } + /** + * Gets installed Sentry integration names as list + * + * @deprecated use {@link SdkVersion#getIntegrationSet()} + */ + @Deprecated public @Nullable List getIntegrations() { - return integrations; + final Set integrations = + deserializedIntegrations != null + ? deserializedIntegrations + : SentryIntegrationPackageStorage.getInstance().getIntegrations(); + return new CopyOnWriteArrayList<>(integrations); + } + + public @NotNull Set getIntegrationSet() { + return deserializedIntegrations != null + ? deserializedIntegrations + : SentryIntegrationPackageStorage.getInstance().getIntegrations(); } /** @@ -164,10 +189,12 @@ public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) writer.beginObject(); writer.name(JsonKeys.NAME).value(name); writer.name(JsonKeys.VERSION).value(version); - if (packages != null && !packages.isEmpty()) { + Set packages = getPackageSet(); + Set integrations = getIntegrationSet(); + if (!packages.isEmpty()) { writer.name(JsonKeys.PACKAGES).value(logger, packages); } - if (integrations != null && !integrations.isEmpty()) { + if (!integrations.isEmpty()) { writer.name(JsonKeys.INTEGRATIONS).value(logger, integrations); } if (unknown != null) { @@ -240,8 +267,9 @@ public static final class Deserializer implements JsonDeserializer { } SdkVersion sdkVersion = new SdkVersion(name, version); - sdkVersion.packages = packages; - sdkVersion.integrations = integrations; + sdkVersion.deserializedPackages = new CopyOnWriteArraySet<>(packages); + sdkVersion.deserializedIntegrations = new CopyOnWriteArraySet<>(integrations); + sdkVersion.setUnknown(unknown); return sdkVersion; } diff --git a/sentry/src/main/java/io/sentry/protocol/SentryPackage.java b/sentry/src/main/java/io/sentry/protocol/SentryPackage.java index 0cb57e1489..a8ed584bd0 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryPackage.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryPackage.java @@ -46,6 +46,20 @@ public void setVersion(final @NotNull String version) { this.version = Objects.requireNonNull(version, "version is required."); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SentryPackage that = (SentryPackage) o; + return java.util.Objects.equals(name, that.name) + && java.util.Objects.equals(version, that.version); + } + + @Override + public int hashCode() { + return java.util.Objects.hash(name, version); + } + // JsonKeys public static final class JsonKeys { diff --git a/sentry/src/test/java/io/sentry/JsonSerializerTest.kt b/sentry/src/test/java/io/sentry/JsonSerializerTest.kt index 403dabef2a..cf54a1a749 100644 --- a/sentry/src/test/java/io/sentry/JsonSerializerTest.kt +++ b/sentry/src/test/java/io/sentry/JsonSerializerTest.kt @@ -380,13 +380,10 @@ class JsonSerializerTest { assertEquals("test", sdkInfo.name) assertEquals("1.2.3", sdkInfo.version) - assertNotNull(sdkInfo.integrations) - assertTrue(sdkInfo.integrations!!.any { it == "NdkIntegration" }) - - assertNotNull(sdkInfo.packages) + assertTrue(sdkInfo.integrationSet.contains("Ndk")) assertTrue( - sdkInfo.packages!!.any { + sdkInfo.packageSet.any { it.name == "io.sentry:maven:sentry-android-core" && it.version == "4.5.6" } ) @@ -420,13 +417,9 @@ class JsonSerializerTest { val sdkVersion = envelope.header.sdkVersion!! assertEquals(version.name, sdkVersion.name) assertEquals(version.version, sdkVersion.version) - - assertNotNull(sdkVersion.integrations) - assertTrue(sdkVersion.integrations!!.any { it == "TestIntegration" }) - - assertNotNull(sdkVersion.packages) + assertTrue(sdkVersion.integrationSet.any { it == "TestIntegration" }) assertTrue( - sdkVersion.packages!!.any { + sdkVersion.packageSet.any { it.name == "abc" && it.version == "4.5.6" } ) diff --git a/sentry/src/test/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegrationTest.kt b/sentry/src/test/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegrationTest.kt index 4de02848db..e1f6982748 100644 --- a/sentry/src/test/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegrationTest.kt +++ b/sentry/src/test/java/io/sentry/SendCachedEnvelopeFireAndForgetIntegrationTest.kt @@ -1,22 +1,30 @@ package io.sentry +import io.sentry.protocol.SdkVersion +import org.mockito.kotlin.any import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.verifyNoMoreInteractions +import org.mockito.kotlin.whenever import kotlin.test.Test import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertTrue class SendCachedEnvelopeFireAndForgetIntegrationTest { private class Fixture { var hub: IHub = mock() var logger: ILogger = mock() var options = SentryOptions() - var callback = mock() + var callback = mock().apply { + whenever(hasValidPath(any(), any())).thenCallRealMethod() + } init { options.setDebug(true) options.setLogger(logger) + options.sdkVersion = SdkVersion("test", "1.2.3") } fun getSut(): SendCachedEnvelopeFireAndForgetIntegration { @@ -50,7 +58,7 @@ class SendCachedEnvelopeFireAndForgetIntegrationTest { @Test fun `path is valid if not null or empty`() { fixture.getSut() - assertFalse(fixture.callback.hasValidPath("cache", fixture.logger)) + assertTrue(fixture.callback.hasValidPath("cache", fixture.logger)) } @Test @@ -62,6 +70,18 @@ class SendCachedEnvelopeFireAndForgetIntegrationTest { verifyNoMoreInteractions(fixture.hub) } + @Test + fun `sets SDKVersion Info`() { + fixture.options.cacheDirPath = "cache" + whenever(fixture.callback.create(any(), any())).thenReturn( + mock() + ) + val sut = fixture.getSut() + sut.register(fixture.hub, fixture.options) + assertNotNull(fixture.options.sdkVersion) + assert(fixture.options.sdkVersion!!.integrationSet.contains("SendCachedEnvelopeFireAndForget")) + } + private class CustomFactory : SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForgetFactory { override fun create(hub: IHub, options: SentryOptions): SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForget? { return null diff --git a/sentry/src/test/java/io/sentry/SentryOptionsTest.kt b/sentry/src/test/java/io/sentry/SentryOptionsTest.kt index 1197b83cb7..f1b3c004de 100644 --- a/sentry/src/test/java/io/sentry/SentryOptionsTest.kt +++ b/sentry/src/test/java/io/sentry/SentryOptionsTest.kt @@ -188,7 +188,7 @@ class SentryOptionsTest { assertEquals(BuildConfig.VERSION_NAME, sdkVersion.version) assertTrue( - sdkVersion.packages!!.any { + sdkVersion.packageSet.any { it.name == "maven:io.sentry:sentry" && it.version == BuildConfig.VERSION_NAME } diff --git a/sentry/src/test/java/io/sentry/ShutdownHookIntegrationTest.kt b/sentry/src/test/java/io/sentry/ShutdownHookIntegrationTest.kt index f7e3848cad..d6ce0ff043 100644 --- a/sentry/src/test/java/io/sentry/ShutdownHookIntegrationTest.kt +++ b/sentry/src/test/java/io/sentry/ShutdownHookIntegrationTest.kt @@ -9,6 +9,7 @@ import org.mockito.kotlin.whenever import kotlin.test.Test import kotlin.test.assertFails import kotlin.test.assertNotNull +import kotlin.test.assertTrue class ShutdownHookIntegrationTest { @@ -104,4 +105,15 @@ class ShutdownHookIntegrationTest { verify(fixture.runtime).removeShutdownHook(any()) } + + @Test + fun `Integration adds itself to integration list`() { + val integration = fixture.getSut() + + integration.register(fixture.hub, fixture.options) + + assertTrue( + fixture.options.sdkVersion!!.integrationSet.contains("ShutdownHook") + ) + } } diff --git a/sentry/src/test/java/io/sentry/protocol/SdkVersionSerializationTest.kt b/sentry/src/test/java/io/sentry/protocol/SdkVersionSerializationTest.kt index 8e49d8e128..ee3d72add9 100644 --- a/sentry/src/test/java/io/sentry/protocol/SdkVersionSerializationTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/SdkVersionSerializationTest.kt @@ -5,11 +5,15 @@ import io.sentry.ILogger import io.sentry.JsonObjectReader import io.sentry.JsonObjectWriter import io.sentry.JsonSerializable +import io.sentry.SentryIntegrationPackageStorage +import org.junit.Before import org.junit.Test import org.mockito.kotlin.mock import java.io.StringReader import java.io.StringWriter import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNull class SdkVersionSerializationTest { @@ -30,6 +34,11 @@ class SdkVersionSerializationTest { } private val fixture = Fixture() + @Before + fun clearIntegrationPackageStorage() { + SentryIntegrationPackageStorage.getInstance().clearStorage() + } + @Test fun serialize() { val expected = sanitizedFile("json/sdk_version.json") @@ -45,6 +54,18 @@ class SdkVersionSerializationTest { assertEquals(expectedJson, actualJson) } + @Test + fun deserializeIgnoresStoredIntegrationsAndPackages() { + SentryIntegrationPackageStorage.getInstance().addIntegration("testIntegration") + SentryIntegrationPackageStorage.getInstance().addPackage("testPackage", "0.0.1") + + val expectedJson = sanitizedFile("json/sdk_version.json") + val actual = deserialize(expectedJson) + + assertFalse(actual.integrationSet.contains("testIntegration")) + assertNull(actual.packageSet.firstOrNull { it.name == "testIntegration" }) + } + // Helper private fun sanitizedFile(path: String): String { diff --git a/sentry/src/test/resources/envelope_session_sdkversion.txt b/sentry/src/test/resources/envelope_session_sdkversion.txt index 970103c409..d16082bc8f 100644 --- a/sentry/src/test/resources/envelope_session_sdkversion.txt +++ b/sentry/src/test/resources/envelope_session_sdkversion.txt @@ -1,3 +1,3 @@ -{"sdk":{"name":"test","version":"1.2.3","integrations":["NdkIntegration"],"packages":[{"name":"io.sentry:maven:sentry-android-core","version":"4.5.6"}]}} +{"sdk":{"name":"test","version":"1.2.3","integrations":["Ndk"],"packages":[{"name":"io.sentry:maven:sentry-android-core","version":"4.5.6"}]}} {"content_type":"application/json","type":"session","length":306} {"sid":"c81d4e2e-bcf2-11e6-869b-7df92533d2db","did":"123","init":true,"started":"2020-02-07T14:16:00Z","status":"ok","seq":123456,"errors":2,"duration":6000.0,"timestamp":"2020-02-07T14:16:00Z","attrs":{"release":"io.sentry@1.0+123","environment":"debug","ip_address":"127.0.0.1","user_agent":"jamesBond"}}