Skip to content

Commit e0baf35

Browse files
authored
feat: adds otel-android HTTP instrumentation (#195)
## Summary Adds otel-android instrumentations for OkHTTP and URLConnection ## How did you test this change? Bench testing at this point. e2e instrumentation tests will be written once instrumentations stabilize.
1 parent e72871e commit e0baf35

4 files changed

Lines changed: 77 additions & 26 deletions

File tree

e2e/android/app/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ plugins {
22
alias(libs.plugins.android.application)
33
alias(libs.plugins.kotlin.android)
44
alias(libs.plugins.kotlin.compose)
5+
id("net.bytebuddy.byte-buddy-gradle-plugin") version "1.17.6"
56
}
67

78
android {
@@ -52,6 +53,15 @@ dependencies {
5253
implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.51.0")
5354
implementation("io.opentelemetry:opentelemetry-sdk-metrics:1.51.0")
5455

56+
// Android HTTP Url instrumentation
57+
implementation("io.opentelemetry.android.instrumentation:httpurlconnection-library:0.11.0-alpha")
58+
byteBuddy("io.opentelemetry.android.instrumentation:httpurlconnection-agent:0.11.0-alpha")
59+
60+
// OkHTTP instrumentation
61+
implementation("io.opentelemetry.android.instrumentation:okhttp3-library:0.11.0-alpha")
62+
byteBuddy("io.opentelemetry.android.instrumentation:okhttp3-agent:0.11.0-alpha")
63+
implementation("com.squareup.okhttp3:okhttp:4.12.0")
64+
5565
implementation("com.google.android.material:material:1.12.0")
5666
implementation(libs.androidx.core.ktx)
5767
implementation(libs.androidx.lifecycle.runtime.ktx)

e2e/android/app/src/main/java/com/example/androidobservability/MainActivity.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ class MainActivity : ComponentActivity() {
3737
) {
3838
Text("Go to Secondary Activity")
3939
}
40+
Button(
41+
onClick = {
42+
viewModel.triggerHttpRequests()
43+
}
44+
) {
45+
Text("Trigger HTTP Request")
46+
}
4047
Button(
4148
onClick = {
4249
viewModel.triggerMetric()
@@ -60,17 +67,10 @@ class MainActivity : ComponentActivity() {
6067
}
6168
Button(
6269
onClick = {
63-
viewModel.triggerStartSpan()
64-
}
65-
) {
66-
Text("Trigger Start Span")
67-
}
68-
Button(
69-
onClick = {
70-
viewModel.triggerStopSpan()
70+
viewModel.triggerNestedSpans()
7171
}
7272
) {
73-
Text("Trigger Stop Span")
73+
Text("Trigger Nested Spans")
7474
}
7575
Button(
7676
onClick = {
Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
package com.example.androidobservability
22

33
import androidx.lifecycle.ViewModel
4+
import androidx.lifecycle.viewModelScope
45
import com.launchdarkly.observability.interfaces.Metric
56
import com.launchdarkly.observability.sdk.LDObserve
6-
import com.launchdarkly.sdk.android.LDClient
77
import io.opentelemetry.api.common.AttributeKey
88
import io.opentelemetry.api.common.Attributes
99
import io.opentelemetry.api.logs.Severity
10-
import io.opentelemetry.api.trace.Span
11-
import java.net.SocketTimeoutException
10+
import kotlinx.coroutines.Dispatchers
11+
import kotlinx.coroutines.launch
12+
import okhttp3.OkHttpClient
13+
import okhttp3.Request
14+
import java.io.BufferedInputStream
15+
import java.net.HttpURLConnection
16+
import java.net.URL
1217

1318
class ViewModel : ViewModel() {
1419

15-
private var lastSpan: Span? = null
16-
1720
fun triggerMetric() {
1821
LDObserve.recordMetric(Metric("test", 50.0))
1922
}
@@ -33,20 +36,59 @@ class ViewModel : ViewModel() {
3336
)
3437
}
3538

36-
fun triggerStartSpan() {
37-
val newSpan = LDObserve.startSpan("FakeSpan", Attributes.empty())
38-
newSpan.makeCurrent()
39-
lastSpan = newSpan
40-
LDClient.get().boolVariation("my-boolean-flag", false)
41-
}
42-
43-
fun triggerStopSpan() {
44-
// TODO O11Y-397: for some reason stopped spans are stacking, the current span might be the problem
45-
lastSpan?.end()
46-
lastSpan = null
39+
fun triggerNestedSpans() {
40+
viewModelScope.launch(Dispatchers.IO) {
41+
val newSpan0 = LDObserve.startSpan("FakeSpan", Attributes.empty())
42+
newSpan0.makeCurrent().use {
43+
val newSpan1 = LDObserve.startSpan("FakeSpan1", Attributes.empty())
44+
newSpan1.makeCurrent().use {
45+
val newSpan2 = LDObserve.startSpan("FakeSpan2", Attributes.empty())
46+
newSpan2.makeCurrent().use {
47+
sendOkHttpRequest()
48+
sendURLRequest()
49+
newSpan2.end()
50+
}
51+
newSpan1.end()
52+
}
53+
newSpan0.end()
54+
}
55+
}
4756
}
4857

4958
fun triggerCrash() {
5059
throw RuntimeException("Failed to connect to bogus server.")
5160
}
61+
62+
fun triggerHttpRequests() {
63+
viewModelScope.launch(Dispatchers.IO) {
64+
sendOkHttpRequest()
65+
sendURLRequest()
66+
}
67+
}
68+
69+
private fun sendOkHttpRequest() {
70+
// Create HTTP client
71+
val client = OkHttpClient()
72+
73+
// Build request
74+
val request: Request = Request.Builder()
75+
.url("https://www.google.com")
76+
.build()
77+
78+
client.newCall(request).execute().use { response ->
79+
println("Response code: " + response.code)
80+
println("Response body: " + response.body?.string())
81+
}
82+
}
83+
84+
private fun sendURLRequest() {
85+
val url = URL("https://www.android.com/")
86+
val urlConnection = url.openConnection() as HttpURLConnection
87+
try {
88+
val output = BufferedInputStream(urlConnection.inputStream).bufferedReader().use { it.readText() }
89+
println("URLRequest output: $output")
90+
} finally {
91+
urlConnection.disconnect()
92+
}
93+
}
5294
}

sdk/@launchdarkly/observability-android/lib/src/main/kotlin/com/launchdarkly/observability/client/InstrumentationManager.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ class InstrumentationManager(
189189

190190
fun startSpan(name: String, attributes: Attributes): Span {
191191
return otelTracer.spanBuilder(name)
192-
.setParent(Context.current().with(Span.current()))
193192
.setAllAttributes(attributes)
194193
.startSpan()
195194
}

0 commit comments

Comments
 (0)