Skip to content

Commit b8472b5

Browse files
committed
refactor: use kotlin api for exporters
1 parent 74851b9 commit b8472b5

15 files changed

Lines changed: 255 additions & 177 deletions

File tree

embrace-android-otel/src/main/kotlin/io/embrace/android/embracesdk/internal/otel/config/OtelSdkConfig.kt

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
package io.embrace.android.embracesdk.internal.otel.config
22

33
import io.embrace.android.embracesdk.internal.SystemInfo
4-
import io.embrace.android.embracesdk.internal.otel.logs.EmbraceOtelJavaLogRecordExporter
4+
import io.embrace.android.embracesdk.internal.otel.logs.DefaultLogRecordExporter
55
import io.embrace.android.embracesdk.internal.otel.logs.LogSink
66
import io.embrace.android.embracesdk.internal.otel.sdk.IdGenerator
7-
import io.embrace.android.embracesdk.internal.otel.spans.EmbraceOtelJavaSpanExporter
7+
import io.embrace.android.embracesdk.internal.otel.spans.DefaultSpanExporter
88
import io.embrace.android.embracesdk.internal.otel.spans.EmbraceSpanProcessor
99
import io.embrace.android.embracesdk.internal.otel.spans.SpanSink
1010
import io.embrace.android.embracesdk.internal.utils.EmbTrace
1111
import io.embrace.opentelemetry.kotlin.ExperimentalApi
1212
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaLogRecordExporter
1313
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanExporter
1414
import io.embrace.opentelemetry.kotlin.attributes.AttributeContainer
15+
import io.embrace.opentelemetry.kotlin.j2k.logging.export.OtelJavaLogRecordExporterAdapter
16+
import io.embrace.opentelemetry.kotlin.j2k.tracing.export.OtelJavaSpanExporterAdapter
17+
import io.embrace.opentelemetry.kotlin.logging.export.LogRecordExporter
18+
import io.embrace.opentelemetry.kotlin.tracing.export.SpanExporter
1519
import io.embrace.opentelemetry.kotlin.tracing.export.SpanProcessor
1620
import io.opentelemetry.semconv.ServiceAttributes
1721
import io.opentelemetry.semconv.incubating.AndroidIncubatingAttributes
@@ -71,14 +75,15 @@ class OtelSdkConfig(
7175
exportEnabled = false
7276
}
7377

