Skip to content

Commit af1cdb1

Browse files
authored
Exposing SessionProvider setter (#979)
* Moving session manager to the agent * Addressing symbols in OpenTelemetryRumBuilder and SdkPreconfiguredRumBuilder * Moving some session interfaces to the session module to address SessionInstrumentation usage * Fixing and moving tests * Fixing tests * Fixing git conflicts * Renaming session provider variable
1 parent ec4ffe6 commit af1cdb1

24 files changed

Lines changed: 250 additions & 228 deletions

File tree

android-agent/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ android {
1010
dependencies {
1111
api(project(":core"))
1212
implementation(project(":common"))
13+
implementation(project(":session"))
14+
implementation(project(":services"))
1315
implementation(libs.opentelemetry.instrumentation.api)
1416
implementation(libs.opentelemetry.exporter.otlp)
1517

@@ -21,6 +23,8 @@ dependencies {
2123
api(project(":instrumentation:network"))
2224
api(project(":instrumentation:slowrendering"))
2325
api(project(":instrumentation:startup"))
26+
27+
testImplementation(libs.robolectric)
2428
}
2529

2630
extra["pomName"] = "OpenTelemetry Android Agent"

android-agent/src/main/kotlin/io/opentelemetry/android/agent/OpenTelemetryRumInitializer.kt

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import io.opentelemetry.android.OpenTelemetryRum
1010
import io.opentelemetry.android.OpenTelemetryRumBuilder
1111
import io.opentelemetry.android.agent.connectivity.EndpointConnectivity
1212
import io.opentelemetry.android.agent.connectivity.HttpEndpointConnectivity
13+
import io.opentelemetry.android.agent.session.SessionConfig
14+
import io.opentelemetry.android.agent.session.SessionIdTimeoutHandler
15+
import io.opentelemetry.android.agent.session.SessionManager
1316
import io.opentelemetry.android.config.OtelRumConfig
1417
import io.opentelemetry.android.instrumentation.AndroidInstrumentation
1518
import io.opentelemetry.android.instrumentation.AndroidInstrumentationLoader
@@ -22,6 +25,7 @@ import io.opentelemetry.android.instrumentation.fragment.FragmentLifecycleInstru
2225
import io.opentelemetry.android.instrumentation.network.NetworkAttributesExtractor
2326
import io.opentelemetry.android.instrumentation.network.NetworkChangeInstrumentation
2427
import io.opentelemetry.android.instrumentation.slowrendering.SlowRenderingInstrumentation
28+
import io.opentelemetry.android.internal.services.Services
2529
import io.opentelemetry.api.trace.Tracer
2630
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter
2731
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter
@@ -40,6 +44,7 @@ object OpenTelemetryRumInitializer {
4044
* @param logEndpointConnectivity Log-specific endpoint configuration.
4145
* @param metricEndpointConnectivity Metric-specific endpoint configuration.
4246
* @param rumConfig Configuration used by [OpenTelemetryRumBuilder].
47+
* @param sessionConfig The session configuration, which includes inactivity timeout and maximum lifetime durations.
4348
* @param activityTracerCustomizer Tracer customizer for [ActivityLifecycleInstrumentation].
4449
* @param activityNameExtractor Name extractor for [ActivityLifecycleInstrumentation].
4550
* @param fragmentTracerCustomizer Tracer customizer for [FragmentLifecycleInstrumentation].
@@ -70,6 +75,7 @@ object OpenTelemetryRumInitializer {
7075
endpointHeaders,
7176
),
7277
rumConfig: OtelRumConfig = OtelRumConfig(),
78+
sessionConfig: SessionConfig = SessionConfig.withDefaults(),
7379
activityTracerCustomizer: ((Tracer) -> Tracer)? = null,
7480
activityNameExtractor: ScreenNameExtractor? = null,
7581
fragmentTracerCustomizer: ((Tracer) -> Tracer)? = null,
@@ -79,6 +85,60 @@ object OpenTelemetryRumInitializer {
7985
networkChangeAttributesExtractors: List<NetworkAttributesExtractor> = emptyList(),
8086
slowRenderingDetectionPollInterval: Duration? = null,
8187
): OpenTelemetryRum {
88+
configureInstrumentation(
89+
activityTracerCustomizer,
90+
activityNameExtractor,
91+
fragmentTracerCustomizer,
92+
fragmentNameExtractor,
93+
anrAttributesExtractors,
94+
crashAttributesExtractors,
95+
networkChangeAttributesExtractors,
96+
slowRenderingDetectionPollInterval,
97+
)
98+
99+
return OpenTelemetryRum
100+
.builder(application, rumConfig)
101+
.setSessionProvider(createSessionManager(application, sessionConfig))
102+
.addSpanExporterCustomizer {
103+
OtlpHttpSpanExporter
104+
.builder()
105+
.setEndpoint(spanEndpointConnectivity.getUrl())
106+
.setHeaders(spanEndpointConnectivity::getHeaders)
107+
.build()
108+
}.addLogRecordExporterCustomizer {
109+
OtlpHttpLogRecordExporter
110+
.builder()
111+
.setEndpoint(logEndpointConnectivity.getUrl())
112+
.setHeaders(logEndpointConnectivity::getHeaders)
113+
.build()
114+
}.addMetricExporterCustomizer {
115+
OtlpHttpMetricExporter
116+
.builder()
117+
.setEndpoint(metricEndpointConnectivity.getUrl())
118+
.setHeaders(metricEndpointConnectivity::getHeaders)
119+
.build()
120+
}.build()
121+
}
122+
123+
private fun createSessionManager(
124+
application: Application,
125+
sessionConfig: SessionConfig,
126+
): SessionManager {
127+
val timeoutHandler = SessionIdTimeoutHandler(sessionConfig)
128+
Services.get(application).appLifecycle.registerListener(timeoutHandler)
129+
return SessionManager.create(timeoutHandler, sessionConfig)
130+
}
131+
132+
private fun configureInstrumentation(
133+
activityTracerCustomizer: ((Tracer) -> Tracer)?,
134+
activityNameExtractor: ScreenNameExtractor?,
135+
fragmentTracerCustomizer: ((Tracer) -> Tracer)?,
136+
fragmentNameExtractor: ScreenNameExtractor?,
137+
anrAttributesExtractors: List<AttributesExtractor<Array<StackTraceElement>, Void>>,
138+
crashAttributesExtractors: List<AttributesExtractor<CrashDetails, Void>>,
139+
networkChangeAttributesExtractors: List<NetworkAttributesExtractor>,
140+
slowRenderingDetectionPollInterval: Duration?,
141+
) {
82142
val activityLifecycleInstrumentation =
83143
getInstrumentation<ActivityLifecycleInstrumentation>()
84144
if (activityTracerCustomizer != null) {
@@ -123,28 +183,6 @@ object OpenTelemetryRumInitializer {
123183
slowRenderingDetectionPollInterval,
124184
)
125185
}
126-
127-
return OpenTelemetryRum
128-
.builder(application, rumConfig)
129-
.addSpanExporterCustomizer {
130-
OtlpHttpSpanExporter
131-
.builder()
132-
.setEndpoint(spanEndpointConnectivity.getUrl())
133-
.setHeaders(spanEndpointConnectivity::getHeaders)
134-
.build()
135-
}.addLogRecordExporterCustomizer {
136-
OtlpHttpLogRecordExporter
137-
.builder()
138-
.setEndpoint(logEndpointConnectivity.getUrl())
139-
.setHeaders(logEndpointConnectivity::getHeaders)
140-
.build()
141-
}.addMetricExporterCustomizer {
142-
OtlpHttpMetricExporter
143-
.builder()
144-
.setEndpoint(metricEndpointConnectivity.getUrl())
145-
.setHeaders(metricEndpointConnectivity::getHeaders)
146-
.build()
147-
}.build()
148186
}
149187

150188
private inline fun <reified T : AndroidInstrumentation> getInstrumentation(): T? =

core/src/main/java/io/opentelemetry/android/config/SessionConfig.kt renamed to android-agent/src/main/kotlin/io/opentelemetry/android/agent/session/SessionConfig.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.android.config
6+
package io.opentelemetry.android.agent.session
77

88
import kotlin.time.Duration
99
import kotlin.time.Duration.Companion.hours

session/src/main/kotlin/io/opentelemetry/android/session/SessionIdGenerator.kt renamed to android-agent/src/main/kotlin/io/opentelemetry/android/agent/session/SessionIdGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.android.session
6+
package io.opentelemetry.android.agent.session
77

88
import io.opentelemetry.api.trace.TraceId
99
import java.util.Random

core/src/main/java/io/opentelemetry/android/internal/session/SessionIdTimeoutHandler.kt renamed to android-agent/src/main/kotlin/io/opentelemetry/android/agent/session/SessionIdTimeoutHandler.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.android.internal.session
6+
package io.opentelemetry.android.agent.session
77

8-
import io.opentelemetry.android.config.SessionConfig
98
import io.opentelemetry.android.internal.services.applifecycle.ApplicationStateListener
109
import io.opentelemetry.sdk.common.Clock
1110
import kotlin.time.Duration

core/src/main/java/io/opentelemetry/android/internal/session/SessionManagerImpl.kt renamed to android-agent/src/main/kotlin/io/opentelemetry/android/agent/session/SessionManager.kt

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,24 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.android.internal.session
6+
package io.opentelemetry.android.agent.session
77

8-
import io.opentelemetry.android.config.SessionConfig
98
import io.opentelemetry.android.session.Session
10-
import io.opentelemetry.android.session.SessionIdGenerator
11-
import io.opentelemetry.android.session.SessionManager
129
import io.opentelemetry.android.session.SessionObserver
13-
import io.opentelemetry.android.session.SessionStorage
10+
import io.opentelemetry.android.session.SessionProvider
11+
import io.opentelemetry.android.session.SessionPublisher
1412
import io.opentelemetry.sdk.common.Clock
1513
import java.util.Collections.synchronizedList
1614
import kotlin.time.Duration
1715

18-
internal class SessionManagerImpl(
16+
internal class SessionManager(
1917
private val clock: Clock = Clock.getDefault(),
2018
private val sessionStorage: SessionStorage = SessionStorage.InMemory(),
2119
private val timeoutHandler: SessionIdTimeoutHandler,
2220
private val idGenerator: SessionIdGenerator = SessionIdGenerator.DEFAULT,
2321
private val maxSessionLifetime: Duration,
24-
) : SessionManager {
22+
) : SessionProvider,
23+
SessionPublisher {
2524
// TODO: Make thread safe / wrap with AtomicReference?
2625
private var session: Session = Session.NONE
2726
private val observers = synchronizedList(ArrayList<SessionObserver>())
@@ -75,8 +74,8 @@ internal class SessionManagerImpl(
7574
fun create(
7675
timeoutHandler: SessionIdTimeoutHandler,
7776
sessionConfig: SessionConfig,
78-
): SessionManagerImpl =
79-
SessionManagerImpl(
77+
): SessionManager =
78+
SessionManager(
8079
timeoutHandler = timeoutHandler,
8180
maxSessionLifetime = sessionConfig.maxLifetime,
8281
)

session/src/main/kotlin/io/opentelemetry/android/session/SessionStorage.kt renamed to android-agent/src/main/kotlin/io/opentelemetry/android/agent/session/SessionStorage.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.android.session
6+
package io.opentelemetry.android.agent.session
7+
8+
import io.opentelemetry.android.session.Session
79

810
interface SessionStorage {
911
fun get(): Session
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.android.agent
7+
8+
import androidx.test.ext.junit.runners.AndroidJUnit4
9+
import io.mockk.every
10+
import io.mockk.mockk
11+
import io.mockk.verify
12+
import io.opentelemetry.android.agent.session.SessionIdTimeoutHandler
13+
import io.opentelemetry.android.internal.services.Services
14+
import io.opentelemetry.android.internal.services.applifecycle.AppLifecycle
15+
import org.junit.After
16+
import org.junit.Before
17+
import org.junit.Test
18+
import org.junit.runner.RunWith
19+
import org.robolectric.RuntimeEnvironment
20+
21+
@RunWith(AndroidJUnit4::class)
22+
class OpenTelemetryRumInitializerTest {
23+
private lateinit var appLifecycle: AppLifecycle
24+
25+
@Before
26+
fun setUp() {
27+
appLifecycle = mockk(relaxed = true)
28+
}
29+
30+
@Test
31+
fun `Verify timeoutHandler initialization`() {
32+
createAndSetServiceManager()
33+
34+
OpenTelemetryRumInitializer.initialize(
35+
RuntimeEnvironment.getApplication(),
36+
"http://127.0.0.1:4318",
37+
)
38+
39+
verify {
40+
appLifecycle.registerListener(any<SessionIdTimeoutHandler>())
41+
}
42+
}
43+
44+
@After
45+
fun tearDown() {
46+
Services.set(null)
47+
}
48+
49+
private fun createAndSetServiceManager(): Services {
50+
val services = mockk<Services>()
51+
every { services.appLifecycle }.returns(appLifecycle)
52+
every { services.currentNetworkProvider }.returns(mockk(relaxed = true))
53+
every { services.visibleScreenTracker }.returns(mockk(relaxed = true))
54+
Services.set(services)
55+
return services
56+
}
57+
}

core/src/test/java/io/opentelemetry/android/internal/session/SessionIdTimeoutHandlerTest.kt renamed to android-agent/src/test/kotlin/io/opentelemetry/android/agent/session/SessionIdTimeoutHandlerTest.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.android.internal.session
6+
package io.opentelemetry.android.agent.session
77

8-
import io.opentelemetry.android.config.SessionConfig
98
import io.opentelemetry.sdk.testing.time.TestClock
109
import org.junit.jupiter.api.Assertions.assertFalse
1110
import org.junit.jupiter.api.Assertions.assertTrue

core/src/test/java/io/opentelemetry/android/internal/session/SessionManagerImplTest.kt renamed to android-agent/src/test/kotlin/io/opentelemetry/android/agent/session/SessionManagerTest.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.android.internal.session
6+
package io.opentelemetry.android.agent.session
77

88
import io.mockk.MockKAnnotations
99
import io.mockk.Runs
@@ -24,7 +24,7 @@ import java.util.concurrent.TimeUnit
2424
import java.util.regex.Pattern
2525
import kotlin.time.Duration.Companion.hours
2626

27-
internal class SessionManagerImplTest {
27+
internal class SessionManagerTest {
2828
@MockK
2929
lateinit var timeoutHandler: SessionIdTimeoutHandler
3030

@@ -38,7 +38,7 @@ internal class SessionManagerImplTest {
3838
@Test
3939
fun valueValid() {
4040
val sessionManager =
41-
SessionManagerImpl(
41+
SessionManager(
4242
TestClock.create(),
4343
timeoutHandler = timeoutHandler,
4444
maxSessionLifetime = 4.hours,
@@ -53,7 +53,7 @@ internal class SessionManagerImplTest {
5353
fun valueSameUntil4Hours() {
5454
val clock = TestClock.create()
5555
val sessionManager =
56-
SessionManagerImpl(
56+
SessionManager(
5757
clock,
5858
timeoutHandler = timeoutHandler,
5959
maxSessionLifetime = 4.hours,
@@ -82,7 +82,7 @@ internal class SessionManagerImplTest {
8282
every { observer.onSessionEnded(any<Session>()) } just Runs
8383

8484
val sessionManager =
85-
SessionManagerImpl(
85+
SessionManager(
8686
clock,
8787
timeoutHandler = timeoutHandler,
8888
maxSessionLifetime = 4.hours,
@@ -125,7 +125,8 @@ internal class SessionManagerImplTest {
125125

126126
@Test
127127
fun shouldCreateNewSessionIdAfterTimeout() {
128-
val sessionId = SessionManagerImpl(timeoutHandler = timeoutHandler, maxSessionLifetime = 4.hours)
128+
val sessionId =
129+
SessionManager(timeoutHandler = timeoutHandler, maxSessionLifetime = 4.hours)
129130

130131
val value = sessionId.getSessionId()
131132
verify { timeoutHandler.bump() }

0 commit comments

Comments
 (0)