Skip to content

Commit

Permalink
RUM-3438 Add the OkHttp otel extensions module
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusc83 committed Jun 4, 2024
1 parent ee23810 commit 9e598bb
Show file tree
Hide file tree
Showing 19 changed files with 243 additions and 4 deletions.
1 change: 1 addition & 0 deletions features/dd-sdk-android-trace-otel/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ dependencies {
api(libs.openTelemetryApi)
implementation(libs.kotlin)
implementation(libs.androidXAnnotation)
implementation(libs.okHttp)

testImplementation(project(":tools:unit")) {
attributes {
Expand Down
18 changes: 18 additions & 0 deletions integrations/dd-sdk-android-okhttp-otel/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Built application files
*.apk
*.ap_
*.aab

# Files for the ART/Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/
out/

# Gradle files
build/
7 changes: 7 additions & 0 deletions integrations/dd-sdk-android-okhttp-otel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Datadog SDK OpenTelemetry extensions for OkHttp

See the dedicated [Datadog SDK instrumentation for OkHttp documentation][1] to learn how track network requests made by `OkHttp` library automatically.
See the dedicated [Datadog SDK Android for OpenTelemetry documentation][2] to learn how to add a parent span to network requests made by `OkHttp` library.

[1]: https://docs.datadoghq.com/real_user_monitoring/android/advanced_configuration/?tab=kotlin#automatically-track-network-requests
[2]: https://docs.datadoghq.com/tracing/trace_collection/custom_instrumentation/android?tab=kotlin
1 change: 1 addition & 0 deletions integrations/dd-sdk-android-okhttp-otel/api/apiSurface
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fun okhttp3.Request.Builder.addParentSpan(io.opentelemetry.api.trace.Span): okhttp3.Request.Builder
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public final class com/datadog/android/okhttp/otel/OkHttpExtKt {
public static final fun addParentSpan (Lokhttp3/Request$Builder;Lio/opentelemetry/api/trace/Span;)Lokhttp3/Request$Builder;
}

69 changes: 69 additions & 0 deletions integrations/dd-sdk-android-okhttp-otel/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

import com.datadog.gradle.config.androidLibraryConfig
import com.datadog.gradle.config.dependencyUpdateConfig
import com.datadog.gradle.config.javadocConfig
import com.datadog.gradle.config.junitConfig
import com.datadog.gradle.config.kotlinConfig
import com.datadog.gradle.config.publishingConfig
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
// Build
id("com.android.library")
kotlin("android")

// Publish
`maven-publish`
signing
id("org.jetbrains.dokka")

// Analysis tools
id("com.github.ben-manes.versions")

// Tests
id("de.mobilej.unmock")
id("org.jetbrains.kotlinx.kover")

// Internal Generation
id("thirdPartyLicences")
id("apiSurface")
id("transitiveDependencies")
id("binary-compatibility-validator")
}

android {
namespace = "com.datadog.android.okhttp.otel"
}

dependencies {
implementation(project(":integrations:dd-sdk-android-okhttp"))
implementation(project(":features:dd-sdk-android-trace-otel"))
implementation(libs.okHttp)
implementation(libs.kotlin)

testImplementation(project(":tools:unit")) {
attributes {
attribute(
com.android.build.api.attributes.ProductFlavorAttr.of("platform"),
objects.named("jvm")
)
}
}
testImplementation(libs.bundles.jUnit5)
testImplementation(libs.bundles.testTools)
testImplementation(libs.okHttpMock)
}

kotlinConfig(jvmBytecodeTarget = JvmTarget.JVM_11)
androidLibraryConfig()
junitConfig()
javadocConfig()
dependencyUpdateConfig()
publishingConfig(
"An OkHttp collection of extensions to be used in conjunction with OpenTelemetry Datadog SDK."
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.okhttp.otel

import com.datadog.android.okhttp.DdOtelContext
import com.datadog.trace.api.sampling.PrioritySampling
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.SpanContext
import okhttp3.Request

fun Request.Builder.addParentSpan(span: Span): Request.Builder {
val context = span.spanContext
val prioritySampling = resolveSamplingPriority(context)
tag(DdOtelContext::class.java, DdOtelContext(context.traceId, context.spanId, prioritySampling))
return this
}

private fun resolveSamplingPriority(context: SpanContext): Int {
return if (context.isSampled) PrioritySampling.SAMPLER_KEEP.toInt() else PrioritySampling.UNSET.toInt()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mock-maker-inline
14 changes: 14 additions & 0 deletions integrations/dd-sdk-android-okhttp-otel/transitiveDependencies
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Dependencies List

com.squareup.okhttp3:okhttp:4.11.0 : 768 Kb
com.squareup.okio:okio-jvm:3.2.0 : 337 Kb
io.opentelemetry:opentelemetry-api:1.4.0 : 78 Kb
io.opentelemetry:opentelemetry-context:1.4.0 : 42 Kb
org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 : 216 Kb
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 : 963 b
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 : 969 b
org.jetbrains.kotlin:kotlin-stdlib:1.8.22 : 1631 Kb
org.jetbrains:annotations:13.0 : 17 Kb

Total transitive dependencies size : 3 Mb

2 changes: 2 additions & 0 deletions integrations/dd-sdk-android-okhttp/api/apiSurface
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ open class com.datadog.android.okhttp.DatadogInterceptor : com.datadog.android.o
override fun onRequestIntercepted(com.datadog.android.api.feature.FeatureSdkCore, okhttp3.Request, io.opentracing.Span?, okhttp3.Response?, Throwable?)
override fun canSendSpan(): Boolean
override fun onSdkInstanceReady(com.datadog.android.core.InternalSdkCore)
data class com.datadog.android.okhttp.DdOtelContext
constructor(String, String, Int)
fun okhttp3.Request.Builder.parentSpan(io.opentracing.Span): okhttp3.Request.Builder
interface com.datadog.android.okhttp.trace.TracedRequestListener
fun onRequestIntercepted(okhttp3.Request, io.opentracing.Span, okhttp3.Response?, Throwable?)
Expand Down
15 changes: 15 additions & 0 deletions integrations/dd-sdk-android-okhttp/api/dd-sdk-android-okhttp.api
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,21 @@ public class com/datadog/android/okhttp/DatadogInterceptor : com/datadog/android
protected fun onRequestIntercepted (Lcom/datadog/android/api/feature/FeatureSdkCore;Lokhttp3/Request;Lio/opentracing/Span;Lokhttp3/Response;Ljava/lang/Throwable;)V
}

public final class com/datadog/android/okhttp/DdOtelContext {
public fun <init> (Ljava/lang/String;Ljava/lang/String;I)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()I
public final fun copy (Ljava/lang/String;Ljava/lang/String;I)Lcom/datadog/android/okhttp/DdOtelContext;
public static synthetic fun copy$default (Lcom/datadog/android/okhttp/DdOtelContext;Ljava/lang/String;Ljava/lang/String;IILjava/lang/Object;)Lcom/datadog/android/okhttp/DdOtelContext;
public fun equals (Ljava/lang/Object;)Z
public final fun getSamplingPriority ()I
public final fun getSpanId ()Ljava/lang/String;
public final fun getTraceId ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/datadog/android/okhttp/trace/OkHttpRequestExtKt {
public static final fun parentSpan (Lokhttp3/Request$Builder;Lio/opentracing/Span;)Lokhttp3/Request$Builder;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.okhttp

import com.datadog.android.lint.InternalApi

@InternalApi
data class DdOtelContext(
val traceId: String,
val spanId: String,
val samplingPriority: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.okhttp.internal.otel

import com.datadog.android.okhttp.DdOtelContext
import com.datadog.opentracing.propagation.ExtractedContext
import io.opentracing.SpanContext
import java.math.BigInteger

internal fun DdOtelContext.toOpenTracingContext(): SpanContext {
val traceIdAsBigInteger = BigInteger(traceId, 16)
val spanIdAsBigInteger = BigInteger(spanId, 16)
return ExtractedContext(
traceIdAsBigInteger,
spanIdAsBigInteger,
samplingPriority,
null,
emptyMap(),
emptyMap()
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import com.datadog.android.core.internal.net.DefaultFirstPartyHostHeaderTypeReso
import com.datadog.android.core.internal.utils.loggableStackTrace
import com.datadog.android.core.sampling.RateBasedSampler
import com.datadog.android.core.sampling.Sampler
import com.datadog.android.okhttp.DdOtelContext
import com.datadog.android.okhttp.internal.otel.toOpenTracingContext
import com.datadog.android.trace.AndroidTracer
import com.datadog.android.trace.TracingHeaderType
import com.datadog.legacy.trace.api.DDTags
Expand Down Expand Up @@ -432,6 +434,7 @@ internal constructor(

private fun extractParentContext(tracer: Tracer, request: Request): SpanContext? {
val tagContext = request.tag(Span::class.java)?.context()
?: request.tag(DdOtelContext::class.java)?.toOpenTracingContext()

val headerContext = tracer.extract(
Format.Builtin.TEXT_MAP_EXTRACT,
Expand Down
1 change: 1 addition & 0 deletions sample/kotlin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ dependencies {
implementation(project(":integrations:dd-sdk-android-sqldelight"))
implementation(project(":integrations:dd-sdk-android-compose"))
implementation(project(":integrations:dd-sdk-android-okhttp"))
implementation(project(":integrations:dd-sdk-android-okhttp-otel"))

// Desugaring SDK
coreLibraryDesugaring(libs.androidDesugaringSdk)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal class ViewModelFactory(
WebViewModel(localServer) as T
}
OtelTracesViewModel::class.java -> {
OtelTracesViewModel() as T
OtelTracesViewModel(okHttpClient, localServer) as T
}
else -> {
modelClass.newInstance()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ internal class OtelTracesFragment : Fragment(), View.OnClickListener {
return rootView
}

override fun onResume() {
super.onResume()
viewModel.onResume()
}

override fun onPause() {
viewModel.onPause()
super.onPause()
}

@Suppress("UnsafeCallOnNullableType") // not an issue in the sample
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,38 @@ package com.datadog.android.sample.traces
import android.os.AsyncTask
import androidx.lifecycle.ViewModel
import com.datadog.android.log.Logger
import com.datadog.android.okhttp.otel.addParentSpan
import com.datadog.android.sample.BuildConfig
import com.datadog.android.vendor.sample.LocalServer
import io.opentelemetry.api.GlobalOpenTelemetry
import io.opentelemetry.api.common.Attributes
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.context.Context
import io.opentelemetry.context.ContextKey
import io.opentelemetry.context.Scope
import okhttp3.OkHttpClient
import okhttp3.Request

@Suppress("DEPRECATION")
internal class OtelTracesViewModel : ViewModel() {
internal class OtelTracesViewModel(
private val okHttpClient: OkHttpClient,
private val localServer: LocalServer

) : ViewModel() {

private var asyncOperationTask: AsyncTask<Unit, Unit, Unit>? = null
private var chainedContextsTask: AsyncTask<Unit, Unit, Unit>? = null
private var linkedSpansTask: AsyncTask<Unit, Unit, Unit>? = null

fun onResume() {
localServer.start("https://www.datadoghq.com/")
}

fun onPause() {
localServer.stop()
}

fun startAsyncOperation(
onProgress: (Int) -> Unit = {},
onDone: () -> Unit = {}
Expand All @@ -34,7 +50,11 @@ internal class OtelTracesViewModel : ViewModel() {
}

fun startChainedContexts(onDone: () -> Unit = {}) {
chainedContextsTask = ChainedContextsTask(onDone)
chainedContextsTask = ChainedContextsTask(
localServer.getUrl(),
okHttpClient,
onDone
)
chainedContextsTask?.execute()
}

Expand Down Expand Up @@ -123,6 +143,8 @@ internal class OtelTracesViewModel : ViewModel() {
// region ChainedContextsTask

private class ChainedContextsTask(
private val url: String,
private val okHttpClient: OkHttpClient,
val onDone: () -> Unit
) : AsyncTask<Unit, Unit, Unit>() {
private val tracer: Tracer = GlobalOpenTelemetry.get()
Expand Down Expand Up @@ -167,7 +189,12 @@ internal class OtelTracesViewModel : ViewModel() {
logger.v("Sanitizing username: $username")
Thread.sleep(2000)
processingSanitization.end()
Thread.sleep(5000)
val request = Request.Builder()
.get()
.url(url)
.addParentSpan(processingFormSpan)
.build()
okHttpClient.newCall(request).execute()
formScope.close()
processingFormSpan.end()
}
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ include(":integrations:dd-sdk-android-sqldelight")
include(":integrations:dd-sdk-android-timber")
include(":integrations:dd-sdk-android-tv")
include(":integrations:dd-sdk-android-okhttp")
include(":integrations:dd-sdk-android-okhttp-otel")
include(":integrations:dd-sdk-android-rum-coroutines")
include(":integrations:dd-sdk-android-trace-coroutines")

Expand Down

0 comments on commit 9e598bb

Please sign in to comment.