Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
dbee518
add dependency on opentelemetry-kotlin-api
fractalwrench Apr 29, 2025
58cd029
poc: kotlin otel
fractalwrench Mar 27, 2025
fa7e170
use kotlin api for severity
fractalwrench Apr 30, 2025
db50c32
use kotlin api for status code
fractalwrench Apr 30, 2025
4b582e3
use kotlin api attribute key
fractalwrench Apr 30, 2025
47a5e56
refactor: small tweak to logger definition
fractalwrench May 1, 2025
492c074
Merge pull request #2141 from embrace-io/kotlin-otel-logging
fractalwrench May 2, 2025
375ae2a
Merge pull request #2145 from embrace-io/kotlin-otel-severity
fractalwrench May 2, 2025
61147e5
Merge branch 'add-kotlin-otel-dep' into integration/kotlin-otel-api
fractalwrench May 2, 2025
92c3cb2
Merge pull request #2146 from embrace-io/kotlin-otel-status-code
fractalwrench May 2, 2025
0de7e55
Merge pull request #2148 from embrace-io/kotlin-otel-attr-key
fractalwrench May 2, 2025
9e52942
Merge pull request #2155 from embrace-io/logger-refactor
fractalwrench May 2, 2025
831967f
Merge branch 'main' into integration/kotlin-otel-api
fractalwrench May 2, 2025
32a416c
fix compilation
fractalwrench May 2, 2025
1e0e50c
bump kotlin api dep
fractalwrench May 2, 2025
905a083
Merge branch 'main' into integration/kotlin-otel-api
fractalwrench May 6, 2025
559f873
Merge branch 'main' into integration/kotlin-otel-api
fractalwrench May 7, 2025
bdb6a00
refactor: reorganise span creation logic
fractalwrench May 7, 2025
98e940e
Merge pull request #2183 from embrace-io/refactor-span-builder-wrapper
fractalwrench May 7, 2025
e8311c8
Merge branch 'main' into integration/kotlin-otel-api
fractalwrench May 7, 2025
eb9c77f
Merge branch 'main' into integration/kotlin-otel-api
fractalwrench May 20, 2025
1ede78f
preparatory work for kotlin api
fractalwrench May 8, 2025
01f9ed5
Merge pull request #2198 from embrace-io/kotlin-api-additions
fractalwrench Jun 16, 2025
a0bebc5
Merge branch 'main' into integration/kotlin-otel-api
fractalwrench Jun 16, 2025
3183deb
Merge branch 'main' into integration/kotlin-otel-api
fractalwrench Jun 20, 2025
14d4c58
use opentelemetry-kotlin 0.1.2
fractalwrench Jun 20, 2025
9d1b4ed
refactor: use typealiases for opentelemetry-java
fractalwrench Jun 19, 2025
87f4a14
Merge pull request #2249 from embrace-io/otel-java-aliases
fractalwrench Jun 20, 2025
747873c
refactor: use opentelemetry-kotlin for tracer
fractalwrench Jun 19, 2025
fadd514
wip: fix context propagation
fractalwrench Jun 20, 2025
a2df8c4
test: fix react native tests
fractalwrench Jun 20, 2025
2b1f791
Merge pull request #2257 from embrace-io/fix-rn-tests
fractalwrench Jun 20, 2025
8db8cbc
Look for span otel span in context for parent
bidetofevil Jun 21, 2025
f28bc9e
Merge pull request #2250 from embrace-io/wip-convert-tracer
fractalwrench Jun 23, 2025
53c2158
Merge pull request #2259 from embrace-io/hho/otel-span-parent
fractalwrench Jun 23, 2025
cd99e02
Merge branch 'main' into integration/kotlin-otel-api
fractalwrench Jun 23, 2025
6572fde
Merge branch 'integration/kotlin-otel-api' into fix-context-propagation
fractalwrench Jun 23, 2025
74b0dc9
build: bump opentelemetry-kotlin to 0.1.3
fractalwrench Jun 23, 2025
e2c5e3c
Merge pull request #2255 from embrace-io/fix-context-propagation
fractalwrench Jun 23, 2025
c92e7ab
Merge branch 'main' into integration/kotlin-otel-api
fractalwrench Jun 24, 2025
b22e212
refactor: rename embrace otel java implementations
fractalwrench Jun 24, 2025
d25de17
build: remove unnecessary deps
fractalwrench Jun 24, 2025
d718205
refactor: remove unused clock in gradle plugin
fractalwrench Jun 24, 2025
3c34e27
refactor: simplify the clock implementation
fractalwrench Jun 24, 2025
65bc288
refactor: cleanup of unused functions
fractalwrench Jun 25, 2025
8033b27
refactor: create enum for result code
fractalwrench Jun 25, 2025
f3758e0
Merge pull request #2266 from embrace-io/rename-emb-implementations
fractalwrench Jun 25, 2025
b9779ba
Merge pull request #2267 from embrace-io/remove-unnecessary-deps
fractalwrench Jun 25, 2025
3c58fb4
Merge pull request #2268 from embrace-io/remove-unused-class
fractalwrench Jun 25, 2025
44da62a
Merge pull request #2270 from embrace-io/simplify-clock-impl
fractalwrench Jun 25, 2025
6dca77c
Merge pull request #2279 from embrace-io/cleanup-otel-module
fractalwrench Jun 25, 2025
085b59f
Merge pull request #2280 from embrace-io/otel-result-code
fractalwrench Jun 25, 2025
b79c2d2
Merge branch 'main' into integration/kotlin-otel-api
fractalwrench Jun 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion embrace-android-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ android {
dependencies {
compileOnly(platform(libs.opentelemetry.bom))
compileOnly(libs.opentelemetry.api)
compileOnly(libs.opentelemetry.sdk)
implementation(libs.lifecycle.process)
implementation(libs.opentelemetry.java.aliases)
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package io.embrace.android.embracesdk.internal.api

import io.embrace.android.embracesdk.annotation.InternalApi
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.sdk.logs.export.LogRecordExporter
import io.opentelemetry.sdk.resources.Resource
import io.opentelemetry.sdk.trace.export.SpanExporter
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaAttributeKey
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaLogRecordExporter
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaOpenTelemetry
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanExporter

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

/**
* Adds a [SpanExporter] that OTel Spans will be exported to after completion
*/
public fun addSpanExporter(spanExporter: SpanExporter)
public fun addSpanExporter(spanExporter: OtelJavaSpanExporter)

/**
* Returns an [OpenTelemetry] that provides working [Tracer] implementations that will record spans that fit into the Embrace data
* model.
*/
public fun getOpenTelemetry(): OpenTelemetry
public fun getOpenTelemetry(): OtelJavaOpenTelemetry

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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.embrace.android.embracesdk.spans

import io.opentelemetry.api.common.Attributes
import io.opentelemetry.api.trace.SpanContext
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaSpanContext

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

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

/**
Expand All @@ -159,5 +158,5 @@ public interface EmbraceSpan {
/**
* Add a link to the span with the given [SpanContext] with the given attributes
*/
public fun addLink(linkedSpanContext: SpanContext, attributes: Map<String, String>?): Boolean
public fun addLink(linkedSpanContext: OtelJavaSpanContext, attributes: Map<String, String>?): Boolean
}
5 changes: 5 additions & 0 deletions embrace-android-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ dependencies {
implementation(libs.lifecycle.process)
implementation(libs.okhttp)

implementation(libs.opentelemetry.kotlin.api)
implementation(libs.opentelemetry.kotlin.api.ext)
implementation(libs.opentelemetry.kotlin.compat)
implementation(libs.opentelemetry.java.aliases)

testImplementation(platform(libs.opentelemetry.bom))
testImplementation(libs.opentelemetry.api)
testImplementation(libs.opentelemetry.sdk)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
package io.embrace.android.embracesdk.internal.arch.destination

import io.embrace.android.embracesdk.Severity
import io.embrace.android.embracesdk.internal.arch.schema.SchemaType
import io.embrace.android.embracesdk.internal.clock.Clock
import io.embrace.android.embracesdk.internal.otel.attrs.asOtelAttributeKey
import io.embrace.android.embracesdk.internal.otel.attrs.embState
import io.embrace.android.embracesdk.internal.otel.schema.PrivateSpan
import io.embrace.android.embracesdk.internal.otel.sdk.setAttribute
import io.embrace.android.embracesdk.internal.otel.sdk.setEmbraceAttribute
import io.embrace.android.embracesdk.internal.otel.sdk.toOtelSeverity
import io.embrace.android.embracesdk.internal.session.id.SessionIdTracker
import io.embrace.android.embracesdk.internal.session.lifecycle.EmbraceProcessStateService.Companion.BACKGROUND_STATE
import io.embrace.android.embracesdk.internal.session.lifecycle.EmbraceProcessStateService.Companion.FOREGROUND_STATE
import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateService
import io.embrace.android.embracesdk.internal.utils.Uuid
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.logs.Logger
import io.opentelemetry.api.logs.Severity
import io.embrace.opentelemetry.kotlin.ExperimentalApi
import io.embrace.opentelemetry.kotlin.logging.Logger
import io.embrace.opentelemetry.kotlin.logging.SeverityNumber
import io.opentelemetry.semconv.incubating.LogIncubatingAttributes
import io.opentelemetry.semconv.incubating.SessionIncubatingAttributes
import java.util.concurrent.TimeUnit

@OptIn(ExperimentalApi::class)
class LogWriterImpl(
private val logger: Logger,
private val sessionIdTracker: SessionIdTracker,
Expand All @@ -36,45 +34,49 @@ class LogWriterImpl(
timestampMs: Long?,
) {
val logTimeMs = timestampMs ?: clock.now()
val otelSeverity = severity.toOtelSeverity()
val builder = logger.logRecordBuilder()
.setBody(message)
.setSeverity(otelSeverity)
.setSeverityText(getSeverityText(otelSeverity))
.setTimestamp(logTimeMs, TimeUnit.MILLISECONDS)

builder.setAttribute(LogIncubatingAttributes.LOG_RECORD_UID, Uuid.getEmbUuid())
val severityNumber = when (severity) {
Severity.INFO -> SeverityNumber.INFO
Severity.WARNING -> SeverityNumber.WARN
Severity.ERROR -> SeverityNumber.ERROR
}
logger.log(
body = message,
severityNumber = severityNumber,
severityText = getSeverityText(severityNumber),
timestampNs = TimeUnit.MILLISECONDS.toNanos(logTimeMs)
) {
setStringAttribute(LogIncubatingAttributes.LOG_RECORD_UID.key, Uuid.getEmbUuid())

if (addCurrentSessionInfo) {
var sessionState: String? = null
sessionIdTracker.getActiveSession()?.let { session ->
builder.setAttribute(SessionIncubatingAttributes.SESSION_ID, session.id, false)
sessionState = if (session.isForeground) {
FOREGROUND_STATE
} else {
BACKGROUND_STATE
if (addCurrentSessionInfo) {
var sessionState: String? = null
sessionIdTracker.getActiveSession()?.let { session ->
if (session.id.isNotBlank()) {
setStringAttribute(SessionIncubatingAttributes.SESSION_ID.key, session.id)
}
sessionState = if (session.isForeground) {
FOREGROUND_STATE
} else {
BACKGROUND_STATE
}
}
setStringAttribute(embState.name, sessionState ?: processStateService.getAppState())
}

builder.setAttribute(embState.asOtelAttributeKey(), sessionState ?: processStateService.getAppState())
}

if (isPrivate) {
builder.setEmbraceAttribute(PrivateSpan)
}
if (isPrivate) {
setStringAttribute(PrivateSpan.key.name, PrivateSpan.value)
}

with(schemaType) {
builder.setEmbraceAttribute(telemetryType)
attributes().forEach {
builder.setAttribute(AttributeKey.stringKey(it.key), it.value)
with(schemaType) {
setStringAttribute(telemetryType.key.name, telemetryType.value)
attributes().forEach {
setStringAttribute(it.key, it.value)
}
}
}

builder.emit()
}

private fun getSeverityText(severity: Severity) = when (severity) {
Severity.WARN -> "WARNING"
private fun getSeverityText(severity: SeverityNumber) = when (severity) {
SeverityNumber.WARN -> "WARNING"
else -> severity.name
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateServ
import io.embrace.android.embracesdk.internal.utils.EmbTrace
import io.embrace.android.embracesdk.internal.utils.Provider
import io.embrace.android.embracesdk.internal.worker.Worker
import io.embrace.opentelemetry.kotlin.ExperimentalApi

@OptIn(ExperimentalApi::class)
class EssentialServiceModuleImpl(
initModule: InitModule,
configModule: ConfigModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package io.embrace.android.embracesdk.internal.injection
import io.embrace.android.embracesdk.internal.SystemInfo
import io.embrace.android.embracesdk.internal.clock.Clock
import io.embrace.android.embracesdk.internal.clock.NormalizedIntervalClock
import io.embrace.android.embracesdk.internal.clock.SystemClock
import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.logging.EmbLogger
Expand All @@ -16,7 +15,7 @@ import io.embrace.android.embracesdk.internal.telemetry.EmbraceTelemetryService
import io.embrace.android.embracesdk.internal.telemetry.TelemetryService

internal class InitModuleImpl(
override val clock: Clock = NormalizedIntervalClock(systemClock = SystemClock()),
override val clock: Clock = NormalizedIntervalClock(),
override val logger: EmbLogger = EmbLoggerImpl(),
override val systemInfo: SystemInfo = SystemInfo(),
override val processIdentifierProvider: () -> String = IdGenerator.Companion::generateLaunchInstanceId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.content.Context
import io.embrace.android.embracesdk.internal.SystemInfo
import io.embrace.android.embracesdk.internal.clock.Clock
import io.embrace.android.embracesdk.internal.clock.NormalizedIntervalClock
import io.embrace.android.embracesdk.internal.clock.SystemClock
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl

Expand All @@ -17,7 +16,7 @@ typealias InitModuleSupplier = (
) -> InitModule

fun createInitModule(
clock: Clock = NormalizedIntervalClock(systemClock = SystemClock()),
clock: Clock = NormalizedIntervalClock(),
logger: EmbLogger = EmbLoggerImpl(),
systemInfo: SystemInfo = SystemInfo(),
): InitModule = InitModuleImpl(clock, logger, systemInfo)
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ import io.embrace.android.embracesdk.internal.otel.spans.SpanSink
import io.embrace.android.embracesdk.internal.spans.CurrentSessionSpan
import io.embrace.android.embracesdk.internal.spans.EmbraceTracer
import io.embrace.android.embracesdk.internal.spans.InternalTracer
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.logs.Logger
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.api.trace.TracerProvider
import io.embrace.opentelemetry.kotlin.ExperimentalApi
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaClock
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaOpenTelemetry
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaTracerProvider
import io.embrace.opentelemetry.kotlin.logging.Logger
import io.embrace.opentelemetry.kotlin.tracing.Tracer

/**
* Module that instantiates various OpenTelemetry related components
*/
@OptIn(ExperimentalApi::class)
interface OpenTelemetryModule {

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

/**
* Provides [Tracer] instances for instrumentation external to the Embrace SDK to create spans
*/
val externalTracerProvider: TracerProvider
val externalTracerProvider: OtelJavaTracerProvider

/**
* OpenTelemetry SDK compatible clock based on the internal Embrace clock instance
*/
val openTelemetryClock: io.opentelemetry.sdk.common.Clock
val openTelemetryClock: OtelJavaClock

/**
* Setup configuration configuration-dependent behavior
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import io.embrace.android.embracesdk.core.BuildConfig
import io.embrace.android.embracesdk.internal.config.behavior.REDACTED_LABEL
import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehavior
import io.embrace.android.embracesdk.internal.otel.config.OtelSdkConfig
import io.embrace.android.embracesdk.internal.otel.impl.EmbClock
import io.embrace.android.embracesdk.internal.otel.impl.EmbOpenTelemetry
import io.embrace.android.embracesdk.internal.otel.impl.EmbTracerProvider
import io.embrace.android.embracesdk.internal.otel.impl.EmbOtelJavaClock
import io.embrace.android.embracesdk.internal.otel.impl.EmbOtelJavaOpenTelemetry
import io.embrace.android.embracesdk.internal.otel.impl.EmbOtelJavaTracerProvider
import io.embrace.android.embracesdk.internal.otel.logs.LogSink
import io.embrace.android.embracesdk.internal.otel.logs.LogSinkImpl
import io.embrace.android.embracesdk.internal.otel.sdk.DataValidator
Expand All @@ -23,15 +23,17 @@ import io.embrace.android.embracesdk.internal.spans.CurrentSessionSpanImpl
import io.embrace.android.embracesdk.internal.spans.EmbraceTracer
import io.embrace.android.embracesdk.internal.spans.InternalTracer
import io.embrace.android.embracesdk.internal.utils.EmbTrace
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.logs.Logger
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.api.trace.TracerProvider
import io.opentelemetry.sdk.common.Clock

import io.embrace.opentelemetry.kotlin.ExperimentalApi
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaClock
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaOpenTelemetry
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaTracerProvider
import io.embrace.opentelemetry.kotlin.logging.Logger
import io.embrace.opentelemetry.kotlin.tracing.Tracer

@OptIn(ExperimentalApi::class)
internal class OpenTelemetryModuleImpl(
private val initModule: InitModule,
override val openTelemetryClock: Clock = EmbClock(
override val openTelemetryClock: OtelJavaClock = EmbOtelJavaClock(
embraceClock = initModule.clock
),
) : OpenTelemetryModule {
Expand Down Expand Up @@ -137,21 +139,25 @@ internal class OpenTelemetryModuleImpl(
}

override val logger: Logger by lazy {
otelSdkWrapper.getOpenTelemetryLogger()
EmbTrace.trace("otel-logger-init") {
otelSdkWrapper.kotlinApi.loggerProvider.getLogger(
name = otelSdkConfig.sdkName
)
}
}

override val logSink: LogSink by lazy {
LogSinkImpl()
}

override val externalOpenTelemetry: OpenTelemetry by lazy {
EmbOpenTelemetry(
override val externalOpenTelemetry: OtelJavaOpenTelemetry by lazy {
EmbOtelJavaOpenTelemetry(
traceProviderSupplier = { externalTracerProvider }
)
}

override val externalTracerProvider: TracerProvider by lazy {
EmbTracerProvider(
override val externalTracerProvider: OtelJavaTracerProvider by lazy {
EmbOtelJavaTracerProvider(
sdkTracerProvider = otelSdkWrapper.sdkTracerProvider,
spanService = spanService,
clock = openTelemetryClock,
Expand Down
Loading
Loading