Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions android-agent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ android {
dependencies {
api(project(":core"))
implementation(project(":common"))
implementation(project(":session"))
implementation(project(":services"))
implementation(libs.opentelemetry.instrumentation.api)
implementation(libs.opentelemetry.exporter.otlp)

Expand All @@ -21,6 +23,8 @@ dependencies {
api(project(":instrumentation:network"))
api(project(":instrumentation:slowrendering"))
api(project(":instrumentation:startup"))

testImplementation(libs.robolectric)
}

extra["pomName"] = "OpenTelemetry Android Agent"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ 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.agent.session.SessionConfig
import io.opentelemetry.android.agent.session.SessionIdTimeoutHandler
import io.opentelemetry.android.agent.session.SessionManager
import io.opentelemetry.android.config.OtelRumConfig
import io.opentelemetry.android.instrumentation.AndroidInstrumentation
import io.opentelemetry.android.instrumentation.AndroidInstrumentationLoader
Expand All @@ -22,6 +25,7 @@ import io.opentelemetry.android.instrumentation.fragment.FragmentLifecycleInstru
import io.opentelemetry.android.instrumentation.network.NetworkAttributesExtractor
import io.opentelemetry.android.instrumentation.network.NetworkChangeInstrumentation
import io.opentelemetry.android.instrumentation.slowrendering.SlowRenderingInstrumentation
import io.opentelemetry.android.internal.services.Services
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter
Expand All @@ -40,6 +44,7 @@ object OpenTelemetryRumInitializer {
* @param logEndpointConnectivity Log-specific endpoint configuration.
* @param metricEndpointConnectivity Metric-specific endpoint configuration.
* @param rumConfig Configuration used by [OpenTelemetryRumBuilder].
* @param sessionConfig The session configuration, which includes inactivity timeout and maximum lifetime durations.
* @param activityTracerCustomizer Tracer customizer for [ActivityLifecycleInstrumentation].
* @param activityNameExtractor Name extractor for [ActivityLifecycleInstrumentation].
* @param fragmentTracerCustomizer Tracer customizer for [FragmentLifecycleInstrumentation].
Expand Down Expand Up @@ -70,6 +75,7 @@ object OpenTelemetryRumInitializer {
endpointHeaders,
),
rumConfig: OtelRumConfig = OtelRumConfig(),
sessionConfig: SessionConfig = SessionConfig.withDefaults(),
activityTracerCustomizer: ((Tracer) -> Tracer)? = null,
activityNameExtractor: ScreenNameExtractor? = null,
fragmentTracerCustomizer: ((Tracer) -> Tracer)? = null,
Expand All @@ -79,6 +85,60 @@ object OpenTelemetryRumInitializer {
networkChangeAttributesExtractors: List<NetworkAttributesExtractor> = emptyList(),
slowRenderingDetectionPollInterval: Duration? = null,
): OpenTelemetryRum {
configureInstrumentation(
activityTracerCustomizer,
activityNameExtractor,
fragmentTracerCustomizer,
fragmentNameExtractor,
anrAttributesExtractors,
crashAttributesExtractors,
networkChangeAttributesExtractors,
slowRenderingDetectionPollInterval,
)

return OpenTelemetryRum
.builder(application, rumConfig)
.setSessionProvider(createSessionManager(application, sessionConfig))
.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()
}

private fun createSessionManager(
application: Application,
sessionConfig: SessionConfig,
): SessionManager {
val timeoutHandler = SessionIdTimeoutHandler(sessionConfig)
Services.get(application).appLifecycle.registerListener(timeoutHandler)
return SessionManager.create(timeoutHandler, sessionConfig)
}

private fun configureInstrumentation(
activityTracerCustomizer: ((Tracer) -> Tracer)?,
activityNameExtractor: ScreenNameExtractor?,
fragmentTracerCustomizer: ((Tracer) -> Tracer)?,
fragmentNameExtractor: ScreenNameExtractor?,
anrAttributesExtractors: List<AttributesExtractor<Array<StackTraceElement>, Void>>,
crashAttributesExtractors: List<AttributesExtractor<CrashDetails, Void>>,
networkChangeAttributesExtractors: List<NetworkAttributesExtractor>,
slowRenderingDetectionPollInterval: Duration?,
) {
val activityLifecycleInstrumentation =
getInstrumentation<ActivityLifecycleInstrumentation>()
if (activityTracerCustomizer != null) {
Expand Down Expand Up @@ -123,28 +183,6 @@ object OpenTelemetryRumInitializer {
slowRenderingDetectionPollInterval,
)
}

return 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()
}

private inline fun <reified T : AndroidInstrumentation> getInstrumentation(): T? =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.config
package io.opentelemetry.android.agent.session

import kotlin.time.Duration
import kotlin.time.Duration.Companion.hours
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.session
package io.opentelemetry.android.agent.session

import io.opentelemetry.api.trace.TraceId
import java.util.Random
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.internal.session
package io.opentelemetry.android.agent.session

import io.opentelemetry.android.config.SessionConfig
import io.opentelemetry.android.internal.services.applifecycle.ApplicationStateListener
import io.opentelemetry.sdk.common.Clock
import kotlin.time.Duration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,24 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.internal.session
package io.opentelemetry.android.agent.session

import io.opentelemetry.android.config.SessionConfig
import io.opentelemetry.android.session.Session
import io.opentelemetry.android.session.SessionIdGenerator
import io.opentelemetry.android.session.SessionManager
import io.opentelemetry.android.session.SessionObserver
import io.opentelemetry.android.session.SessionStorage
import io.opentelemetry.android.session.SessionProvider
import io.opentelemetry.android.session.SessionPublisher
import io.opentelemetry.sdk.common.Clock
import java.util.Collections.synchronizedList
import kotlin.time.Duration

internal class SessionManagerImpl(
internal class SessionManager(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SessionManager will live only in the agent, and it will be our opinionated SessionProvider implementation.

private val clock: Clock = Clock.getDefault(),
private val sessionStorage: SessionStorage = SessionStorage.InMemory(),
private val timeoutHandler: SessionIdTimeoutHandler,
private val idGenerator: SessionIdGenerator = SessionIdGenerator.DEFAULT,
private val maxSessionLifetime: Duration,
) : SessionManager {
) : SessionProvider,
SessionPublisher {
// TODO: Make thread safe / wrap with AtomicReference?
private var session: Session = Session.NONE
private val observers = synchronizedList(ArrayList<SessionObserver>())
Expand Down Expand Up @@ -75,8 +74,8 @@ internal class SessionManagerImpl(
fun create(
timeoutHandler: SessionIdTimeoutHandler,
sessionConfig: SessionConfig,
): SessionManagerImpl =
SessionManagerImpl(
): SessionManager =
SessionManager(
timeoutHandler = timeoutHandler,
maxSessionLifetime = sessionConfig.maxLifetime,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.session
package io.opentelemetry.android.agent.session

import io.opentelemetry.android.session.Session

interface SessionStorage {
fun get(): Session
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.agent

import androidx.test.ext.junit.runners.AndroidJUnit4
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import io.opentelemetry.android.agent.session.SessionIdTimeoutHandler
import io.opentelemetry.android.internal.services.Services
import io.opentelemetry.android.internal.services.applifecycle.AppLifecycle
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RuntimeEnvironment

@RunWith(AndroidJUnit4::class)
class OpenTelemetryRumInitializerTest {
private lateinit var appLifecycle: AppLifecycle

@Before
fun setUp() {
appLifecycle = mockk(relaxed = true)
}

@Test
fun `Verify timeoutHandler initialization`() {
createAndSetServiceManager()

OpenTelemetryRumInitializer.initialize(
RuntimeEnvironment.getApplication(),
"http://127.0.0.1:4318",
)

verify {
appLifecycle.registerListener(any<SessionIdTimeoutHandler>())
}
}

@After
fun tearDown() {
Services.set(null)
}

private fun createAndSetServiceManager(): Services {
val services = mockk<Services>()
every { services.appLifecycle }.returns(appLifecycle)
every { services.currentNetworkProvider }.returns(mockk(relaxed = true))
every { services.visibleScreenTracker }.returns(mockk(relaxed = true))
Services.set(services)
return services
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.internal.session
package io.opentelemetry.android.agent.session

import io.opentelemetry.android.config.SessionConfig
import io.opentelemetry.sdk.testing.time.TestClock
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.internal.session
package io.opentelemetry.android.agent.session

import io.mockk.MockKAnnotations
import io.mockk.Runs
Expand All @@ -24,7 +24,7 @@ import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import kotlin.time.Duration.Companion.hours

internal class SessionManagerImplTest {
internal class SessionManagerTest {
@MockK
lateinit var timeoutHandler: SessionIdTimeoutHandler

Expand All @@ -38,7 +38,7 @@ internal class SessionManagerImplTest {
@Test
fun valueValid() {
val sessionManager =
SessionManagerImpl(
SessionManager(
TestClock.create(),
timeoutHandler = timeoutHandler,
maxSessionLifetime = 4.hours,
Expand All @@ -53,7 +53,7 @@ internal class SessionManagerImplTest {
fun valueSameUntil4Hours() {
val clock = TestClock.create()
val sessionManager =
SessionManagerImpl(
SessionManager(
clock,
timeoutHandler = timeoutHandler,
maxSessionLifetime = 4.hours,
Expand Down Expand Up @@ -82,7 +82,7 @@ internal class SessionManagerImplTest {
every { observer.onSessionEnded(any<Session>()) } just Runs

val sessionManager =
SessionManagerImpl(
SessionManager(
clock,
timeoutHandler = timeoutHandler,
maxSessionLifetime = 4.hours,
Expand Down Expand Up @@ -125,7 +125,8 @@ internal class SessionManagerImplTest {

@Test
fun shouldCreateNewSessionIdAfterTimeout() {
val sessionId = SessionManagerImpl(timeoutHandler = timeoutHandler, maxSessionLifetime = 4.hours)
val sessionId =
SessionManager(timeoutHandler = timeoutHandler, maxSessionLifetime = 4.hours)

val value = sessionId.getSessionId()
verify { timeoutHandler.bump() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@

import android.app.Application;
import io.opentelemetry.android.config.OtelRumConfig;
import io.opentelemetry.android.internal.services.Services;
import io.opentelemetry.android.internal.session.SessionIdTimeoutHandler;
import io.opentelemetry.android.internal.session.SessionManagerImpl;
import io.opentelemetry.android.session.SessionManager;
import io.opentelemetry.android.session.SessionProvider;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.OpenTelemetrySdk;
Expand Down Expand Up @@ -64,21 +61,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 config The {@link OtelRumConfig} instance.
* @param sessionProvider The {@link SessionProvider} instance.
*/
static SdkPreconfiguredRumBuilder builder(
Application application, OpenTelemetrySdk openTelemetrySdk, OtelRumConfig config) {

SessionIdTimeoutHandler timeoutHandler =
new SessionIdTimeoutHandler(config.getSessionConfig());
SessionManager sessionManager =
SessionManagerImpl.create(timeoutHandler, config.getSessionConfig());
Application application,
OpenTelemetrySdk openTelemetrySdk,
OtelRumConfig config,
SessionProvider sessionProvider) {
return new SdkPreconfiguredRumBuilder(
application,
openTelemetrySdk,
timeoutHandler,
sessionManager,
config,
Services.get(application));
application, openTelemetrySdk, sessionProvider, config);
}

/** Returns a no-op implementation of {@link OpenTelemetryRum}. */
Expand Down
Loading