Skip to content

Commit

Permalink
Initialization events (#397)
Browse files Browse the repository at this point in the history
* build first set of initialization events

* Rename .java to .kt

* swizzle to kotlin

* add tests for init events

* move init lower so that the specific exporter type can be evented

* Update instrumentation/startup/src/main/java/io/opentelemetry/android/instrumentation/startup/SdkInitializationEvents.kt

Co-authored-by: Manoel Aranda Neto <[email protected]>

* Update instrumentation/startup/src/main/java/io/opentelemetry/android/instrumentation/startup/SdkInitializationEvents.kt

Co-authored-by: Manoel Aranda Neto <[email protected]>

* leverage defaults and simplify

* clean up events class

---------

Co-authored-by: Manoel Aranda Neto <[email protected]>
  • Loading branch information
breedx-splk and marandaneto authored Jun 3, 2024
1 parent 8119edd commit e40aa81
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,11 @@ public final class OpenTelemetryRumBuilder {
private final OtelRumConfig config;
private final VisibleScreenTracker visibleScreenTracker = new VisibleScreenTracker();

private Function<? super SpanExporter, ? extends SpanExporter> spanExporterCustomizer = a -> a;
private final List<Consumer<InstrumentedApplication>> instrumentationInstallers =
new ArrayList<>();

private final List<Consumer<OpenTelemetrySdk>> otelSdkReadyListeners = new ArrayList<>();
private Function<? super SpanExporter, ? extends SpanExporter> spanExporterCustomizer = a -> a;
private Function<? super TextMapPropagator, ? extends TextMapPropagator> propagatorCustomizer =
(a) -> a;

Expand Down Expand Up @@ -325,6 +326,7 @@ OpenTelemetryRum build(ServiceManager serviceManager) {
Log.e(RumConstants.OTEL_RUM_LOG_TAG, "Could not initialize disk exporters.", e);
}
}
initializationEvents.spanExporterInitialized(spanExporter);

OpenTelemetrySdk sdk =
OpenTelemetrySdk.builder()
Expand Down Expand Up @@ -377,14 +379,30 @@ private void scheduleDiskTelemetryReader(
}
}

/**
* Adds a callback to be invoked after the OpenTelemetry SDK has been initialized. This can be
* used to defer some early lifecycle functionality until the working SDK is ready.
*
* @param callback - A callback that receives the OpenTelemetry SDK instance.
* @return this
*/
public OpenTelemetryRumBuilder addOtelSdkReadyListener(Consumer<OpenTelemetrySdk> callback) {
otelSdkReadyListeners.add(callback);
return this;
}

