Skip to content

Commit ae7738c

Browse files
convert AttributeModifyingSpanExporter to Kotlin (#1334)
1 parent aaa296b commit ae7738c

File tree

7 files changed

+100
-158
lines changed

7 files changed

+100
-158
lines changed

core/api/core.api

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ public class io/opentelemetry/android/config/OtelRumConfig {
8383
public fun suppressInstrumentation (Ljava/lang/String;)Lio/opentelemetry/android/config/OtelRumConfig;
8484
}
8585

86-
public class io/opentelemetry/android/export/AttributeModifyingSpanExporter : io/opentelemetry/sdk/trace/export/SpanExporter {
87-
public fun <init> (Lio/opentelemetry/sdk/trace/export/SpanExporter;Ljava/util/Map;)V
86+
public final class io/opentelemetry/android/export/AttributeModifyingSpanExporter : io/opentelemetry/sdk/trace/export/SpanExporter {
87+
public fun <init> (Lio/opentelemetry/sdk/trace/export/SpanExporter;Lkotlin/jvm/functions/Function2;)V
8888
public fun export (Ljava/util/Collection;)Lio/opentelemetry/sdk/common/CompletableResultCode;
8989
public fun flush ()Lio/opentelemetry/sdk/common/CompletableResultCode;
9090
public fun shutdown ()Lio/opentelemetry/sdk/common/CompletableResultCode;

core/src/main/java/io/opentelemetry/android/export/AttributeModifyingSpanExporter.java

Lines changed: 0 additions & 81 deletions
This file was deleted.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.android.export
7+
8+
import io.opentelemetry.api.common.AttributeKey
9+
import io.opentelemetry.api.common.Attributes
10+
import io.opentelemetry.sdk.common.CompletableResultCode
11+
import io.opentelemetry.sdk.trace.data.SpanData
12+
import io.opentelemetry.sdk.trace.export.SpanExporter
13+
14+
typealias SpanAttributeReplacement = (AttributeKey<*>, Any?) -> Any?
15+
16+
/**
17+
* A SpanExporter that is configured to modify some of its attributes at export time.
18+
*/
19+
class AttributeModifyingSpanExporter(
20+
private val delegate: SpanExporter,
21+
private val spanAttributeReplacements: SpanAttributeReplacement,
22+
) : SpanExporter {
23+
override fun export(spans: Collection<SpanData>): CompletableResultCode = delegate.export(spans.map(::buildModifiedAttributes))
24+
25+
private fun buildModifiedAttributes(span: SpanData): ModifiedSpanData {
26+
val originals = span.attributes.asMap()
27+
val modified =
28+
originals.mapValues { entry ->
29+
spanAttributeReplacements(entry.key, entry.value)
30+
}
31+
32+
val builder = Attributes.builder()
33+
modified.forEach {
34+
@Suppress("UNCHECKED_CAST")
35+
builder.put(it.key as AttributeKey<Any>, it.value)
36+
}
37+
return ModifiedSpanData(span, builder.build())
38+
}
39+
40+
override fun flush(): CompletableResultCode = delegate.flush()
41+
42+
override fun shutdown(): CompletableResultCode = delegate.shutdown()
43+
}

core/src/main/java/io/opentelemetry/android/export/ModifiedSpanData.java

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.android.export
7+
8+
import io.opentelemetry.api.common.Attributes
9+
import io.opentelemetry.sdk.trace.data.DelegatingSpanData
10+
import io.opentelemetry.sdk.trace.data.SpanData
11+
12+
internal class ModifiedSpanData(
13+
original: SpanData,
14+
private val modifiedAttributes: Attributes,
15+
) : DelegatingSpanData(original) {
16+
override fun getAttributes(): Attributes = modifiedAttributes
17+
18+
override fun getTotalAttributeCount(): Int = modifiedAttributes.size()
19+
}

core/src/main/java/io/opentelemetry/android/export/SpanDataModifier.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,18 @@ public SpanExporter build() {
132132
if (!spanAttributeReplacements.isEmpty()) {
133133
modifier =
134134
new AttributeModifyingSpanExporter(
135-
delegate, new HashMap<>(spanAttributeReplacements));
135+
delegate,
136+
(attributeKey, value) -> {
137+
//noinspection unchecked
138+
Function<Object, Object> function =
139+
(Function<Object, Object>)
140+
spanAttributeReplacements.get(attributeKey);
141+
if (function != null) {
142+
return function.apply(value);
143+
} else {
144+
return value;
145+
}
146+
});
136147
}
137148
return FilteringSpanExporter.builder(modifier)
138149
.rejectSpansWithAttributesMatching(new HashMap<>(rejectSpanAttributesPredicates))

core/src/test/java/io/opentelemetry/android/export/AttributeModifyingSpanExporterTest.kt

Lines changed: 24 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,64 +10,44 @@ import io.opentelemetry.api.common.AttributeKey
1010
import io.opentelemetry.api.common.Attributes
1111
import io.opentelemetry.sdk.common.CompletableResultCode
1212
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions
13+
import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter
1314
import io.opentelemetry.sdk.trace.data.SpanData
14-
import io.opentelemetry.sdk.trace.export.SpanExporter
1515
import org.assertj.core.api.Assertions.assertThat
1616
import org.assertj.core.api.ThrowingConsumer
1717
import org.junit.jupiter.api.Assertions.assertSame
18+
import org.junit.jupiter.api.BeforeEach
1819
import org.junit.jupiter.api.Test
19-
import org.junit.jupiter.api.extension.ExtendWith
20-
import org.mockito.ArgumentCaptor
21-
import org.mockito.Captor
22-
import org.mockito.Mock
23-
import org.mockito.Mockito
24-
import org.mockito.Mockito.mock
25-
import org.mockito.Mockito.`when`
26-
import org.mockito.junit.jupiter.MockitoExtension
27-
import java.util.function.Function
2820

29-
@ExtendWith(MockitoExtension::class)
3021
internal class AttributeModifyingSpanExporterTest {
31-
@Mock
32-
private lateinit var exporter: SpanExporter
22+
private lateinit var exporter: InMemorySpanExporter
3323

34-
@Captor
35-
private lateinit var spansCaptor: ArgumentCaptor<MutableCollection<SpanData>>
24+
@BeforeEach
25+
fun setUp() {
26+
exporter = InMemorySpanExporter.create()
27+
}
3628

3729
@Test
3830
fun testEmptyMap() {
3931
val span1 = span("span1")
4032
val span2 = span("span2")
4133
val span3 = span("span3")
4234
val spans = listOf(span1, span2, span3)
43-
val expectedResult: CompletableResultCode? = mock(CompletableResultCode::class.java)
44-
`when`(exporter.export(spans)).thenReturn(expectedResult)
45-
46-
val underTest =
47-
AttributeModifyingSpanExporter(exporter, emptyMap())
35+
val underTest = AttributeModifyingSpanExporter(exporter) { _, value -> value }
4836

4937
val result = underTest.export(spans)
50-
assertSame(expectedResult, result)
38+
assertSame(CompletableResultCode.ofSuccess(), result)
5139
}
5240

5341
@Test
5442
fun testRemappedToNull() {
5543
val key = AttributeKey.stringKey("foo")
5644
val span1 = span("span1", Attributes.of(key, "bar"))
5745
val originalSpans = listOf(span1)
46+
val underTest = AttributeModifyingSpanExporter(exporter) { _, value -> null }
47+
val result = underTest.export(originalSpans)
5848

59-
val remappers = mutableMapOf<AttributeKey<*>, Function<*, *>>()
60-
remappers.put(key, Function { _: Any? -> null })
61-
62-
val expectedResult = Mockito.mock(CompletableResultCode::class.java)
63-
`when`(exporter.export(spansCaptor.capture()))
64-
.thenReturn(expectedResult)
65-
66-
val underTest =
67-
AttributeModifyingSpanExporter(exporter, remappers)
68-
69-
underTest.export(originalSpans)
70-
assertThat(spansCaptor.getValue())
49+
assertSame(CompletableResultCode.ofSuccess(), result)
50+
assertThat(exporter.finishedSpanItems)
7151
.satisfiesExactly(
7252
ThrowingConsumer { span: SpanData? ->
7353
OpenTelemetryAssertions
@@ -87,23 +67,23 @@ internal class AttributeModifyingSpanExporterTest {
8767
val attr3 = buildAttr(3)
8868
val span3 = span("span3", attr3)
8969
val spans = listOf(span1, span2, span3)
90-
val modifiers = mutableMapOf<AttributeKey<*>, Function<*, *>>()
91-
modifiers.put(AttributeKey.stringKey("foo1"), Function { x: Any? -> "" + x + x })
92-
modifiers.put(AttributeKey.stringKey("foo3"), Function { x: Any? -> "3$x$x" })
93-
modifiers.put(AttributeKey.stringKey("boop2"), Function { x: Any? -> "2$x$x" })
9470

95-
val expectedResult = Mockito.mock(CompletableResultCode::class.java)
96-
`when`(exporter.export(spansCaptor.capture()))
97-
.thenReturn(expectedResult)
98-
99-
val underTest = AttributeModifyingSpanExporter(exporter, modifiers)
71+
val underTest =
72+
AttributeModifyingSpanExporter(exporter) { key, value ->
73+
when (key) {
74+
AttributeKey.stringKey("foo1") -> "$value$value"
75+
AttributeKey.stringKey("foo3") -> "3$value$value"
76+
AttributeKey.stringKey("boop2") -> "2$value$value"
77+
else -> value
78+
}
79+
}
10080
val result = underTest.export(spans)
101-
assertSame(expectedResult, result)
81+
assertSame(CompletableResultCode.ofSuccess(), result)
10282
assertAttributes()
10383
}
10484

10585
private fun assertAttributes() {
106-
assertThat(spansCaptor.getValue())
86+
assertThat(exporter.finishedSpanItems)
10787
.satisfiesExactly(
10888
ThrowingConsumer {
10989
OpenTelemetryAssertions

0 commit comments

Comments
 (0)