74-
val otelJavaSpanExporter: OtelJavaSpanExporter by lazy {
75-
EmbraceOtelJavaSpanExporter(
78+
val spanExporter: SpanExporter by lazy {
79+
val externalExporter = if (externalSpanExporters.isNotEmpty()) {
80+
OtelJavaSpanExporter.composite(externalSpanExporters)
81+
} else {
82+
null
83+
}
84+
DefaultSpanExporter(
7685
spanSink = spanSink,
77-
externalSpanExporter = if (externalSpanExporters.isNotEmpty()) {
78-
OtelJavaSpanExporter.composite(externalSpanExporters)
79-
} else {
80-
null
81-
},
86+
externalSpanExporter = externalExporter?.let(::OtelJavaSpanExporterAdapter),
8287
exportCheck = exportCheck,
8388
)
8489
}
@@ -89,14 +94,15 @@ class OtelSdkConfig(
8994
)
9095
}
9196

92-
val otelJavaLogRecordExporter: OtelJavaLogRecordExporter by lazy {
93-
EmbraceOtelJavaLogRecordExporter(
97+
val logRecordExporter: LogRecordExporter by lazy {
98+
val externalExporter = if (externalLogExporters.isNotEmpty()) {
99+
OtelJavaLogRecordExporter.composite(externalLogExporters)
100+
} else {
101+
null
102+
}
103+
DefaultLogRecordExporter(
94104
logSink = logSink,
95-
externalLogRecordExporter = if (externalLogExporters.isNotEmpty()) {
96-
OtelJavaLogRecordExporter.composite(externalLogExporters)
97-
} else {
98-
null
99-
},
105+
externalLogRecordExporter = externalExporter?.let(::OtelJavaLogRecordExporterAdapter),
100106
exportCheck = exportCheck,
101107
)
102108
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.embrace.android.embracesdk.internal.otel.logs
2+
3+
import io.embrace.android.embracesdk.internal.otel.payload.toEmbracePayload
4+
import io.embrace.android.embracesdk.internal.otel.schema.PrivateSpan
5+
import io.embrace.android.embracesdk.internal.otel.sdk.StoreDataResult
6+
import io.embrace.opentelemetry.kotlin.ExperimentalApi
7+
import io.embrace.opentelemetry.kotlin.export.OperationResultCode
8+
import io.embrace.opentelemetry.kotlin.logging.export.LogRecordExporter
9+
import io.embrace.opentelemetry.kotlin.logging.model.ReadableLogRecord
10+
11+
/**
12+
* Exports the given log record to a [LogSink]
13+
*/
14+
@ExperimentalApi
15+
internal class DefaultLogRecordExporter(
16+
private val logSink: LogSink,
17+
private val externalLogRecordExporter: LogRecordExporter?,
18+
private val exportCheck: () -> Boolean,
19+
) : LogRecordExporter {
20+
21+
override fun export(telemetry: List<ReadableLogRecord>): OperationResultCode {
22+
if (!exportCheck()) {
23+
return OperationResultCode.Success
24+
}
25+
val result = logSink.storeLogs(telemetry.map(ReadableLogRecord::toEmbracePayload))
26+
if (externalLogRecordExporter != null && result == StoreDataResult.SUCCESS) {
27+
return externalLogRecordExporter.export(
28+
telemetry.filterNot {
29+
it.attributes.containsKey(PrivateSpan.key.name)
30+
}
31+
)
32+
}
33+
return when (result) {
34+
StoreDataResult.SUCCESS -> OperationResultCode.Success
35+
StoreDataResult.FAILURE -> OperationResultCode.Failure
36+
}
37+
}
38+
39+
override fun forceFlush(): OperationResultCode = OperationResultCode.Success
40+
override fun shutdown(): OperationResultCode = OperationResultCode.Success
41+
}

embrace-android-otel/src/main/kotlin/io/embrace/android/embracesdk/internal/otel/logs/EmbraceOtelJavaLogRecordExporter.kt

Lines changed: 0 additions & 39 deletions
This file was deleted.

embrace-android-otel/src/main/kotlin/io/embrace/android/embracesdk/internal/otel/payload/LogMapper.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package io.embrace.android.embracesdk.internal.otel.payload
22

33
import io.embrace.android.embracesdk.internal.payload.Attribute
44
import io.embrace.android.embracesdk.internal.payload.Log
5+
import io.embrace.opentelemetry.kotlin.ExperimentalApi
56
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaAttributes
67
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaLogRecordData
8+
import io.embrace.opentelemetry.kotlin.logging.model.ReadableLogRecord
79

810
@Suppress("DEPRECATION") // suppress for backwards compat
911
fun OtelJavaLogRecordData.toEmbracePayload(): Log {
@@ -19,5 +21,19 @@ fun OtelJavaLogRecordData.toEmbracePayload(): Log {
1921
)
2022
}
2123

24+
@OptIn(ExperimentalApi::class)
25+
fun ReadableLogRecord.toEmbracePayload(): Log {
26+
val isSpanContextValid = spanContext.isValid
27+
return Log(
28+
traceId = if (isSpanContextValid) spanContext.traceId else null,
29+
spanId = if (isSpanContextValid) spanContext.spanId else null,
30+
timeUnixNano = timestamp,
31+
severityNumber = severityNumber?.ordinal,
32+
severityText = severityText,
33+
body = body,
34+
attributes = attributes.map { (key, value) -> Attribute(key, value.toString()) }
35+
)
36+
}
37+
2238
fun OtelJavaAttributes.toEmbracePayload(): List<Attribute> =
2339
this.asMap().entries.map { Attribute(it.key.key, it.value.toString()) }

embrace-android-otel/src/main/kotlin/io/embrace/android/embracesdk/internal/otel/sdk/OtelExt.kt

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package io.embrace.android.embracesdk.internal.otel.sdk
22

3+
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
34
import io.embrace.android.embracesdk.internal.otel.attrs.EmbraceAttribute
45
import io.embrace.android.embracesdk.internal.otel.attrs.EmbraceAttributeKey
56
import io.embrace.android.embracesdk.internal.otel.attrs.asOtelAttributeKey
67
import io.embrace.android.embracesdk.internal.otel.payload.toEmbracePayload
78
import io.embrace.android.embracesdk.internal.otel.spans.EmbraceSpanData
89
import io.embrace.android.embracesdk.internal.otel.spans.EmbraceSpanData.Companion.fromEventData
910
import io.embrace.android.embracesdk.internal.otel.toOtelKotlin
11+
import io.embrace.android.embracesdk.internal.payload.Attribute
1012
import io.embrace.android.embracesdk.internal.payload.Link
1113
import io.embrace.android.embracesdk.internal.utils.isBlankish
14+
import io.embrace.android.embracesdk.spans.EmbraceSpanEvent
1215
import io.embrace.opentelemetry.kotlin.ExperimentalApi
1316
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaAttributeKey
1417
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaAttributes
@@ -17,6 +20,9 @@ import io.embrace.opentelemetry.kotlin.aliases.OtelJavaLinkData
1720
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaLogRecordBuilder
1821
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpan
1922
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanData
23+
import io.embrace.opentelemetry.kotlin.tracing.model.ReadableLink
24+
import io.embrace.opentelemetry.kotlin.tracing.model.ReadableSpan
25+
import io.embrace.opentelemetry.kotlin.tracing.model.ReadableSpanEvent
2026
import io.embrace.opentelemetry.kotlin.tracing.model.Span
2127

2228
/**
@@ -25,7 +31,7 @@ import io.embrace.opentelemetry.kotlin.tracing.model.Span
2531
fun OtelJavaAttributesBuilder.fromMap(
2632
attributes: Map<String, String>,
2733
internal: Boolean,
28-
limitsValidator: DataValidator
34+
limitsValidator: DataValidator,
2935
): OtelJavaAttributesBuilder {
3036
attributes.filter {
3137
limitsValidator.isAttributeValid(it.key, it.value, internal) || it.key.isValidLongValueAttribute()
@@ -90,5 +96,36 @@ fun OtelJavaSpanData.toEmbraceSpanData(): EmbraceSpanData = EmbraceSpanData(
9096
links = links.map { it.toEmbracePayload() }
9197
)
9298

99+
@OptIn(ExperimentalApi::class)
100+
fun ReadableSpan.toEmbracePayload(): EmbraceSpanData = EmbraceSpanData(
101+
traceId = spanContext.traceId,
102+
spanId = spanContext.spanId,
103+
parentSpanId = parent?.spanId,
104+
name = name,
105+
startTimeNanos = startTimestamp,
106+
endTimeNanos = endTimestamp ?: 0,
107+
status = status,
108+
events = events.mapNotNull(ReadableSpanEvent::toEmbracePayload),
109+
attributes = attributes.mapValues { it.value.toString() },
110+
links = links.map(ReadableLink::toEmbracePayload),
111+
)
112+
113+
@OptIn(ExperimentalApi::class)
114+
fun ReadableLink.toEmbracePayload(): Link = Link(
115+
spanId = spanContext.spanId,
116+
traceId = spanContext.traceId,
117+
attributes = attributes.map { Attribute(it.key, it.value.toString()) },
118+
isRemote = spanContext.isRemote
119+
)
120+
121+
@OptIn(ExperimentalApi::class)
122+
fun ReadableSpanEvent.toEmbracePayload(): EmbraceSpanEvent? {
123+
return EmbraceSpanEvent.create(
124+
name = name,
125+
timestampMs = timestamp.nanosToMillis(),
126+
attributes = attributes.mapValues { it.value.toString() },
127+
)
128+
}
129+
93130
fun OtelJavaAttributes.hasEmbraceAttribute(embraceAttribute: EmbraceAttribute): Boolean =
94131
asMap()[embraceAttribute.key.asOtelAttributeKey()] == embraceAttribute.value

embrace-android-otel/src/main/kotlin/io/embrace/android/embracesdk/internal/otel/sdk/OtelSdkWrapper.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import io.embrace.opentelemetry.kotlin.Clock
1313
import io.embrace.opentelemetry.kotlin.ExperimentalApi
1414
import io.embrace.opentelemetry.kotlin.OpenTelemetry
1515
import io.embrace.opentelemetry.kotlin.OpenTelemetryInstance
16-
import io.embrace.opentelemetry.kotlin.j2k.logging.export.OtelJavaLogRecordExporterAdapter
17-
import io.embrace.opentelemetry.kotlin.j2k.tracing.export.OtelJavaSpanExporterAdapter
1816
import io.embrace.opentelemetry.kotlin.kotlinApi
1917
import io.embrace.opentelemetry.kotlin.tracing.Tracer
2018

@@ -48,9 +46,7 @@ class OtelSdkWrapper(
4846
loggerProvider = {
4947
resource(configuration.resourceAction)
5048
addLogRecordProcessor(
51-
DefaultLogRecordProcessor(
52-
OtelJavaLogRecordExporterAdapter(configuration.otelJavaLogRecordExporter)
53-
)
49+
DefaultLogRecordProcessor(configuration.logRecordExporter)
5450
)
5551
},
5652
tracerProvider = {
@@ -62,7 +58,7 @@ class OtelSdkWrapper(
6258
}
6359
addSpanProcessor(
6460
DefaultSpanProcessor(
65-
OtelJavaSpanExporterAdapter(configuration.otelJavaSpanExporter),
61+
configuration.spanExporter,
6662
configuration.processIdentifier
6763
)
6864
)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package io.embrace.android.embracesdk.internal.otel.spans
2+
3+
import io.embrace.android.embracesdk.internal.otel.schema.PrivateSpan
4+
import io.embrace.android.embracesdk.internal.otel.sdk.StoreDataResult
5+
import io.embrace.android.embracesdk.internal.otel.sdk.toEmbracePayload
6+
import io.embrace.android.embracesdk.internal.utils.EmbTrace
7+
import io.embrace.opentelemetry.kotlin.ExperimentalApi
8+
import io.embrace.opentelemetry.kotlin.export.OperationResultCode
9+
import io.embrace.opentelemetry.kotlin.tracing.export.SpanExporter
10+
import io.embrace.opentelemetry.kotlin.tracing.model.ReadableSpan
11+
12+
/**
13+
* Exports the given completed span to the given [SpanSink] as well as any configured external exporter
14+
*/
15+
@ExperimentalApi
16+
internal class DefaultSpanExporter(
17+
private val spanSink: SpanSink,
18+
private val externalSpanExporter: SpanExporter?,
19+
private val exportCheck: () -> Boolean,
20+
) : SpanExporter {
21+
22+
@Synchronized
23+
override fun export(telemetry: List<ReadableSpan>): OperationResultCode {
24+
if (!exportCheck()) {
25+
return OperationResultCode.Success
26+
}
27+
val result = spanSink.storeCompletedSpans(telemetry.map(ReadableSpan::toEmbracePayload))
28+
if (externalSpanExporter != null && result == StoreDataResult.SUCCESS) {
29+
return EmbTrace.trace("otel-external-export") {
30+
externalSpanExporter.export(
31+
telemetry.filterNot {
32+
it.attributes.containsKey(PrivateSpan.key.name)
33+
}
34+
)
35+
}
36+
}
37+
return when (result) {
38+
StoreDataResult.SUCCESS -> OperationResultCode.Success
39+
StoreDataResult.FAILURE -> OperationResultCode.Failure
40+
}
41+
}
42+
43+
override fun forceFlush(): OperationResultCode = OperationResultCode.Success
44+
45+
@Synchronized
46+
override fun shutdown(): OperationResultCode = OperationResultCode.Success
47+
}

embrace-android-otel/src/main/kotlin/io/embrace/android/embracesdk/internal/otel/spans/EmbraceOtelJavaSpanExporter.kt

Lines changed: 0 additions & 40 deletions
This file was deleted.

embrace-android-otel/src/main/kotlin/io/embrace/android/embracesdk/internal/otel/spans/SpanSink.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package io.embrace.android.embracesdk.internal.otel.spans
33
import io.embrace.android.embracesdk.internal.otel.sdk.StoreDataResult
44

55
/**
6-
* A service that stores all the spans that are completed and exported via [EmbraceOtelJavaSpanExporter],
6+
* A service that stores all the spans that are completed and exported via an exporter,
77
* and provides access to them so they
88
* can be sent off-device at the appropriate cadence.
99
*/

0 commit comments

Comments
 (0)