diff --git a/android-agent/build.gradle.kts b/android-agent/build.gradle.kts index 25d79a3d0..59bef257e 100644 --- a/android-agent/build.gradle.kts +++ b/android-agent/build.gradle.kts @@ -11,6 +11,7 @@ dependencies { api(project(":core")) implementation(project(":common")) implementation(libs.opentelemetry.instrumentation.api) + implementation(libs.opentelemetry.exporter.otlp) // Default instrumentations: api(project(":instrumentation:activity")) diff --git a/android-agent/src/main/kotlin/io/opentelemetry/android/agent/OpenTelemetryRumInitializer.kt b/android-agent/src/main/kotlin/io/opentelemetry/android/agent/OpenTelemetryRumInitializer.kt new file mode 100644 index 000000000..81bff83bf --- /dev/null +++ b/android-agent/src/main/kotlin/io/opentelemetry/android/agent/OpenTelemetryRumInitializer.kt @@ -0,0 +1,73 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.agent + +import android.app.Application +import io.opentelemetry.android.OpenTelemetryRum +import io.opentelemetry.android.OpenTelemetryRumBuilder +import io.opentelemetry.android.agent.connectivity.EndpointConnectivity +import io.opentelemetry.android.agent.connectivity.HttpEndpointConnectivity +import io.opentelemetry.android.config.OtelRumConfig +import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter +import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter + +object OpenTelemetryRumInitializer { + /** + * Opinionated [OpenTelemetryRum] initialization. + * + * @param application Your android app's application object. + * @param endpointBaseUrl The base endpoint for exporting all your signals. + * @param endpointHeaders These will be added to each signal export request. + * @param spanEndpointConnectivity Span-specific endpoint configuration. + * @param logEndpointConnectivity Log-specific endpoint configuration. + * @param metricEndpointConnectivity Metric-specific endpoint configuration. + * @param rumConfig Configuration used by [OpenTelemetryRumBuilder]. + */ + @JvmStatic + fun initialize( + application: Application, + endpointBaseUrl: String, + endpointHeaders: Map = emptyMap(), + spanEndpointConnectivity: EndpointConnectivity = + HttpEndpointConnectivity.forTraces( + endpointBaseUrl, + endpointHeaders, + ), + logEndpointConnectivity: EndpointConnectivity = + HttpEndpointConnectivity.forLogs( + endpointBaseUrl, + endpointHeaders, + ), + metricEndpointConnectivity: EndpointConnectivity = + HttpEndpointConnectivity.forMetrics( + endpointBaseUrl, + endpointHeaders, + ), + rumConfig: OtelRumConfig = OtelRumConfig(), + ): OpenTelemetryRum = + OpenTelemetryRum + .builder(application, rumConfig) + .addSpanExporterCustomizer { + OtlpHttpSpanExporter + .builder() + .setEndpoint(spanEndpointConnectivity.getUrl()) + .setHeaders(spanEndpointConnectivity::getHeaders) + .build() + }.addLogRecordExporterCustomizer { + OtlpHttpLogRecordExporter + .builder() + .setEndpoint(logEndpointConnectivity.getUrl()) + .setHeaders(logEndpointConnectivity::getHeaders) + .build() + }.addMetricExporterCustomizer { + OtlpHttpMetricExporter + .builder() + .setEndpoint(metricEndpointConnectivity.getUrl()) + .setHeaders(metricEndpointConnectivity::getHeaders) + .build() + }.build() +} diff --git a/android-agent/src/main/kotlin/io/opentelemetry/android/agent/connectivity/EndpointConnectivity.kt b/android-agent/src/main/kotlin/io/opentelemetry/android/agent/connectivity/EndpointConnectivity.kt new file mode 100644 index 000000000..1dc11456b --- /dev/null +++ b/android-agent/src/main/kotlin/io/opentelemetry/android/agent/connectivity/EndpointConnectivity.kt @@ -0,0 +1,12 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.agent.connectivity + +interface EndpointConnectivity { + fun getUrl(): String + + fun getHeaders(): Map +} diff --git a/android-agent/src/main/kotlin/io/opentelemetry/android/agent/connectivity/HttpEndpointConnectivity.kt b/android-agent/src/main/kotlin/io/opentelemetry/android/agent/connectivity/HttpEndpointConnectivity.kt new file mode 100644 index 000000000..3b181db4d --- /dev/null +++ b/android-agent/src/main/kotlin/io/opentelemetry/android/agent/connectivity/HttpEndpointConnectivity.kt @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.agent.connectivity + +class HttpEndpointConnectivity private constructor( + private val url: String, + private val headers: Map, +) : EndpointConnectivity { + companion object { + fun forTraces( + baseUrl: String, + headers: Map = emptyMap(), + ): HttpEndpointConnectivity = HttpEndpointConnectivity(baseUrl.trimEnd('/') + "/v1/traces", headers) + + fun forLogs( + baseUrl: String, + headers: Map = emptyMap(), + ): HttpEndpointConnectivity = HttpEndpointConnectivity(baseUrl.trimEnd('/') + "/v1/logs", headers) + + fun forMetrics( + baseUrl: String, + headers: Map = emptyMap(), + ): HttpEndpointConnectivity = HttpEndpointConnectivity(baseUrl.trimEnd('/') + "/v1/metrics", headers) + } + + override fun getUrl(): String = url + + override fun getHeaders(): Map = headers +} diff --git a/android-agent/src/test/kotlin/io/opentelemetry/android/agent/connectivity/HttpEndpointConnectivityTest.kt b/android-agent/src/test/kotlin/io/opentelemetry/android/agent/connectivity/HttpEndpointConnectivityTest.kt new file mode 100644 index 000000000..01e6a11f0 --- /dev/null +++ b/android-agent/src/test/kotlin/io/opentelemetry/android/agent/connectivity/HttpEndpointConnectivityTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.agent.connectivity + +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class HttpEndpointConnectivityTest { + @Test + fun `Validate exporter endpoint configuration`() { + val headers = mapOf("Authorization" to "Basic something") + val tracesConnectivity = HttpEndpointConnectivity.forTraces("http://some.endpoint", headers) + val logsConnectivity = HttpEndpointConnectivity.forLogs("http://some.endpoint/", headers) + val metricsConnectivity = + HttpEndpointConnectivity.forMetrics("http://some.endpoint", headers) + + assertThat(tracesConnectivity.getUrl()).isEqualTo("http://some.endpoint/v1/traces") + assertThat(tracesConnectivity.getHeaders()).isEqualTo(headers) + assertThat(logsConnectivity.getUrl()).isEqualTo("http://some.endpoint/v1/logs") + assertThat(logsConnectivity.getHeaders()).isEqualTo(headers) + assertThat(metricsConnectivity.getUrl()).isEqualTo("http://some.endpoint/v1/metrics") + assertThat(metricsConnectivity.getHeaders()).isEqualTo(headers) + } +} diff --git a/core/src/main/java/io/opentelemetry/android/OpenTelemetryRumBuilder.java b/core/src/main/java/io/opentelemetry/android/OpenTelemetryRumBuilder.java index 8a1f5413b..cfcaf1279 100644 --- a/core/src/main/java/io/opentelemetry/android/OpenTelemetryRumBuilder.java +++ b/core/src/main/java/io/opentelemetry/android/OpenTelemetryRumBuilder.java @@ -570,19 +570,16 @@ private SdkLoggerProvider buildLoggerProvider( } private SpanExporter buildSpanExporter() { - // TODO: Default to otlp...but how can we make endpoint and auth mandatory? SpanExporter defaultExporter = LoggingSpanExporter.create(); return spanExporterCustomizer.apply(defaultExporter); } private MetricExporter buildMetricExporter() { - // TODO: Default to otlp...but how can we make endpoint and auth mandatory? MetricExporter defaultExporter = LoggingMetricExporter.create(); return metricExporterCustomizer.apply(defaultExporter); } private LogRecordExporter buildLogsExporter() { - // TODO: Default to otlp...but how can we make endpoint and auth mandatory? LogRecordExporter defaultExporter = SystemOutLogRecordExporter.create(); return logRecordExporterCustomizer.apply(defaultExporter); } diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/OtelDemoApplication.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/OtelDemoApplication.kt index 26d1f3289..5c31a7b4a 100644 --- a/demo-app/src/main/java/io/opentelemetry/android/demo/OtelDemoApplication.kt +++ b/demo-app/src/main/java/io/opentelemetry/android/demo/OtelDemoApplication.kt @@ -9,18 +9,15 @@ import android.annotation.SuppressLint import android.app.Application import android.util.Log import io.opentelemetry.android.OpenTelemetryRum -import io.opentelemetry.android.OpenTelemetryRumBuilder +import io.opentelemetry.android.agent.OpenTelemetryRumInitializer import io.opentelemetry.android.config.OtelRumConfig import io.opentelemetry.android.features.diskbuffering.DiskBufferingConfig -import io.opentelemetry.android.instrumentation.sessions.SessionInstrumentation import io.opentelemetry.api.common.AttributeKey.stringKey import io.opentelemetry.api.common.Attributes import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder import io.opentelemetry.api.logs.LogRecordBuilder import io.opentelemetry.api.metrics.LongCounter import io.opentelemetry.api.trace.Tracer -import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter -import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter @@ -40,24 +37,8 @@ class OtelDemoApplication : Application() { .setDiskBufferingConfig(diskBufferingConfig) // 10.0.2.2 is apparently a special binding to the host running the emulator - val spansIngestUrl = "http://10.0.2.2:4318/v1/traces" - val logsIngestUrl = "http://10.0.2.2:4318/v1/logs" - val otelRumBuilder: OpenTelemetryRumBuilder = - OpenTelemetryRum.builder(this, config) - .addSpanExporterCustomizer { - OtlpHttpSpanExporter.builder() - .setEndpoint(spansIngestUrl) - .build() - } - .addLogRecordExporterCustomizer { - OtlpHttpLogRecordExporter.builder() - .setEndpoint(logsIngestUrl) - .build() - } - // TODO: This should NOT be necessary if it's in the runtime classpath... - .addInstrumentation(SessionInstrumentation()) try { - rum = otelRumBuilder.build() + rum = OpenTelemetryRumInitializer.initialize(this, "http://10.0.2.2:4318") Log.d(TAG, "RUM session started: " + rum!!.rumSessionId) } catch (e: Exception) { Log.e(TAG, "Oh no!", e)