Skip to content

Commit bed0d61

Browse files
Merge pull request #2153 from embrace-io/integration/kotlin-otel-api
Integration branch for Kotlin OTel API
2 parents e38b3e4 + b79c2d2 commit bed0d61

File tree

151 files changed

+2002
-1633
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

151 files changed

+2002
-1633
lines changed

embrace-android-api/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ android {
1717
dependencies {
1818
compileOnly(platform(libs.opentelemetry.bom))
1919
compileOnly(libs.opentelemetry.api)
20-
compileOnly(libs.opentelemetry.sdk)
2120
implementation(libs.lifecycle.process)
21+
implementation(libs.opentelemetry.java.aliases)
2222
}

embrace-android-api/src/main/kotlin/io/embrace/android/embracesdk/internal/api/OTelApi.kt

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package io.embrace.android.embracesdk.internal.api
22

33
import io.embrace.android.embracesdk.annotation.InternalApi
4-
import io.opentelemetry.api.OpenTelemetry
5-
import io.opentelemetry.api.common.AttributeKey
6-
import io.opentelemetry.api.trace.Tracer
7-
import io.opentelemetry.sdk.logs.export.LogRecordExporter
8-
import io.opentelemetry.sdk.resources.Resource
9-
import io.opentelemetry.sdk.trace.export.SpanExporter
4+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaAttributeKey
5+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaLogRecordExporter
6+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaOpenTelemetry
7+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanExporter
108

119
/**
1210
* Methods that enable integration with the the large OTel ecosystem through standard OTel APIs and concepts.
@@ -17,26 +15,26 @@ public interface OTelApi {
1715
/**
1816
* Add a [LogRecordExporter] that OTel Logs will be exported to after logging
1917
*/
20-
public fun addLogRecordExporter(logRecordExporter: LogRecordExporter)
18+
public fun addLogRecordExporter(logRecordExporter: OtelJavaLogRecordExporter)
2119

2220
/**
2321
* Adds a [SpanExporter] that OTel Spans will be exported to after completion
2422
*/
25-
public fun addSpanExporter(spanExporter: SpanExporter)
23+
public fun addSpanExporter(spanExporter: OtelJavaSpanExporter)
2624

2725
/**
2826
* Returns an [OpenTelemetry] that provides working [Tracer] implementations that will record spans that fit into the Embrace data
2927
* model.
3028
*/
31-
public fun getOpenTelemetry(): OpenTelemetry
29+
public fun getOpenTelemetry(): OtelJavaOpenTelemetry
3230

3331
/**
3432
* Set an attribute on the [Resource] used by the OTel SDK instance with the given [AttributeKey] key and String value.
3533
* The value set will override any value set previously or by the Embrace SDK.
3634
* This must be called before the SDK is started in order for it to take effect.
3735
*/
3836
public fun setResourceAttribute(
39-
key: AttributeKey<String>,
37+
key: OtelJavaAttributeKey<String>,
4038
value: String
4139
): Unit = setResourceAttribute(key.key, value)
4240

embrace-android-api/src/main/kotlin/io/embrace/android/embracesdk/spans/EmbraceSpan.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.embrace.android.embracesdk.spans
22

3-
import io.opentelemetry.api.common.Attributes
4-
import io.opentelemetry.api.trace.SpanContext
3+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanContext
54

65
/**
76
* Represents a Span that can be started and stopped with the appropriate [ErrorCode] if applicable. This wraps the OpenTelemetry Span
@@ -12,7 +11,7 @@ public interface EmbraceSpan {
1211
/**
1312
* The [SpanContext] for this [EmbraceSpan] instance. This is null if the span has not been started.
1413
*/
15-
public val spanContext: SpanContext?
14+
public val spanContext: OtelJavaSpanContext?
1615

1716
/**
1817
* ID of the Trace that this Span belongs to. The format adheres to the OpenTelemetry standard for Trace IDs
@@ -141,7 +140,7 @@ public interface EmbraceSpan {
141140
* Add a link to the span with the given [SpanContext]
142141
*/
143142
public fun addLink(
144-
linkedSpanContext: SpanContext
143+
linkedSpanContext: OtelJavaSpanContext
145144
): Boolean = addLink(linkedSpanContext = linkedSpanContext, attributes = null)
146145

147146
/**
@@ -159,5 +158,5 @@ public interface EmbraceSpan {
159158
/**
160159
* Add a link to the span with the given [SpanContext] with the given attributes
161160
*/
162-
public fun addLink(linkedSpanContext: SpanContext, attributes: Map<String, String>?): Boolean
161+
public fun addLink(linkedSpanContext: OtelJavaSpanContext, attributes: Map<String, String>?): Boolean
163162
}

