Skip to content

Commit 3851375

Browse files
authored
Reimplement fix to pass down params when creating span via OTel API (#2595)
1 parent 9267b07 commit 3851375

File tree

7 files changed

+109
-10
lines changed

7 files changed

+109
-10
lines changed

buildSrc/src/main/kotlin/io/embrace/internal/LintConfig.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ fun LibraryExtension.configureLint(project: Project) {
1010
checkAllWarnings = true
1111
checkReleaseBuilds = false // run on CI instead, speeds up release builds
1212
baseline = project.file("lint-baseline.xml")
13-
disable.addAll(setOf("GradleDependency", "NewerVersionAvailable"))
13+
disable.addAll(setOf("GradleDependency", "NewerVersionAvailable", "AndroidGradlePluginVersion"))
1414
}
1515
}

embrace-android-otel/src/main/kotlin/io/embrace/android/embracesdk/internal/otel/impl/EmbTracer.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,27 @@ class EmbTracer(
4141
private = false,
4242
tracer = impl,
4343
parentCtx = parentCtx,
44+
spanKind = spanKind,
45+
startTimeMs = startTimestamp,
4446
objectCreator = objectCreator,
4547
)
48+
var span: Span? = null
4649

4750
spanService.createSpan(spanCreator)?.let { embraceSpan ->
4851
if (embraceSpan.start()) {
49-
return EmbSpan(
52+
span = EmbSpan(
5053
impl = embraceSpan,
5154
clock = clock,
5255
objectCreator = objectCreator,
5356
)
5457
}
5558
}
56-
return EmbInvalidSpan(objectCreator)
59+
val ref = span
60+
return if (ref == null) {
61+
EmbInvalidSpan(objectCreator)
62+
} else {
63+
action(ref)
64+
ref
65+
}
5766
}
5867
}

embrace-android-otel/src/test/kotlin/io/embrace/android/embracesdk/internal/otel/impl/EmbTracerTest.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import io.embrace.android.embracesdk.fakes.FakeTracer
77
import io.embrace.android.embracesdk.fakes.fakeObjectCreator
88
import io.embrace.android.embracesdk.internal.otel.schema.EmbType
99
import io.embrace.opentelemetry.kotlin.ExperimentalApi
10+
import io.embrace.opentelemetry.kotlin.tracing.model.SpanKind
1011
import org.junit.Assert.assertEquals
1112
import org.junit.Assert.assertNull
1213
import org.junit.Before
@@ -36,11 +37,35 @@ internal class EmbTracerTest {
3637
@Test
3738
fun `check span generated with default parameters`() {
3839
tracer.createSpan("foo").end()
40+
val now = clock.now()
3941
val fakeCreatedSpan = spanService.createdSpans.single()
4042
with(fakeCreatedSpan) {
4143
assertNull(parent)
4244
assertEquals("foo", name)
45+
assertEquals(SpanKind.INTERNAL, spanKind)
4346
assertEquals(EmbType.Performance.Default, type)
47+
assertEquals(now, spanStartTimeMs)
48+
}
49+
}
50+
51+
@Test
52+
fun `check span generated with non default parameters`() {
53+
val parentCtx = fakeObjectCreator.context.root()
54+
tracer.createSpan(
55+
"foo",
56+
parentContext = parentCtx,
57+
spanKind = SpanKind.CLIENT,
58+
startTimestamp = 700L
59+
) {
60+
setStringAttribute("foo", "bar")
61+
}
62+
val fakeCreatedSpan = spanService.createdSpans.single()
63+
with(fakeCreatedSpan) {
64+
assertEquals(parentCtx, parentContext)
65+
assertEquals("foo", name)
66+
assertEquals(SpanKind.CLIENT, spanKind)
67+
assertEquals("bar", attributes["foo"])
68+
assertEquals(700L, spanStartTimeMs)
4469
}
4570
}
4671
}

embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/ExternalTracerTest.kt

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import io.embrace.opentelemetry.kotlin.aliases.OtelJavaOpenTelemetry
1919
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpan
2020
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanContext
2121
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanData
22+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanKind
2223
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaStatusCode
2324
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaTracer
2425
import io.opentelemetry.context.Context
@@ -31,6 +32,7 @@ import org.junit.Before
3132
import org.junit.Rule
3233
import org.junit.Test
3334
import org.junit.runner.RunWith
35+
import java.util.concurrent.TimeUnit
3436

3537
@RunWith(AndroidJUnit4::class)
3638
internal class ExternalTracerTest {
@@ -171,6 +173,57 @@ internal class ExternalTracerTest {
171173
)
172174
}
173175

176+
@Test
177+
fun `otel span builder parameters propagated correctly`() {
178+
var startTimeMs: Long? = null
179+
var endTimeMs: Long? = null
180+
181+
testRule.runTest(
182+
preSdkStartAction = {
183+
setupExporter()
184+
},
185+
testCaseAction = {
186+
initializeTracer()
187+
recordSession {
188+
val pastTs = clock.now() - 100L
189+
startTimeMs = pastTs
190+
val spanBuilder = embTracer.spanBuilder("external-span").apply {
191+
setStartTimestamp(pastTs, TimeUnit.MILLISECONDS)
192+
setSpanKind(OtelJavaSpanKind.CLIENT)
193+
setAttribute("builder-attribute", "dope")
194+
}
195+
196+
val span = spanBuilder.startSpan()
197+
endTimeMs = clock.tick()
198+
span.end()
199+
}
200+
},
201+
assertAction = {
202+
val sessionMessage = getSingleSessionEnvelope()
203+
val spans = checkNotNull(sessionMessage.data.spans)
204+
val recordedSpans = spans.associateBy { it.name }
205+
val parent = checkNotNull(recordedSpans["external-span"])
206+
assertEmbraceSpanData(
207+
span = parent,
208+
expectedStartTimeMs = checkNotNull(startTimeMs),
209+
expectedEndTimeMs = checkNotNull(endTimeMs),
210+
expectedParentId = OtelIds.invalidSpanId,
211+
expectedCustomAttributes = mapOf("builder-attribute" to "dope")
212+
)
213+
214+
assertTrue("Timed out waiting for the span to be exported", spanExporter.awaitSpanExport(2))
215+
val exportedSpan: OtelJavaSpanData = spanExporter.exportedSpans.single { it.name == "external-span" }
216+
assertEquals(OtelJavaSpanKind.CLIENT, exportedSpan.kind)
217+
assertEquals(parent.toEmbracePayload(), exportedSpan.toEmbraceSpanData())
218+
with(exportedSpan.instrumentationScopeInfo) {
219+
assertEquals("external-tracer", name)
220+
assertEquals("1.0.0", version)
221+
assertNull(schemaUrl)
222+
}
223+
}
224+
)
225+
}
226+
174227
@Test
175228
fun `span with explicit parent`() {
176229
testRule.runTest(

embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeEmbraceSdkSpan.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import io.embrace.opentelemetry.kotlin.ExperimentalApi
3232
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaContext
3333
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpan
3434
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanContext
35+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanKind
3536
import io.embrace.opentelemetry.kotlin.context.Context
3637
import io.embrace.opentelemetry.kotlin.context.toOtelJavaContext
3738
import io.embrace.opentelemetry.kotlin.context.toOtelJavaContextKey
@@ -52,10 +53,11 @@ class FakeEmbraceSdkSpan(
5253
val private: Boolean = internal,
5354
override val autoTerminationMode: AutoTerminationMode = AutoTerminationMode.NONE,
5455
private val fakeClock: FakeClock = FakeClock(),
56+
override var spanKind: SpanKind = SpanKind.INTERNAL,
57+
var spanStartTimeMs: Long? = null
5558
) : EmbraceSdkSpan {
56-
5759
private var sdkSpan: OtelJavaSpan? = null
58-
var spanStartTimeMs: Long? = null
60+
5961
var spanEndTimeMs: Long? = null
6062
override var status: StatusData = StatusData.Unset
6163
var errorCode: ErrorCode? = null
@@ -82,10 +84,11 @@ class FakeEmbraceSdkSpan(
8284

8385
override fun start(startTimeMs: Long?): Boolean {
8486
if (!started()) {
85-
val timestampMs = startTimeMs ?: fakeClock.now()
87+
val timestampMs = startTimeMs ?: spanStartTimeMs ?: fakeClock.now()
8688
sdkSpan = FakeSpanBuilder(name)
8789
.setStartTimestamp(timestampMs, TimeUnit.MILLISECONDS)
8890
.setParent(parentContext.toOtelJavaContext())
91+
.setSpanKind(spanKind.toOtelJavaSpanKind())
8992
.startSpan()
9093
spanStartTimeMs = timestampMs
9194
}
@@ -199,8 +202,6 @@ class FakeEmbraceSdkSpan(
199202

200203
override fun name(): String = name
201204

202-
override val spanKind: SpanKind = SpanKind.INTERNAL
203-
204205
override fun events(): List<SpanEvent> {
205206
throw UnsupportedOperationException()
206207
}
@@ -216,6 +217,14 @@ class FakeEmbraceSdkSpan(
216217

217218
private fun started(): Boolean = sdkSpan != null
218219

220+
private fun SpanKind.toOtelJavaSpanKind(): OtelJavaSpanKind = when (this) {
221+
SpanKind.INTERNAL -> OtelJavaSpanKind.INTERNAL
222+
SpanKind.CLIENT -> OtelJavaSpanKind.CLIENT
223+
SpanKind.SERVER -> OtelJavaSpanKind.SERVER
224+
SpanKind.PRODUCER -> OtelJavaSpanKind.PRODUCER
225+
SpanKind.CONSUMER -> OtelJavaSpanKind.CONSUMER
226+
}
227+
219228
companion object {
220229
fun notStarted(): FakeEmbraceSdkSpan = FakeEmbraceSdkSpan(name = "not-started")
221230

embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeSpanService.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import io.embrace.android.embracesdk.spans.ErrorCode
1212
import io.embrace.opentelemetry.kotlin.ExperimentalApi
1313
import io.embrace.opentelemetry.kotlin.context.toOtelJavaContext
1414
import io.embrace.opentelemetry.kotlin.context.toOtelKotlinContext
15+
import io.embrace.opentelemetry.kotlin.tracing.model.SpanKind
1516

1617
@OptIn(ExperimentalApi::class)
1718
class FakeSpanService : SpanService {
@@ -44,7 +45,7 @@ class FakeSpanService : SpanService {
4445
}
4546

4647
override fun createSpan(
47-
otelSpanStartArgs: OtelSpanStartArgs
48+
otelSpanStartArgs: OtelSpanStartArgs,
4849
): EmbraceSdkSpan {
4950
return FakeEmbraceSdkSpan(
5051
name = otelSpanStartArgs.initialSpanName,
@@ -53,6 +54,8 @@ class FakeSpanService : SpanService {
5354
internal = otelSpanStartArgs.internal,
5455
private = otelSpanStartArgs.embraceAttributes.contains(PrivateSpan),
5556
autoTerminationMode = otelSpanStartArgs.autoTerminationMode,
57+
spanKind = otelSpanStartArgs.spanKind ?: SpanKind.INTERNAL,
58+
spanStartTimeMs = otelSpanStartArgs.startTimeMs
5659
).apply {
5760
createdSpans.add(this)
5861
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ org.gradle.caching=true
55
org.gradle.configuration-cache=true
66
org.gradle.configuration-cache.problems=fail
77
org.gradle.configuration-cache.parallel=true
8-
version=7.9.1
8+
version=7.9.2
99
android.useAndroidX=true
1010
android.experimental.enableArtProfiles=true
1111
android.defaults.buildfeatures.buildconfig=false

0 commit comments

Comments
 (0)