Skip to content

Commit

Permalink
Instrumentation API part 10 (#498)
Browse files Browse the repository at this point in the history
* Installing AndroidInstrumentations

* Validating installing instrumentations

* Clean up

* Improving test name

* Removing common module

* Renaming android-agent to core

* Making instrumentations into services

* Created android-agent module

* Adding OtelRumConfig extensions

* Updating agent description

* Reverting core namespace change

* Moving RumConstants to common package

* Adding auto service annotations as implementation to avoid R8 complains
  • Loading branch information
LikeTheSalad authored Jul 31, 2024
1 parent 5f6a0d0 commit 461bf86
Show file tree
Hide file tree
Showing 140 changed files with 329 additions and 226 deletions.
89 changes: 15 additions & 74 deletions android-agent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,83 +4,24 @@ plugins {
}

android {
namespace = "io.opentelemetry.android"

buildToolsVersion = "34.0.0"

defaultConfig {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
buildConfigField("String", "OTEL_ANDROID_VERSION", "\"$version\"")
}

buildTypes {
all {
resValue("string", "rum.version", "${project.version}")
}
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
}

androidComponents {
onVariants {
if (it.buildType == "release") { // The one we choose to release
project.tasks.register("createReleaseBuild", Copy::class) {
from(it.artifacts.get(com.android.build.api.artifact.SingleArtifact.AAR))
into(project.layout.buildDirectory.dir("outputs/aar"))
rename(".+", "opentelemetry-android.aar")
}
}
}
}

project.afterEvaluate {
tasks.named("assembleRelease") {
finalizedBy("createReleaseBuild")
}
}

testOptions {
unitTests.isReturnDefaultValues = true
unitTests.isIncludeAndroidResources = true
}

buildFeatures {
buildConfig = true
}

sourceSets {
getByName("test") {
kotlin.srcDirs("src/integrationTest/kotlin")
}
}
namespace = "io.opentelemetry.android.agent"
}

dependencies {
implementation(project(":common"))
implementation(project(":instrumentation:common-api"))
implementation(libs.androidx.core)
implementation(libs.androidx.navigation.fragment)
implementation(libs.androidx.lifecycle.process)

api(platform(libs.opentelemetry.platform))
api(libs.opentelemetry.api)
implementation(libs.opentelemetry.sdk)
implementation(libs.opentelemetry.exporter.logging)
api(project(":core"))
implementation(libs.opentelemetry.instrumentation.api)
implementation(libs.opentelemetry.semconv.incubating)
implementation(libs.opentelemetry.diskBuffering)
testImplementation(libs.opentelemetry.api.incubator)
testImplementation(libs.androidx.test.core)
testImplementation(libs.awaitility)
testImplementation(libs.robolectric)
testImplementation(libs.androidx.junit.ktx)

// Default instrumentations:
api(project(":instrumentation:activity"))
api(project(":instrumentation:fragment"))
api(project(":instrumentation:crash"))
api(project(":instrumentation:startup"))
api(project(":instrumentation:slowrendering"))
api(project(":instrumentation:anr"))
api(project(":instrumentation:network"))
}

extra["pomName"] = "OpenTelemetry Android Instrumentation"
description = "A library for instrumenting Android applications with OpenTelemetry"
extra["pomName"] = "OpenTelemetry Android Agent"
description =
"A library that contains all the commonly needed instrumentation for Android apps in a " +
"convenient way with minimum configuration needed."
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.agent

import io.opentelemetry.android.config.OtelRumConfig
import io.opentelemetry.android.instrumentation.AndroidInstrumentationRegistry
import io.opentelemetry.android.instrumentation.activity.ActivityLifecycleInstrumentation
import io.opentelemetry.android.instrumentation.anr.AnrInstrumentation
import io.opentelemetry.android.instrumentation.common.ScreenNameExtractor
import io.opentelemetry.android.instrumentation.crash.CrashDetails
import io.opentelemetry.android.instrumentation.crash.CrashReporterInstrumentation
import io.opentelemetry.android.instrumentation.fragment.FragmentLifecycleInstrumentation
import io.opentelemetry.android.instrumentation.network.NetworkChangeInstrumentation
import io.opentelemetry.android.instrumentation.slowrendering.SlowRenderingInstrumentation
import io.opentelemetry.android.internal.services.network.data.CurrentNetwork
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor
import java.time.Duration

/**
* Convenience functions to allow configuring the default instrumentations through the [OtelRumConfig] object, for example:
*
* ```
* OtelRumConfig()
* .setSessionTimeout(Duration.ofSeconds(10)) // Real OtelRumConfig function
* .setSlowRenderingDetectionPollInterval(Duration.ofSeconds(5)) // Extension function
* .disableScreenAttributes() // Real OtelRumConfig function
* ```
*/

fun OtelRumConfig.setActivityTracerCustomizer(customizer: (Tracer) -> Tracer): OtelRumConfig {
AndroidInstrumentationRegistry.get().get(ActivityLifecycleInstrumentation::class.java)
?.setTracerCustomizer(customizer)
return this
}

fun OtelRumConfig.setActivityNameExtractor(screenNameExtractor: ScreenNameExtractor): OtelRumConfig {
AndroidInstrumentationRegistry.get().get(ActivityLifecycleInstrumentation::class.java)
?.setScreenNameExtractor(screenNameExtractor)
return this
}

fun OtelRumConfig.setFragmentTracerCustomizer(customizer: (Tracer) -> Tracer): OtelRumConfig {
AndroidInstrumentationRegistry.get().get(FragmentLifecycleInstrumentation::class.java)
?.setTracerCustomizer(customizer)
return this
}

fun OtelRumConfig.setFragmentNameExtractor(screenNameExtractor: ScreenNameExtractor): OtelRumConfig {
AndroidInstrumentationRegistry.get().get(FragmentLifecycleInstrumentation::class.java)
?.setScreenNameExtractor(screenNameExtractor)
return this
}

fun OtelRumConfig.addAnrAttributesExtractor(extractor: AttributesExtractor<Array<StackTraceElement>, Void>): OtelRumConfig {
AndroidInstrumentationRegistry.get().get(AnrInstrumentation::class.java)
?.addAttributesExtractor(extractor)
return this
}

fun OtelRumConfig.addCrashAttributesExtractor(extractor: AttributesExtractor<CrashDetails, Void>): OtelRumConfig {
AndroidInstrumentationRegistry.get().get(CrashReporterInstrumentation::class.java)
?.addAttributesExtractor(extractor)
return this
}

fun OtelRumConfig.addNetworkChangeAttributesExtractor(extractor: AttributesExtractor<CurrentNetwork, Void>): OtelRumConfig {
AndroidInstrumentationRegistry.get().get(NetworkChangeInstrumentation::class.java)
?.addAttributesExtractor(extractor)
return this
}

fun OtelRumConfig.setSlowRenderingDetectionPollInterval(interval: Duration): OtelRumConfig {
AndroidInstrumentationRegistry.get().get(SlowRenderingInstrumentation::class.java)
?.setSlowRenderingDetectionPollInterval(interval)
return this
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ tasks.withType<Test> {
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
dependencies {
implementation(libs.findLibrary("findbugs-jsr305").get())
compileOnly(libs.findLibrary("auto-service-annotations").get())
implementation(libs.findLibrary("auto-service-annotations").get())
kapt(libs.findLibrary("auto-service-processor").get())
testImplementation(libs.findLibrary("assertj-core").get())
testImplementation(libs.findBundle("mocking").get())
Expand Down
20 changes: 0 additions & 20 deletions common/build.gradle.kts

This file was deleted.

84 changes: 84 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
plugins {
id("otel.android-library-conventions")
id("otel.publish-conventions")
}

android {
namespace = "io.opentelemetry.android"

buildToolsVersion = "34.0.0"

defaultConfig {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
buildConfigField("String", "OTEL_ANDROID_VERSION", "\"$version\"")
}

buildTypes {
all {
resValue("string", "rum.version", "${project.version}")
}
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
}

androidComponents {
onVariants {
if (it.buildType == "release") { // The one we choose to release
project.tasks.register("createReleaseBuild", Copy::class) {
from(it.artifacts.get(com.android.build.api.artifact.SingleArtifact.AAR))
into(project.layout.buildDirectory.dir("outputs/aar"))
rename(".+", "opentelemetry-android.aar")
}
}
}
}

project.afterEvaluate {
tasks.named("assembleRelease") {
finalizedBy("createReleaseBuild")
}
}

testOptions {
unitTests.isReturnDefaultValues = true
unitTests.isIncludeAndroidResources = true
}

buildFeatures {
buildConfig = true
}

sourceSets {
getByName("test") {
kotlin.srcDirs("src/integrationTest/kotlin")
}
}
}

dependencies {
implementation(libs.androidx.core)
implementation(libs.androidx.navigation.fragment)
implementation(libs.androidx.lifecycle.process)

api(platform(libs.opentelemetry.platform))
api(libs.opentelemetry.api)
implementation(libs.opentelemetry.sdk)
implementation(libs.opentelemetry.exporter.logging)
implementation(libs.opentelemetry.instrumentation.api)
implementation(libs.opentelemetry.semconv.incubating)
implementation(libs.opentelemetry.diskBuffering)
testImplementation(libs.opentelemetry.api.incubator)
testImplementation(libs.androidx.test.core)
testImplementation(libs.awaitility)
testImplementation(libs.robolectric)
testImplementation(libs.androidx.junit.ktx)
}

extra["pomName"] = "OpenTelemetry Android Instrumentation"
description = "A library for instrumenting Android applications with OpenTelemetry"
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ static OpenTelemetryRumBuilder builder(Application application) {
* SDK as a parameter.
*/
static OpenTelemetryRumBuilder builder(Application application, OtelRumConfig config) {
return new OpenTelemetryRumBuilder(application, config);
return OpenTelemetryRumBuilder.create(application, config);
}

/**
Expand All @@ -58,10 +58,15 @@ static OpenTelemetryRumBuilder builder(Application application, OtelRumConfig co
*
* @param application The {@link Application} that is being instrumented.
* @param openTelemetrySdk The {@link OpenTelemetrySdk} that the user has already created.
* @param discoverInstrumentations TRUE to look for instrumentations in the classpath and
* applying them automatically.
*/
static SdkPreconfiguredRumBuilder builder(
Application application, OpenTelemetrySdk openTelemetrySdk) {
return new SdkPreconfiguredRumBuilder(application, openTelemetrySdk);
Application application,
OpenTelemetrySdk openTelemetrySdk,
boolean discoverInstrumentations) {
return new SdkPreconfiguredRumBuilder(
application, openTelemetrySdk, discoverInstrumentations);
}

/** Returns a no-op implementation of {@link OpenTelemetryRum}. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import io.opentelemetry.android.features.diskbuffering.DiskBufferingConfiguration;
import io.opentelemetry.android.features.diskbuffering.SignalFromDiskExporter;
import io.opentelemetry.android.features.diskbuffering.scheduler.ExportScheduleHandler;
import io.opentelemetry.android.instrumentation.common.InstrumentedApplication;
import io.opentelemetry.android.instrumentation.AndroidInstrumentation;
import io.opentelemetry.android.internal.features.networkattrs.NetworkAttributesSpanAppender;
import io.opentelemetry.android.internal.features.persistence.DiskManager;
import io.opentelemetry.android.internal.features.persistence.SimpleTemporaryFileProvider;
Expand Down Expand Up @@ -74,10 +74,7 @@ public final class OpenTelemetryRumBuilder {
private final List<BiFunction<SdkLoggerProviderBuilder, Application, SdkLoggerProviderBuilder>>
loggerProviderCustomizers = new ArrayList<>();
private final OtelRumConfig config;

private final List<Consumer<InstrumentedApplication>> instrumentationInstallers =
new ArrayList<>();

private final List<AndroidInstrumentation> instrumentations = new ArrayList<>();
private final List<Consumer<OpenTelemetrySdk>> otelSdkReadyListeners = new ArrayList<>();
private Function<? super SpanExporter, ? extends SpanExporter> spanExporterCustomizer = a -> a;
private Function<? super LogRecordExporter, ? extends LogRecordExporter>
Expand All @@ -92,10 +89,14 @@ private static TextMapPropagator buildDefaultPropagator() {
W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance());
}

OpenTelemetryRumBuilder(Application application, OtelRumConfig config) {
public static OpenTelemetryRumBuilder create(Application application, OtelRumConfig config) {
return new OpenTelemetryRumBuilder(
application, config, new SessionIdTimeoutHandler(config.getSessionTimeout()));
}

OpenTelemetryRumBuilder(
Application application, OtelRumConfig config, SessionIdTimeoutHandler timeoutHandler) {
this.application = application;
final SessionIdTimeoutHandler timeoutHandler =
new SessionIdTimeoutHandler(config.getSessionTimeout());
this.sessionId = new SessionId(timeoutHandler);
this.resource = AndroidResource.createDefault(application);
this.config = config;
Expand Down Expand Up @@ -184,14 +185,12 @@ public OpenTelemetryRumBuilder addLoggerProviderCustomizer(
}

/**
* Adds an instrumentation installer function that will be run on an {@link
* InstrumentedApplication} instance as a part of the {@link #build()} method call.
* Adds an instrumentation to be applied as a part of the {@link #build()} method call.
*
* @return {@code this}
*/
public OpenTelemetryRumBuilder addInstrumentation(
Consumer<InstrumentedApplication> instrumentationInstaller) {
instrumentationInstallers.add(instrumentationInstaller);
public OpenTelemetryRumBuilder addInstrumentation(AndroidInstrumentation instrumentation) {
instrumentations.add(instrumentation);
return this;
}

Expand Down Expand Up @@ -319,8 +318,12 @@ OpenTelemetryRum build(ServiceManager serviceManager) {

SdkPreconfiguredRumBuilder delegate =
new SdkPreconfiguredRumBuilder(
application, sdk, sessionId, serviceManager::getAppLifecycleService);
instrumentationInstallers.forEach(delegate::addInstrumentation);
application,
sdk,
sessionId,
serviceManager::getAppLifecycleService,
config.shouldDiscoverInstrumentations());
instrumentations.forEach(delegate::addInstrumentation);
serviceManager.start();
return delegate.build();
}
Expand Down
Loading

0 comments on commit 461bf86

Please sign in to comment.