embrace-android-core/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ dependencies {
4343
implementation(libs.lifecycle.process)
4444
implementation(libs.okhttp)
4545

46+
implementation(libs.opentelemetry.kotlin.api)
47+
implementation(libs.opentelemetry.kotlin.api.ext)
48+
implementation(libs.opentelemetry.kotlin.compat)
49+
implementation(libs.opentelemetry.java.aliases)
50+
4651
testImplementation(platform(libs.opentelemetry.bom))
4752
testImplementation(libs.opentelemetry.api)
4853
testImplementation(libs.opentelemetry.sdk)
Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
package io.embrace.android.embracesdk.internal.arch.destination
22

3+
import io.embrace.android.embracesdk.Severity
34
import io.embrace.android.embracesdk.internal.arch.schema.SchemaType
45
import io.embrace.android.embracesdk.internal.clock.Clock
5-
import io.embrace.android.embracesdk.internal.otel.attrs.asOtelAttributeKey
66
import io.embrace.android.embracesdk.internal.otel.attrs.embState
77
import io.embrace.android.embracesdk.internal.otel.schema.PrivateSpan
8-
import io.embrace.android.embracesdk.internal.otel.sdk.setAttribute
9-
import io.embrace.android.embracesdk.internal.otel.sdk.setEmbraceAttribute
10-
import io.embrace.android.embracesdk.internal.otel.sdk.toOtelSeverity
118
import io.embrace.android.embracesdk.internal.session.id.SessionIdTracker
129
import io.embrace.android.embracesdk.internal.session.lifecycle.EmbraceProcessStateService.Companion.BACKGROUND_STATE
1310
import io.embrace.android.embracesdk.internal.session.lifecycle.EmbraceProcessStateService.Companion.FOREGROUND_STATE
1411
import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateService
1512
import io.embrace.android.embracesdk.internal.utils.Uuid
16-
import io.opentelemetry.api.common.AttributeKey
17-
import io.opentelemetry.api.logs.Logger
18-
import io.opentelemetry.api.logs.Severity
13+
import io.embrace.opentelemetry.kotlin.ExperimentalApi
14+
import io.embrace.opentelemetry.kotlin.logging.Logger
15+
import io.embrace.opentelemetry.kotlin.logging.SeverityNumber
1916
import io.opentelemetry.semconv.incubating.LogIncubatingAttributes
2017
import io.opentelemetry.semconv.incubating.SessionIncubatingAttributes
2118
import java.util.concurrent.TimeUnit
2219

20+
@OptIn(ExperimentalApi::class)
2321
class LogWriterImpl(
2422
private val logger: Logger,
2523
private val sessionIdTracker: SessionIdTracker,
@@ -36,45 +34,49 @@ class LogWriterImpl(
3634
timestampMs: Long?,
3735
) {
3836
val logTimeMs = timestampMs ?: clock.now()
39-
val otelSeverity = severity.toOtelSeverity()
40-
val builder = logger.logRecordBuilder()
41-
.setBody(message)
42-
.setSeverity(otelSeverity)
43-
.setSeverityText(getSeverityText(otelSeverity))
44-
.setTimestamp(logTimeMs, TimeUnit.MILLISECONDS)
45-
46-
builder.setAttribute(LogIncubatingAttributes.LOG_RECORD_UID, Uuid.getEmbUuid())
37+
val severityNumber = when (severity) {
38+
Severity.INFO -> SeverityNumber.INFO
39+
Severity.WARNING -> SeverityNumber.WARN
40+
Severity.ERROR -> SeverityNumber.ERROR
41+
}
42+
logger.log(
43+
body = message,
44+
severityNumber = severityNumber,
45+
severityText = getSeverityText(severityNumber),
46+
timestampNs = TimeUnit.MILLISECONDS.toNanos(logTimeMs)
47+
) {
48+
setStringAttribute(LogIncubatingAttributes.LOG_RECORD_UID.key, Uuid.getEmbUuid())
4749

48-
if (addCurrentSessionInfo) {
49-
var sessionState: String? = null
50-
sessionIdTracker.getActiveSession()?.let { session ->
51-
builder.setAttribute(SessionIncubatingAttributes.SESSION_ID, session.id, false)
52-
sessionState = if (session.isForeground) {
53-
FOREGROUND_STATE
54-
} else {
55-
BACKGROUND_STATE
50+
if (addCurrentSessionInfo) {
51+
var sessionState: String? = null
52+
sessionIdTracker.getActiveSession()?.let { session ->
53+
if (session.id.isNotBlank()) {
54+
setStringAttribute(SessionIncubatingAttributes.SESSION_ID.key, session.id)
55+
}
56+
sessionState = if (session.isForeground) {
57+
FOREGROUND_STATE
58+
} else {
59+
BACKGROUND_STATE
60+
}
5661
}
62+
setStringAttribute(embState.name, sessionState ?: processStateService.getAppState())
5763
}
5864

59-
builder.setAttribute(embState.asOtelAttributeKey(), sessionState ?: processStateService.getAppState())
60-
}
61-
62-
if (isPrivate) {
63-
builder.setEmbraceAttribute(PrivateSpan)
64-
}
65+
if (isPrivate) {
66+
setStringAttribute(PrivateSpan.key.name, PrivateSpan.value)
67+
}
6568

66-
with(schemaType) {
67-
builder.setEmbraceAttribute(telemetryType)
68-
attributes().forEach {
69-
builder.setAttribute(AttributeKey.stringKey(it.key), it.value)
69+
with(schemaType) {
70+
setStringAttribute(telemetryType.key.name, telemetryType.value)
71+
attributes().forEach {
72+
setStringAttribute(it.key, it.value)
73+
}
7074
}
7175
}
72-
73-
builder.emit()
7476
}
7577

76-
private fun getSeverityText(severity: Severity) = when (severity) {
77-
Severity.WARN -> "WARNING"
78+
private fun getSeverityText(severity: SeverityNumber) = when (severity) {
79+
SeverityNumber.WARN -> "WARNING"
7880
else -> severity.name
7981
}
8082
}

embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/EssentialServiceModuleImpl.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateServ
1818
import io.embrace.android.embracesdk.internal.utils.EmbTrace
1919
import io.embrace.android.embracesdk.internal.utils.Provider
2020
import io.embrace.android.embracesdk.internal.worker.Worker
21+
import io.embrace.opentelemetry.kotlin.ExperimentalApi
2122

23+
@OptIn(ExperimentalApi::class)
2224
class EssentialServiceModuleImpl(
2325
initModule: InitModule,
2426
configModule: ConfigModule,

embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package io.embrace.android.embracesdk.internal.injection
33
import io.embrace.android.embracesdk.internal.SystemInfo
44
import io.embrace.android.embracesdk.internal.clock.Clock
55
import io.embrace.android.embracesdk.internal.clock.NormalizedIntervalClock
6-
import io.embrace.android.embracesdk.internal.clock.SystemClock
76
import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
87
import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
98
import io.embrace.android.embracesdk.internal.logging.EmbLogger
@@ -16,7 +15,7 @@ import io.embrace.android.embracesdk.internal.telemetry.EmbraceTelemetryService
1615
import io.embrace.android.embracesdk.internal.telemetry.TelemetryService
1716

1817
internal class InitModuleImpl(
19-
override val clock: Clock = NormalizedIntervalClock(systemClock = SystemClock()),
18+
override val clock: Clock = NormalizedIntervalClock(),
2019
override val logger: EmbLogger = EmbLoggerImpl(),
2120
override val systemInfo: SystemInfo = SystemInfo(),
2221
override val processIdentifierProvider: () -> String = IdGenerator.Companion::generateLaunchInstanceId,

embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModuleSupplier.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import android.content.Context
44
import io.embrace.android.embracesdk.internal.SystemInfo
55
import io.embrace.android.embracesdk.internal.clock.Clock
66
import io.embrace.android.embracesdk.internal.clock.NormalizedIntervalClock
7-
import io.embrace.android.embracesdk.internal.clock.SystemClock
87
import io.embrace.android.embracesdk.internal.logging.EmbLogger
98
import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl
109

@@ -17,7 +16,7 @@ typealias InitModuleSupplier = (
1716
) -> InitModule
1817

1918
fun createInitModule(
20-
clock: Clock = NormalizedIntervalClock(systemClock = SystemClock()),
19+
clock: Clock = NormalizedIntervalClock(),
2120
logger: EmbLogger = EmbLoggerImpl(),
2221
systemInfo: SystemInfo = SystemInfo(),
2322
): InitModule = InitModuleImpl(clock, logger, systemInfo)

embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ import io.embrace.android.embracesdk.internal.otel.spans.SpanSink
99
import io.embrace.android.embracesdk.internal.spans.CurrentSessionSpan
1010
import io.embrace.android.embracesdk.internal.spans.EmbraceTracer
1111
import io.embrace.android.embracesdk.internal.spans.InternalTracer
12-
import io.opentelemetry.api.OpenTelemetry
13-
import io.opentelemetry.api.logs.Logger
14-
import io.opentelemetry.api.trace.Tracer
15-
import io.opentelemetry.api.trace.TracerProvider
12+
import io.embrace.opentelemetry.kotlin.ExperimentalApi
13+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaClock
14+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaOpenTelemetry
15+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaTracerProvider
16+
import io.embrace.opentelemetry.kotlin.logging.Logger
17+
import io.embrace.opentelemetry.kotlin.tracing.Tracer
1618

1719
/**
1820
* Module that instantiates various OpenTelemetry related components
1921
*/
22+
@OptIn(ExperimentalApi::class)
2023
interface OpenTelemetryModule {
2124

2225
/**
@@ -74,17 +77,17 @@ interface OpenTelemetryModule {
7477
* Embrace APIs. Currently, only the APIs related [Tracer] have operational implementations. Every other method will return no-op
7578
* implementations that records no data.
7679
*/
77-
val externalOpenTelemetry: OpenTelemetry
80+
val externalOpenTelemetry: OtelJavaOpenTelemetry
7881

7982
/**
8083
* Provides [Tracer] instances for instrumentation external to the Embrace SDK to create spans
8184
*/
82-
val externalTracerProvider: TracerProvider
85+
val externalTracerProvider: OtelJavaTracerProvider
8386

8487
/**
8588
* OpenTelemetry SDK compatible clock based on the internal Embrace clock instance
8689
*/
87-
val openTelemetryClock: io.opentelemetry.sdk.common.Clock
90+
val openTelemetryClock: OtelJavaClock
8891

8992
/**
9093
* Setup configuration configuration-dependent behavior

embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModuleImpl.kt

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import io.embrace.android.embracesdk.core.BuildConfig
44
import io.embrace.android.embracesdk.internal.config.behavior.REDACTED_LABEL
55
import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehavior
66
import io.embrace.android.embracesdk.internal.otel.config.OtelSdkConfig
7-
import io.embrace.android.embracesdk.internal.otel.impl.EmbClock
8-
import io.embrace.android.embracesdk.internal.otel.impl.EmbOpenTelemetry
9-
import io.embrace.android.embracesdk.internal.otel.impl.EmbTracerProvider
7+
import io.embrace.android.embracesdk.internal.otel.impl.EmbOtelJavaClock
8+
import io.embrace.android.embracesdk.internal.otel.impl.EmbOtelJavaOpenTelemetry
9+
import io.embrace.android.embracesdk.internal.otel.impl.EmbOtelJavaTracerProvider
1010
import io.embrace.android.embracesdk.internal.otel.logs.LogSink
1111
import io.embrace.android.embracesdk.internal.otel.logs.LogSinkImpl
1212
import io.embrace.android.embracesdk.internal.otel.sdk.DataValidator
@@ -23,15 +23,17 @@ import io.embrace.android.embracesdk.internal.spans.CurrentSessionSpanImpl
2323
import io.embrace.android.embracesdk.internal.spans.EmbraceTracer
2424
import io.embrace.android.embracesdk.internal.spans.InternalTracer
2525
import io.embrace.android.embracesdk.internal.utils.EmbTrace
26-
import io.opentelemetry.api.OpenTelemetry
27-
import io.opentelemetry.api.logs.Logger
28-
import io.opentelemetry.api.trace.Tracer
29-
import io.opentelemetry.api.trace.TracerProvider
30-
import io.opentelemetry.sdk.common.Clock
31-
26+
import io.embrace.opentelemetry.kotlin.ExperimentalApi
27+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaClock
28+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaOpenTelemetry
29+
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaTracerProvider
30+
import io.embrace.opentelemetry.kotlin.logging.Logger
31+
import io.embrace.opentelemetry.kotlin.tracing.Tracer
32+
33+
@OptIn(ExperimentalApi::class)
3234
internal class OpenTelemetryModuleImpl(
3335
private val initModule: InitModule,
34-
override val openTelemetryClock: Clock = EmbClock(
36+
override val openTelemetryClock: OtelJavaClock = EmbOtelJavaClock(
3537
embraceClock = initModule.clock
3638
),
3739
) : OpenTelemetryModule {
@@ -137,21 +139,25 @@ internal class OpenTelemetryModuleImpl(
137139
}
138140

139141
override val logger: Logger by lazy {
140-
otelSdkWrapper.getOpenTelemetryLogger()
142+
EmbTrace.trace("otel-logger-init") {
143+
otelSdkWrapper.kotlinApi.loggerProvider.getLogger(
144+
name = otelSdkConfig.sdkName
145+
)
146+
}
141147
}
142148

143149
override val logSink: LogSink by lazy {
144150
LogSinkImpl()
145151
}
146152

147-
override val externalOpenTelemetry: OpenTelemetry by lazy {
148-
EmbOpenTelemetry(
153+
override val externalOpenTelemetry: OtelJavaOpenTelemetry by lazy {
154+
EmbOtelJavaOpenTelemetry(
149155
traceProviderSupplier = { externalTracerProvider }
150156
)
151157
}
152158

153-
override val externalTracerProvider: TracerProvider by lazy {
154-
EmbTracerProvider(
159+
override val externalTracerProvider: OtelJavaTracerProvider by lazy {
160+
EmbOtelJavaTracerProvider(
155161
sdkTracerProvider = otelSdkWrapper.sdkTracerProvider,
156162
spanService = spanService,
157163
clock = openTelemetryClock,

0 commit comments

Comments
 (0)