Skip to content

Commit

Permalink
Add GraphQL Apollo Kotlin 4 integration (#4166)
Browse files Browse the repository at this point in the history
* Apollo 4 initial setup

* rename some stuff, change and add a few tests

* parametrize tests to run with both v3 and v4 implementations of `ApolloCall<D>::execute`

* changelog

* rename SentryApollo4BuilderExtensions back to SentryApolloBuilderExtensions to make it easier to migrate

* make api

* add README.md

* update comment

---------

Co-authored-by: Lukas Kusik <lukas.kusik@gmail.com>
  • Loading branch information
lcian and cvb941 authored Feb 24, 2025
1 parent 37b98dc commit c87d429
Show file tree
Hide file tree
Showing 27 changed files with 2,215 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- A list of active Spring profiles is attached to payloads sent to Sentry (errors, traces, etc.) and displayed in the UI when using our Spring or Spring Boot integrations ([#4147](https://github.com/getsentry/sentry-java/pull/4147))
- This consists of an empty list when only the default profile is active
- Move to a single NetworkCallback listener to reduce number of IPC calls on Android ([#4164](https://github.com/getsentry/sentry-java/pull/4164))
- Add GraphQL Apollo Kotlin 4 integration ([#4166](https://github.com/getsentry/sentry-java/pull/4166))

### Fixes

Expand Down
2 changes: 2 additions & 0 deletions buildSrc/src/main/java/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ object Config {
val composeCoil = "io.coil-kt:coil-compose:2.6.0"

val apolloKotlin = "com.apollographql.apollo3:apollo-runtime:3.8.2"
val apolloKotlin4 = "com.apollographql.apollo:apollo-runtime:4.1.1"

val sentryNativeNdk = "io.sentry:sentry-native-ndk:0.7.20"

Expand Down Expand Up @@ -250,6 +251,7 @@ object Config {
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_APOLLO4_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.apollo4"
val SENTRY_APOLLO_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.apollo"
val SENTRY_GRAPHQL_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.graphql"
val SENTRY_GRAPHQL22_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.graphql22"
Expand Down
5 changes: 5 additions & 0 deletions sentry-apollo-4/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# sentry-apollo-4

This module provides an integration for [Apollo Kotlin 4](https://www.apollographql.com/docs/kotlin/v4).

Please consult the documentation on how to install and use this integration in the Sentry Docs for [Android](https://docs.sentry.io/platforms/android/integrations/apollo4/) or [Java](https://docs.sentry.io/platforms/java/tracing/instrumentation/apollo4/).
50 changes: 50 additions & 0 deletions sentry-apollo-4/api/sentry-apollo-4.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
public final class io/sentry/apollo4/BuildConfig {
public static final field SENTRY_APOLLO4_SDK_NAME Ljava/lang/String;
public static final field VERSION_NAME Ljava/lang/String;
}

public final class io/sentry/apollo4/SentryApollo4ClientException : java/lang/Exception {
public static final field Companion Lio/sentry/apollo4/SentryApollo4ClientException$Companion;
public fun <init> (Ljava/lang/String;)V
}

public final class io/sentry/apollo4/SentryApollo4ClientException$Companion {
}

public final class io/sentry/apollo4/SentryApollo4HttpInterceptor : com/apollographql/apollo/network/http/HttpInterceptor {
public static final field Companion Lio/sentry/apollo4/SentryApollo4HttpInterceptor$Companion;
public static final field DEFAULT_CAPTURE_FAILED_REQUESTS Z
public fun <init> ()V
public fun <init> (Lio/sentry/IScopes;)V
public fun <init> (Lio/sentry/IScopes;Lio/sentry/apollo4/SentryApollo4HttpInterceptor$BeforeSpanCallback;)V
public fun <init> (Lio/sentry/IScopes;Lio/sentry/apollo4/SentryApollo4HttpInterceptor$BeforeSpanCallback;Z)V
public fun <init> (Lio/sentry/IScopes;Lio/sentry/apollo4/SentryApollo4HttpInterceptor$BeforeSpanCallback;ZLjava/util/List;)V
public synthetic fun <init> (Lio/sentry/IScopes;Lio/sentry/apollo4/SentryApollo4HttpInterceptor$BeforeSpanCallback;ZLjava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun intercept (Lcom/apollographql/apollo/api/http/HttpRequest;Lcom/apollographql/apollo/network/http/HttpInterceptorChain;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public abstract interface class io/sentry/apollo4/SentryApollo4HttpInterceptor$BeforeSpanCallback {
public abstract fun execute (Lio/sentry/ISpan;Lcom/apollographql/apollo/api/http/HttpRequest;Lcom/apollographql/apollo/api/http/HttpResponse;)Lio/sentry/ISpan;
}

public final class io/sentry/apollo4/SentryApollo4HttpInterceptor$Companion {
}

public final class io/sentry/apollo4/SentryApollo4Interceptor : com/apollographql/apollo/interceptor/ApolloInterceptor {
public fun <init> ()V
public fun <init> (Lio/sentry/IScopes;)V
public synthetic fun <init> (Lio/sentry/IScopes;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun intercept (Lcom/apollographql/apollo/api/ApolloRequest;Lcom/apollographql/apollo/interceptor/ApolloInterceptorChain;)Lkotlinx/coroutines/flow/Flow;
}

public final class io/sentry/apollo4/SentryApolloBuilderExtensionsKt {
public static final fun sentryTracing (Lcom/apollographql/apollo/ApolloClient$Builder;)Lcom/apollographql/apollo/ApolloClient$Builder;
public static final fun sentryTracing (Lcom/apollographql/apollo/ApolloClient$Builder;Lio/sentry/IScopes;)Lcom/apollographql/apollo/ApolloClient$Builder;
public static final fun sentryTracing (Lcom/apollographql/apollo/ApolloClient$Builder;Lio/sentry/IScopes;Z)Lcom/apollographql/apollo/ApolloClient$Builder;
public static final fun sentryTracing (Lcom/apollographql/apollo/ApolloClient$Builder;Lio/sentry/IScopes;ZLjava/util/List;)Lcom/apollographql/apollo/ApolloClient$Builder;
public static final fun sentryTracing (Lcom/apollographql/apollo/ApolloClient$Builder;Lio/sentry/IScopes;ZLjava/util/List;Lio/sentry/apollo4/SentryApollo4HttpInterceptor$BeforeSpanCallback;)Lcom/apollographql/apollo/ApolloClient$Builder;
public static final fun sentryTracing (Lcom/apollographql/apollo/ApolloClient$Builder;ZLjava/util/List;Lio/sentry/apollo4/SentryApollo4HttpInterceptor$BeforeSpanCallback;)Lcom/apollographql/apollo/ApolloClient$Builder;
public static synthetic fun sentryTracing$default (Lcom/apollographql/apollo/ApolloClient$Builder;Lio/sentry/IScopes;ZLjava/util/List;Lio/sentry/apollo4/SentryApollo4HttpInterceptor$BeforeSpanCallback;ILjava/lang/Object;)Lcom/apollographql/apollo/ApolloClient$Builder;
public static synthetic fun sentryTracing$default (Lcom/apollographql/apollo/ApolloClient$Builder;ZLjava/util/List;Lio/sentry/apollo4/SentryApollo4HttpInterceptor$BeforeSpanCallback;ILjava/lang/Object;)Lcom/apollographql/apollo/ApolloClient$Builder;
}

89 changes: 89 additions & 0 deletions sentry-apollo-4/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import net.ltgt.gradle.errorprone.errorprone
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
`java-library`
kotlin("jvm")
jacoco
id(Config.QualityPlugins.errorProne)
id(Config.QualityPlugins.gradleVersions)
id(Config.BuildPlugins.buildConfig) version Config.BuildPlugins.buildConfigVersion
}

configure<JavaPluginExtension> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString()
kotlinOptions.languageVersion = Config.kotlinCompatibleLanguageVersion
}

dependencies {
api(projects.sentry)
api(projects.sentryKotlinExtensions)

compileOnly(Config.Libs.apolloKotlin4)

compileOnly(Config.CompileOnly.nopen)
errorprone(Config.CompileOnly.nopenChecker)
errorprone(Config.CompileOnly.errorprone)
errorprone(Config.CompileOnly.errorProneNullAway)
compileOnly(Config.CompileOnly.jetbrainsAnnotations)

// tests
testImplementation(projects.sentryTestSupport)
testImplementation(Config.Libs.coroutinesCore)
testImplementation(kotlin(Config.kotlinStdLib))
testImplementation(Config.TestLibs.kotlinTestJunit)
testImplementation(Config.TestLibs.mockitoKotlin)
testImplementation(Config.TestLibs.mockitoInline)
testImplementation(Config.TestLibs.mockWebserver)
testImplementation(Config.Libs.apolloKotlin4)
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
testImplementation("org.jetbrains.kotlin:kotlin-reflect:2.0.0")
}

configure<SourceSetContainer> {
test {
java.srcDir("src/test/java")
}
}

jacoco {
toolVersion = Config.QualityPlugins.Jacoco.version
}

tasks.jacocoTestReport {
reports {
xml.required.set(true)
html.required.set(false)
}
}

tasks {
jacocoTestCoverageVerification {
violationRules {
rule { limit { minimum = Config.QualityPlugins.Jacoco.minimumCoverage } }
}
}
check {
dependsOn(jacocoTestCoverageVerification)
dependsOn(jacocoTestReport)
}
}

tasks.withType<JavaCompile>().configureEach {
options.errorprone {
check("NullAway", net.ltgt.gradle.errorprone.CheckSeverity.ERROR)
option("NullAway:AnnotatedPackages", "io.sentry")
}
}

buildConfig {
useJavaOutput()
packageName("io.sentry.apollo4")
buildConfigField("String", "SENTRY_APOLLO4_SDK_NAME", "\"${Config.Sentry.SENTRY_APOLLO4_SDK_NAME}\"")
buildConfigField("String", "VERSION_NAME", "\"${project.version}\"")
}
17 changes: 17 additions & 0 deletions sentry-apollo-4/src/main/java/io/sentry/apollo4/SentryApollo4.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.sentry.apollo4

/**
* Common constants used across the module
*/
internal const val OPERATION_ID_HEADER_NAME = "SENTRY-APOLLO-4-OPERATION-ID"
internal const val OPERATION_NAME_HEADER_NAME = "SENTRY-APOLLO-4-OPERATION-NAME"
internal const val OPERATION_TYPE_HEADER_NAME = "SENTRY-APOLLO-4-OPERATION-TYPE"
internal const val VARIABLES_HEADER_NAME = "SENTRY-APOLLO-4-VARIABLES"
internal val INTERNAL_HEADER_NAMES by lazy {
listOf(
OPERATION_ID_HEADER_NAME,
OPERATION_NAME_HEADER_NAME,
OPERATION_TYPE_HEADER_NAME,
VARIABLES_HEADER_NAME
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.sentry.apollo4

/**
* Used for holding an Apollo4 client error, for example. An integration that does not throw when API
* returns 4xx, 5xx or the `errors` field.
*/
class SentryApollo4ClientException(message: String?) : Exception(message) {
companion object {
private const val serialVersionUID = 4312160066430858144L
}
}
Loading

0 comments on commit c87d429

Please sign in to comment.