/** Leverage the configuration to wire up various instrumentation components. */
private void applyConfiguration() {
if (config.shouldGenerateSdkInitializationEvents()) {
if (initializationEvents == InitializationEvents.NO_OP) {
initializationEvents = new SdkInitializationEvents();
SdkInitializationEvents sdkInitEvents = new SdkInitializationEvents();
addOtelSdkReadyListener(sdkInitEvents::finish);
initializationEvents = sdkInitEvents;
}
Map<String, String> configMap = new HashMap<>();
// TODO: Convert config to map
// breedx-splk: Left incomplete for now, because I think Cesar is making changes around
// this
initializationEvents.recordConfiguration(configMap);
}
initializationEvents.sdkInitializationStarted();
Expand Down Expand Up @@ -491,7 +509,6 @@ private SdkTracerProvider buildTracerProvider(
.setResource(resource)
.addSpanProcessor(new SessionIdSpanAppender(sessionId));

initializationEvents.spanExporterInitialized(spanExporter);
BatchSpanProcessor batchSpanProcessor = BatchSpanProcessor.builder(spanExporter).build();
tracerProviderBuilder.addSpanProcessor(batchSpanProcessor);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,18 @@ public class RumConstants {

public static final String APP_START_SPAN_NAME = "AppStart";

public static final class Events {
public static final String INIT_EVENT_STARTED = "rum.sdk.init.started";
public static final String INIT_EVENT_CONFIG = "rum.sdk.init.config";
public static final String INIT_EVENT_NET_PROVIDER = "rum.sdk.init.net.provider";
public static final String INIT_EVENT_NET_MONITOR = "rum.sdk.init.net.monitor";
public static final String INIT_EVENT_ANR_MONITOR = "rum.sdk.init.anr_monitor";
public static final String INIT_EVENT_JANK_MONITOR = "rum.sdk.init.jank_monitor";
public static final String INIT_EVENT_CRASH_REPORTER = "rum.sdk.init.crash.reporter";
public static final String INIT_EVENT_SPAN_EXPORTER = "rum.sdk.init.span.exporter";

private Events() {}
}

private RumConstants() {}
}
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[versions]
opentelemetry = "1.38.0"
opentelemetry-alpha = "1.38.0-alpha"
opentelemetry-instrumentation = "2.4.0"
opentelemetry-instrumentation-alpha = "2.4.0-alpha"
opentelemetry-semconv = "1.25.0-alpha"
Expand All @@ -25,6 +26,8 @@ opentelemetry-instrumentation-okhttp = { module = "io.opentelemetry.instrumentat
opentelemetry-semconv = { module = "io.opentelemetry.semconv:opentelemetry-semconv", version.ref = "opentelemetry-semconv" }
opentelemetry-semconv-incubating = { module = "io.opentelemetry.semconv:opentelemetry-semconv-incubating", version.ref = "opentelemetry-semconv" }
opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api" }
opentelemetry-api-incubator = { module = "io.opentelemetry:opentelemetry-api-incubator" }
opentelemetry-sdk-extension-incubator = { module = "io.opentelemetry:opentelemetry-sdk-extension-incubator", version.ref = "opentelemetry-alpha" }
opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk" }
opentelemetry-exporter-logging = { module = "io.opentelemetry:opentelemetry-exporter-logging" }
opentelemetry-diskBuffering = { module = "io.opentelemetry.contrib:opentelemetry-disk-buffering", version.ref = "opentelemetry-contrib" }
Expand Down
2 changes: 2 additions & 0 deletions instrumentation/startup/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ dependencies {
implementation(libs.androidx.core)
implementation(libs.opentelemetry.semconv)
implementation(libs.opentelemetry.sdk)
implementation(libs.opentelemetry.api.incubator)
implementation(libs.opentelemetry.sdk.extension.incubator)
implementation(libs.opentelemetry.instrumentation.api)
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.instrumentation.startup

import io.opentelemetry.sdk.trace.export.SpanExporter

interface InitializationEvents {
fun sdkInitializationStarted()

fun recordConfiguration(config: Map<String, String>)

fun currentNetworkProviderInitialized()

fun networkMonitorInitialized()

fun anrMonitorInitialized()

fun slowRenderingDetectorInitialized()

fun crashReportingInitialized()

fun spanExporterInitialized(spanExporter: SpanExporter)

companion object {
@JvmField
val NO_OP: InitializationEvents =
object : InitializationEvents {
override fun sdkInitializationStarted() {}

override fun recordConfiguration(config: Map<String, String>) {}

override fun currentNetworkProviderInitialized() {}

override fun networkMonitorInitialized() {}

override fun anrMonitorInitialized() {}

override fun slowRenderingDetectorInitialized() {}

override fun crashReportingInitialized() {}

override fun spanExporterInitialized(spanExporter: SpanExporter) {}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.instrumentation.startup

import io.opentelemetry.android.common.RumConstants
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.common.Attributes
import io.opentelemetry.api.incubator.logs.AnyValue
import io.opentelemetry.sdk.OpenTelemetrySdk
import io.opentelemetry.sdk.logs.internal.SdkEventLoggerProvider
import io.opentelemetry.sdk.trace.export.SpanExporter
import java.time.Instant
import java.util.function.Consumer
import java.util.function.Supplier

class SdkInitializationEvents(private val clock: Supplier<Instant> = Supplier { Instant.now() }) : InitializationEvents {
private val events = mutableListOf<Event>()

override fun sdkInitializationStarted() {
addEvent(RumConstants.Events.INIT_EVENT_STARTED)
}

override fun recordConfiguration(config: Map<String, String>) {
val map = mutableMapOf<String, AnyValue<*>>()
config.entries.forEach(
Consumer { e: Map.Entry<String, String> ->
map[e.key] = AnyValue.of(e.value)
},
)
val body = AnyValue.of(map)
addEvent(RumConstants.Events.INIT_EVENT_CONFIG, body = body)
}

override fun currentNetworkProviderInitialized() {
addEvent(RumConstants.Events.INIT_EVENT_NET_PROVIDER)
}

override fun networkMonitorInitialized() {
addEvent(RumConstants.Events.INIT_EVENT_NET_MONITOR)
}

override fun anrMonitorInitialized() {
addEvent(RumConstants.Events.INIT_EVENT_ANR_MONITOR)
}

override fun slowRenderingDetectorInitialized() {
addEvent(RumConstants.Events.INIT_EVENT_JANK_MONITOR)
}

override fun crashReportingInitialized() {
addEvent(RumConstants.Events.INIT_EVENT_CRASH_REPORTER)
}

override fun spanExporterInitialized(spanExporter: SpanExporter) {
val attributes =
Attributes.of(AttributeKey.stringKey("span.exporter"), spanExporter.toString())
addEvent(RumConstants.Events.INIT_EVENT_SPAN_EXPORTER, attr = attributes)
}

fun finish(sdk: OpenTelemetrySdk) {
val loggerProvider = sdk.sdkLoggerProvider
val eventLogger =
SdkEventLoggerProvider.create(loggerProvider).get("otel.initialization.events")
events.forEach { event: Event ->
val eventBuilder =
eventLogger.builder(event.name)
.setTimestamp(event.timestamp)
.setAttributes(event.attributes)
if (event.body != null) {
// TODO: Config is technically correct because config is the only startup event
// with a body, but this is ultimately clunky/fragile.
eventBuilder.put("config", event.body)
}
eventBuilder.emit()
}
}

private fun addEvent(
name: String,
attr: Attributes? = null,
body: AnyValue<*>? = null,
) {
events.add(Event(clock.get(), name, attr, body))
}

private data class Event(
val timestamp: Instant,
val name: String,
val attributes: Attributes?,
val body: AnyValue<*>? = null,
)
}
Loading

0 comments on commit e40aa81

Please sign in to comment.