From cee55aa9a6ff683d0855b4113c2a7bdd10f9682e Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Thu, 30 May 2024 15:29:18 +0200 Subject: [PATCH 01/16] Created AndroidInstrumentation interface --- .../instrumentation/AndroidInstrumentation.kt | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt new file mode 100644 index 000000000..882da8fd8 --- /dev/null +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.instrumentation + +import android.app.Application +import io.opentelemetry.android.OpenTelemetryRum + +/** + * This interface defines a tool that automatically generates telemetry, that is, creates spans, metrics or logs for a specific use-case + * without the need for end users to directly interact with the OpenTelemetry SDK to create those signals manually. + * + * Implementations of this interface should be focused on a single use-case and should attach themselves automatically + * to the tool that they are supposed to generate telemetry for. For example, an implementation that tracks + * Fragment lifecycle methods by generating OTel events in key places of a Fragment's lifecycle, should + * come with its own "FragmentLifecycleCallbacks" implementation (or similar callback mechanism that notifies when a fragment lifecycle state has changed) + * and should find a way to register its callback into all of the Fragments of the host app to automatically + * track their lifecycle without end users having to modify their project's code to make it work. + * + * Even though users shouldn't have to write code to make an AndroidInstrumentation implementation work, + * implementations should expose configurable options whenever possible to allow users to customize relevant + * options depending on the use-case. + * + * Access to an implementation, either to configure it or to install it, must be made through + * [AndroidInstrumentation.get] or [AndroidInstrumentation.getAll]. + */ +interface AndroidInstrumentation { + /** + * This is the entry point of the instrumentation, it must be called once per implementation and it should + * only be called from [OpenTelemetryRum]'s builder once the [OpenTelemetryRum] instance is initialized and ready + * to use for generating telemetry. + */ + fun install( + application: Application, + openTelemetryRum: OpenTelemetryRum, + ) + + companion object { + @JvmStatic + fun get(type: Class): T { + TODO() + } + + @JvmStatic + fun getAll(): Collection { + TODO() + } + } +} From 03876a833d2824afaa912c2fae5b0a821e122853 Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Thu, 30 May 2024 17:21:58 +0200 Subject: [PATCH 02/16] Validating loading instrumentations from the classpath --- .../instrumentation/AndroidInstrumentation.kt | 13 +++++++-- .../TestAndroidInstrumentation.kt | 21 ++++++++++++++ .../AndroidInstrumentationTest.kt | 29 +++++++++++++++++++ ...oid.instrumentation.AndroidInstrumentation | 1 + 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 android-agent/src/main/java/io/opentelemetry/android/instrumentation/TestAndroidInstrumentation.kt create mode 100644 android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt create mode 100644 android-agent/src/test/resources/META-INF/services/io.opentelemetry.android.instrumentation.AndroidInstrumentation diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt index 882da8fd8..6c664d8db 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt @@ -7,6 +7,7 @@ package io.opentelemetry.android.instrumentation import android.app.Application import io.opentelemetry.android.OpenTelemetryRum +import java.util.ServiceLoader /** * This interface defines a tool that automatically generates telemetry, that is, creates spans, metrics or logs for a specific use-case @@ -37,15 +38,21 @@ interface AndroidInstrumentation { openTelemetryRum: OpenTelemetryRum, ) - companion object { + companion object Registry { + private val instrumentations: MutableMap, AndroidInstrumentation> by lazy { + ServiceLoader.load(AndroidInstrumentation::class.java).associateBy { it.javaClass } + .toMutableMap() + } + + @Suppress("UNCHECKED_CAST") @JvmStatic fun get(type: Class): T { - TODO() + return instrumentations.getValue(type) as T } @JvmStatic fun getAll(): Collection { - TODO() + return instrumentations.values } } } diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/TestAndroidInstrumentation.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/TestAndroidInstrumentation.kt new file mode 100644 index 000000000..27b32a376 --- /dev/null +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/TestAndroidInstrumentation.kt @@ -0,0 +1,21 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.instrumentation + +import android.app.Application +import io.opentelemetry.android.OpenTelemetryRum + +class TestAndroidInstrumentation : AndroidInstrumentation { + var installed = false + private set + + override fun install( + application: Application, + openTelemetryRum: OpenTelemetryRum, + ) { + installed = true + } +} diff --git a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt new file mode 100644 index 000000000..f363a054d --- /dev/null +++ b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.instrumentation + +import io.mockk.mockk +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class AndroidInstrumentationTest { + @Test + fun `Find and register implementations available in the classpath when querying an instrumentation`() { + val instrumentation = AndroidInstrumentation.get(TestAndroidInstrumentation::class.java) + + instrumentation.install(mockk(), mockk()) + + assertThat(AndroidInstrumentation.get(TestAndroidInstrumentation::class.java).installed).isTrue() + } + + @Test + fun `Find and register implementations available in the classpath when querying all instrumentations`() { + val instrumentations = AndroidInstrumentation.getAll() + + assertThat(instrumentations).hasSize(1) + assertThat(instrumentations.first()).isInstanceOf(TestAndroidInstrumentation::class.java) + } +} diff --git a/android-agent/src/test/resources/META-INF/services/io.opentelemetry.android.instrumentation.AndroidInstrumentation b/android-agent/src/test/resources/META-INF/services/io.opentelemetry.android.instrumentation.AndroidInstrumentation new file mode 100644 index 000000000..ddf212907 --- /dev/null +++ b/android-agent/src/test/resources/META-INF/services/io.opentelemetry.android.instrumentation.AndroidInstrumentation @@ -0,0 +1 @@ +io.opentelemetry.android.instrumentation.TestAndroidInstrumentation \ No newline at end of file From c63837f05ea08fa53d1b66b05fbd5810c63e6d10 Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Thu, 30 May 2024 17:33:23 +0200 Subject: [PATCH 03/16] Registering instrumentations --- .../instrumentation/AndroidInstrumentation.kt | 7 ++++ .../AndroidInstrumentationTest.kt | 35 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt index 6c664d8db..996a2331b 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt @@ -54,5 +54,12 @@ interface AndroidInstrumentation { fun getAll(): Collection { return instrumentations.values } + + fun register(instrumentation: AndroidInstrumentation) { + if (instrumentation::class.java in instrumentations) { + throw IllegalStateException("Instrumentation with type '${instrumentation::class.java}' already exists.") + } + instrumentations[instrumentation.javaClass] = instrumentation + } } } diff --git a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt index f363a054d..704adce93 100644 --- a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt +++ b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt @@ -5,9 +5,12 @@ package io.opentelemetry.android.instrumentation +import android.app.Application import io.mockk.mockk +import io.opentelemetry.android.OpenTelemetryRum import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test +import org.junit.jupiter.api.fail class AndroidInstrumentationTest { @Test @@ -26,4 +29,36 @@ class AndroidInstrumentationTest { assertThat(instrumentations).hasSize(1) assertThat(instrumentations.first()).isInstanceOf(TestAndroidInstrumentation::class.java) } + + @Test + fun `Register instrumentations`() { + val instrumentation = DummyInstrumentation("test") + + AndroidInstrumentation.register(instrumentation) + + assertThat(AndroidInstrumentation.get(DummyInstrumentation::class.java).name).isEqualTo("test") + } + + @Test + fun `Register only one instrumentation per type`() { + val instrumentation = DummyInstrumentation("test") + val instrumentation2 = DummyInstrumentation("test2") + + AndroidInstrumentation.register(instrumentation) + + try { + AndroidInstrumentation.register(instrumentation2) + fail("Should not allow to register the same type of instrumentation more than once.") + } catch (e: IllegalStateException) { + assertThat(e.message).isEqualTo("Instrumentation with type '${DummyInstrumentation::class.java}' already exists.") + } + } + + private class DummyInstrumentation(val name: String) : AndroidInstrumentation { + override fun install( + application: Application, + openTelemetryRum: OpenTelemetryRum, + ) { + } + } } From b7430cd1b663dc82c286136363d0c7c0773ddb5f Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Thu, 30 May 2024 17:36:25 +0200 Subject: [PATCH 04/16] Making AndroidInstrumentation.getAll response return an unmodifiable collection --- .../android/instrumentation/AndroidInstrumentation.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt index 996a2331b..93c47d3c0 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt @@ -7,6 +7,7 @@ package io.opentelemetry.android.instrumentation import android.app.Application import io.opentelemetry.android.OpenTelemetryRum +import java.util.Collections import java.util.ServiceLoader /** @@ -52,7 +53,7 @@ interface AndroidInstrumentation { @JvmStatic fun getAll(): Collection { - return instrumentations.values + return Collections.unmodifiableCollection(instrumentations.values) } fun register(instrumentation: AndroidInstrumentation) { From 26cc415e4fbe7bd5e1452748bcbfbc55f903c2ca Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Thu, 30 May 2024 17:54:58 +0200 Subject: [PATCH 05/16] Created AndroidInstrumentationRegistry --- .../instrumentation/AndroidInstrumentation.kt | 29 +---------------- .../AndroidInstrumentationRegistry.kt | 14 ++++++++ .../AndroidInstrumentationRegistryImpl.kt | 32 +++++++++++++++++++ ...AndroidInstrumentationRegistryImplTest.kt} | 24 +++++++++----- .../TestAndroidInstrumentation.kt | 0 5 files changed, 63 insertions(+), 36 deletions(-) create mode 100644 android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt create mode 100644 android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt rename android-agent/src/test/java/io/opentelemetry/android/instrumentation/{AndroidInstrumentationTest.kt => AndroidInstrumentationRegistryImplTest.kt} (70%) rename android-agent/src/{main => test}/java/io/opentelemetry/android/instrumentation/TestAndroidInstrumentation.kt (100%) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt index 93c47d3c0..620d0248c 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt @@ -7,8 +7,6 @@ package io.opentelemetry.android.instrumentation import android.app.Application import io.opentelemetry.android.OpenTelemetryRum -import java.util.Collections -import java.util.ServiceLoader /** * This interface defines a tool that automatically generates telemetry, that is, creates spans, metrics or logs for a specific use-case @@ -26,7 +24,7 @@ import java.util.ServiceLoader * options depending on the use-case. * * Access to an implementation, either to configure it or to install it, must be made through - * [AndroidInstrumentation.get] or [AndroidInstrumentation.getAll]. + * [AndroidInstrumentationRegistry.get] or [AndroidInstrumentationRegistry.getAll]. */ interface AndroidInstrumentation { /** @@ -38,29 +36,4 @@ interface AndroidInstrumentation { application: Application, openTelemetryRum: OpenTelemetryRum, ) - - companion object Registry { - private val instrumentations: MutableMap, AndroidInstrumentation> by lazy { - ServiceLoader.load(AndroidInstrumentation::class.java).associateBy { it.javaClass } - .toMutableMap() - } - - @Suppress("UNCHECKED_CAST") - @JvmStatic - fun get(type: Class): T { - return instrumentations.getValue(type) as T - } - - @JvmStatic - fun getAll(): Collection { - return Collections.unmodifiableCollection(instrumentations.values) - } - - fun register(instrumentation: AndroidInstrumentation) { - if (instrumentation::class.java in instrumentations) { - throw IllegalStateException("Instrumentation with type '${instrumentation::class.java}' already exists.") - } - instrumentations[instrumentation.javaClass] = instrumentation - } - } } diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt new file mode 100644 index 000000000..9da18468a --- /dev/null +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt @@ -0,0 +1,14 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.instrumentation + +interface AndroidInstrumentationRegistry { + fun get(type: Class): T + + fun getAll(): Collection + + fun register(instrumentation: AndroidInstrumentation) +} diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt new file mode 100644 index 000000000..631e1f159 --- /dev/null +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.instrumentation + +import java.util.Collections +import java.util.ServiceLoader + +internal class AndroidInstrumentationRegistryImpl : AndroidInstrumentationRegistry { + private val instrumentations: MutableMap, AndroidInstrumentation> by lazy { + ServiceLoader.load(AndroidInstrumentation::class.java).associateBy { it.javaClass } + .toMutableMap() + } + + @Suppress("UNCHECKED_CAST") + override fun get(type: Class): T { + return instrumentations.getValue(type) as T + } + + override fun getAll(): Collection { + return Collections.unmodifiableCollection(instrumentations.values) + } + + override fun register(instrumentation: AndroidInstrumentation) { + if (instrumentation::class.java in instrumentations) { + throw IllegalStateException("Instrumentation with type '${instrumentation::class.java}' already exists.") + } + instrumentations[instrumentation.javaClass] = instrumentation + } +} diff --git a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt similarity index 70% rename from android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt rename to android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt index 704adce93..74053380f 100644 --- a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationTest.kt +++ b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt @@ -9,22 +9,30 @@ import android.app.Application import io.mockk.mockk import io.opentelemetry.android.OpenTelemetryRum import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.fail -class AndroidInstrumentationTest { +class AndroidInstrumentationRegistryImplTest { + private lateinit var registry: AndroidInstrumentationRegistryImpl + + @BeforeEach + fun setUp() { + registry = AndroidInstrumentationRegistryImpl() + } + @Test fun `Find and register implementations available in the classpath when querying an instrumentation`() { - val instrumentation = AndroidInstrumentation.get(TestAndroidInstrumentation::class.java) + val instrumentation = registry.get(TestAndroidInstrumentation::class.java) instrumentation.install(mockk(), mockk()) - assertThat(AndroidInstrumentation.get(TestAndroidInstrumentation::class.java).installed).isTrue() + assertThat(registry.get(TestAndroidInstrumentation::class.java).installed).isTrue() } @Test fun `Find and register implementations available in the classpath when querying all instrumentations`() { - val instrumentations = AndroidInstrumentation.getAll() + val instrumentations = registry.getAll() assertThat(instrumentations).hasSize(1) assertThat(instrumentations.first()).isInstanceOf(TestAndroidInstrumentation::class.java) @@ -34,9 +42,9 @@ class AndroidInstrumentationTest { fun `Register instrumentations`() { val instrumentation = DummyInstrumentation("test") - AndroidInstrumentation.register(instrumentation) + registry.register(instrumentation) - assertThat(AndroidInstrumentation.get(DummyInstrumentation::class.java).name).isEqualTo("test") + assertThat(registry.get(DummyInstrumentation::class.java).name).isEqualTo("test") } @Test @@ -44,10 +52,10 @@ class AndroidInstrumentationTest { val instrumentation = DummyInstrumentation("test") val instrumentation2 = DummyInstrumentation("test2") - AndroidInstrumentation.register(instrumentation) + registry.register(instrumentation) try { - AndroidInstrumentation.register(instrumentation2) + registry.register(instrumentation2) fail("Should not allow to register the same type of instrumentation more than once.") } catch (e: IllegalStateException) { assertThat(e.message).isEqualTo("Instrumentation with type '${DummyInstrumentation::class.java}' already exists.") diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/TestAndroidInstrumentation.kt b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/TestAndroidInstrumentation.kt similarity index 100% rename from android-agent/src/main/java/io/opentelemetry/android/instrumentation/TestAndroidInstrumentation.kt rename to android-agent/src/test/java/io/opentelemetry/android/instrumentation/TestAndroidInstrumentation.kt From d16b3f80f5a56fd6c73e82a4cb923dbf7a224c2f Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Thu, 30 May 2024 17:56:19 +0200 Subject: [PATCH 06/16] Updating docs --- .../android/instrumentation/AndroidInstrumentation.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt index 620d0248c..5823d6dbf 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt @@ -31,6 +31,9 @@ interface AndroidInstrumentation { * This is the entry point of the instrumentation, it must be called once per implementation and it should * only be called from [OpenTelemetryRum]'s builder once the [OpenTelemetryRum] instance is initialized and ready * to use for generating telemetry. + * + * @param application The host android application. + * @param openTelemetryRum The [OpenTelemetryRum] instance to use for creating signals. */ fun install( application: Application, From c5ddaaa8cff1125d31e11a8909dcc05fe7ea85a8 Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Thu, 30 May 2024 18:18:41 +0200 Subject: [PATCH 07/16] Adding docs to AndroidInstrumentationRegistry --- .../AndroidInstrumentationRegistry.kt | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt index 9da18468a..36c2161d8 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt @@ -5,10 +5,31 @@ package io.opentelemetry.android.instrumentation +/** + * Stores and provides all the available instrumentations. + */ interface AndroidInstrumentationRegistry { - fun get(type: Class): T + /** + * Provides a single instrumentation if available. + * + * @param type The type of the instrumentation to retrieve. + * @return The instrumentation instance if available, NULL otherwise. + */ + fun get(type: Class): T? + /** + * Provides all registered instrumentations. + * + * @return All registered instrumentations. + */ fun getAll(): Collection + /** + * Stores an instrumentation as long as there is not other instrumentation already registered with the same + * type. + * + * @param instrumentation The instrumentation to register. + * @throws IllegalArgumentException If the instrumentation couldn't be registered. + */ fun register(instrumentation: AndroidInstrumentation) } From a68b49c27bfaa66c0f09a6edcd31937c5d12f63d Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Thu, 30 May 2024 18:22:49 +0200 Subject: [PATCH 08/16] Updating docs and adjusting AndroidInstrumentationRegistryImpl --- .../android/instrumentation/AndroidInstrumentationRegistry.kt | 2 +- .../instrumentation/AndroidInstrumentationRegistryImpl.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt index 36c2161d8..efe019593 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt @@ -29,7 +29,7 @@ interface AndroidInstrumentationRegistry { * type. * * @param instrumentation The instrumentation to register. - * @throws IllegalArgumentException If the instrumentation couldn't be registered. + * @throws IllegalStateException If the instrumentation couldn't be registered. */ fun register(instrumentation: AndroidInstrumentation) } diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt index 631e1f159..097229cf7 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt @@ -15,8 +15,8 @@ internal class AndroidInstrumentationRegistryImpl : AndroidInstrumentationRegist } @Suppress("UNCHECKED_CAST") - override fun get(type: Class): T { - return instrumentations.getValue(type) as T + override fun get(type: Class): T? { + return instrumentations[type] as? T } override fun getAll(): Collection { From 7e6003736dc776326348411d9d10cbeedce69c4e Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Thu, 30 May 2024 18:38:07 +0200 Subject: [PATCH 09/16] Adding singleton registry test --- .../AndroidInstrumentationRegistry.kt | 11 +++++++++++ .../AndroidInstrumentationRegistryImplTest.kt | 6 +++--- .../AndroidInstrumentationRegistryTest.kt | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryTest.kt diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt index efe019593..072a7ec6a 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt @@ -32,4 +32,15 @@ interface AndroidInstrumentationRegistry { * @throws IllegalStateException If the instrumentation couldn't be registered. */ fun register(instrumentation: AndroidInstrumentation) + + companion object { + private val instance: AndroidInstrumentationRegistry by lazy { + AndroidInstrumentationRegistryImpl() + } + + @JvmStatic + fun get(): AndroidInstrumentationRegistry { + return instance + } + } } diff --git a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt index 74053380f..a0eddb8c1 100644 --- a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt +++ b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt @@ -25,9 +25,9 @@ class AndroidInstrumentationRegistryImplTest { fun `Find and register implementations available in the classpath when querying an instrumentation`() { val instrumentation = registry.get(TestAndroidInstrumentation::class.java) - instrumentation.install(mockk(), mockk()) + instrumentation?.install(mockk(), mockk()) - assertThat(registry.get(TestAndroidInstrumentation::class.java).installed).isTrue() + assertThat(registry.get(TestAndroidInstrumentation::class.java)?.installed).isTrue() } @Test @@ -44,7 +44,7 @@ class AndroidInstrumentationRegistryImplTest { registry.register(instrumentation) - assertThat(registry.get(DummyInstrumentation::class.java).name).isEqualTo("test") + assertThat(registry.get(DummyInstrumentation::class.java)?.name).isEqualTo("test") } @Test diff --git a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryTest.kt b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryTest.kt new file mode 100644 index 000000000..2a17be5c2 --- /dev/null +++ b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryTest.kt @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.instrumentation + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class AndroidInstrumentationRegistryTest { + @Test + fun `Verify singleton`() { + val registry = AndroidInstrumentationRegistry.get() + + assertThat(registry).isEqualTo(AndroidInstrumentationRegistry.get()) + } +} From a0207b5584447701c3439c7596ae1b2fe0e93a1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar?= <56847527+LikeTheSalad@users.noreply.github.com> Date: Fri, 31 May 2024 11:20:53 +0200 Subject: [PATCH 10/16] Update android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt Co-authored-by: jason plumb <75337021+breedx-splk@users.noreply.github.com> --- .../android/instrumentation/AndroidInstrumentation.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt index 5823d6dbf..1f6add788 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt @@ -9,8 +9,8 @@ import android.app.Application import io.opentelemetry.android.OpenTelemetryRum /** - * This interface defines a tool that automatically generates telemetry, that is, creates spans, metrics or logs for a specific use-case - * without the need for end users to directly interact with the OpenTelemetry SDK to create those signals manually. + * This interface defines a tool that automatically generates telemetry for a specific use-case, + * without the need for end users to directly interact with the OpenTelemetry SDK to create telemetry manually. * * Implementations of this interface should be focused on a single use-case and should attach themselves automatically * to the tool that they are supposed to generate telemetry for. For example, an implementation that tracks From e8e7c2f8b415b735943f347aa69d71349c95d58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar?= <56847527+LikeTheSalad@users.noreply.github.com> Date: Fri, 31 May 2024 11:21:25 +0200 Subject: [PATCH 11/16] Update android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt Co-authored-by: jason plumb <75337021+breedx-splk@users.noreply.github.com> --- .../android/instrumentation/AndroidInstrumentation.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt index 1f6add788..3f4c41e07 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentation.kt @@ -32,7 +32,7 @@ interface AndroidInstrumentation { * only be called from [OpenTelemetryRum]'s builder once the [OpenTelemetryRum] instance is initialized and ready * to use for generating telemetry. * - * @param application The host android application. + * @param application The Android application being instrumented. * @param openTelemetryRum The [OpenTelemetryRum] instance to use for creating signals. */ fun install( From 93bd9a9b39964d20a30dc250fa22829c2d01d7fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar?= <56847527+LikeTheSalad@users.noreply.github.com> Date: Fri, 31 May 2024 11:21:30 +0200 Subject: [PATCH 12/16] Update android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt Co-authored-by: jason plumb <75337021+breedx-splk@users.noreply.github.com> --- .../android/instrumentation/AndroidInstrumentationRegistry.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt index 072a7ec6a..408ea8157 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistry.kt @@ -13,7 +13,7 @@ interface AndroidInstrumentationRegistry { * Provides a single instrumentation if available. * * @param type The type of the instrumentation to retrieve. - * @return The instrumentation instance if available, NULL otherwise. + * @return The instrumentation instance if available, null otherwise. */ fun get(type: Class): T? From d406c1fbd630fb5c5ad502e12c6c7e159a0efa51 Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Fri, 31 May 2024 11:59:31 +0200 Subject: [PATCH 13/16] Updating tests --- .../AndroidInstrumentationRegistryImplTest.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt index a0eddb8c1..de6463b8d 100644 --- a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt +++ b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt @@ -9,9 +9,9 @@ import android.app.Application import io.mockk.mockk import io.opentelemetry.android.OpenTelemetryRum import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import org.junit.jupiter.api.fail class AndroidInstrumentationRegistryImplTest { private lateinit var registry: AndroidInstrumentationRegistryImpl @@ -25,6 +25,8 @@ class AndroidInstrumentationRegistryImplTest { fun `Find and register implementations available in the classpath when querying an instrumentation`() { val instrumentation = registry.get(TestAndroidInstrumentation::class.java) + assertThat(instrumentation?.installed).isFalse() + instrumentation?.install(mockk(), mockk()) assertThat(registry.get(TestAndroidInstrumentation::class.java)?.installed).isTrue() @@ -54,12 +56,10 @@ class AndroidInstrumentationRegistryImplTest { registry.register(instrumentation) - try { + assertThatThrownBy { registry.register(instrumentation2) - fail("Should not allow to register the same type of instrumentation more than once.") - } catch (e: IllegalStateException) { - assertThat(e.message).isEqualTo("Instrumentation with type '${DummyInstrumentation::class.java}' already exists.") - } + }.isInstanceOf(IllegalStateException::class.java) + .hasMessage("Instrumentation with type '${DummyInstrumentation::class.java}' already exists.") } private class DummyInstrumentation(val name: String) : AndroidInstrumentation { From 57f754db81c59b1c5dedce8968831fe34942e4e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar?= <56847527+LikeTheSalad@users.noreply.github.com> Date: Fri, 31 May 2024 14:20:07 +0200 Subject: [PATCH 14/16] Update android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt Co-authored-by: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> --- .../instrumentation/AndroidInstrumentationRegistryImpl.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt index 097229cf7..a36a99258 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt @@ -23,6 +23,7 @@ internal class AndroidInstrumentationRegistryImpl : AndroidInstrumentationRegist return Collections.unmodifiableCollection(instrumentations.values) } + @Throws(IllegalStateException::class) override fun register(instrumentation: AndroidInstrumentation) { if (instrumentation::class.java in instrumentations) { throw IllegalStateException("Instrumentation with type '${instrumentation::class.java}' already exists.") From 08b9f10dda500739c98718184203f9607ae43ca7 Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Fri, 31 May 2024 14:28:59 +0200 Subject: [PATCH 15/16] Updating tests --- .../AndroidInstrumentationRegistryImplTest.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt index de6463b8d..b42aa60a3 100644 --- a/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt +++ b/android-agent/src/test/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImplTest.kt @@ -23,13 +23,13 @@ class AndroidInstrumentationRegistryImplTest { @Test fun `Find and register implementations available in the classpath when querying an instrumentation`() { - val instrumentation = registry.get(TestAndroidInstrumentation::class.java) + val instrumentation = registry.get(TestAndroidInstrumentation::class.java)!! - assertThat(instrumentation?.installed).isFalse() + assertThat(instrumentation.installed).isFalse() - instrumentation?.install(mockk(), mockk()) + instrumentation.install(mockk(), mockk()) - assertThat(registry.get(TestAndroidInstrumentation::class.java)?.installed).isTrue() + assertThat(registry.get(TestAndroidInstrumentation::class.java)!!.installed).isTrue() } @Test @@ -46,7 +46,7 @@ class AndroidInstrumentationRegistryImplTest { registry.register(instrumentation) - assertThat(registry.get(DummyInstrumentation::class.java)?.name).isEqualTo("test") + assertThat(registry.get(DummyInstrumentation::class.java)!!.name).isEqualTo("test") } @Test From 4a0bb4615dd89007c523f903ff4d1e9c9da5a4b0 Mon Sep 17 00:00:00 2001 From: Cesar Munoz <56847527+LikeTheSalad@users.noreply.github.com> Date: Fri, 31 May 2024 15:21:57 +0200 Subject: [PATCH 16/16] Avoid using java Collections --- .../instrumentation/AndroidInstrumentationRegistryImpl.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt index a36a99258..e265f46e7 100644 --- a/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt +++ b/android-agent/src/main/java/io/opentelemetry/android/instrumentation/AndroidInstrumentationRegistryImpl.kt @@ -5,7 +5,6 @@ package io.opentelemetry.android.instrumentation -import java.util.Collections import java.util.ServiceLoader internal class AndroidInstrumentationRegistryImpl : AndroidInstrumentationRegistry { @@ -20,7 +19,7 @@ internal class AndroidInstrumentationRegistryImpl : AndroidInstrumentationRegist } override fun getAll(): Collection { - return Collections.unmodifiableCollection(instrumentations.values) + return instrumentations.values.toList() } @Throws(IllegalStateException::class)