Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor session manager #717

Merged
merged 4 commits into from
Jan 10, 2025
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
3 changes: 2 additions & 1 deletion core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ android {

dependencies {
implementation(project(":instrumentation:android-instrumentation"))
implementation(project(":services"))
implementation(project(":common"))
implementation(project(":services"))
implementation(project(":session"))

implementation(libs.androidx.core)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import io.opentelemetry.android.internal.services.ServiceManager;
import io.opentelemetry.android.internal.services.ServiceManagerImpl;
import io.opentelemetry.android.internal.services.periodicwork.PeriodicWorkService;
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.baggage.propagation.W3CBaggagePropagator;
Expand Down Expand Up @@ -302,7 +304,7 @@ public OpenTelemetryRum build() {
new BufferDelegatingSpanExporter();

SessionManager sessionManager =
SessionManager.create(timeoutHandler, config.getSessionTimeout().toNanos());
SessionManagerImpl.create(timeoutHandler, config.getSessionTimeout().toNanos());

OpenTelemetrySdk sdk =
OpenTelemetrySdk.builder()
Expand Down Expand Up @@ -373,6 +375,8 @@ private void initializeExporters(
}
initializationEvents.spanExporterInitialized(spanExporter);

SessionManager sessionManager =
SessionManagerImpl.create(timeoutHandler, config.getSessionTimeout().toNanos());
bufferedDelegatingLogExporter.setDelegate(logsExporter);

bufferDelegatingSpanExporter.setDelegate(spanExporter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import io.opentelemetry.android.instrumentation.AndroidInstrumentation
import io.opentelemetry.android.instrumentation.AndroidInstrumentationLoader
import io.opentelemetry.android.instrumentation.InstallationContext
import io.opentelemetry.android.internal.services.ServiceManager
import io.opentelemetry.android.internal.session.SessionIdTimeoutHandler
import io.opentelemetry.android.internal.session.SessionManagerImpl
import io.opentelemetry.android.session.SessionManager
import io.opentelemetry.sdk.OpenTelemetrySdk

Expand All @@ -19,7 +21,7 @@ class SdkPreconfiguredRumBuilder
private val application: Application,
private val sdk: OpenTelemetrySdk,
private val timeoutHandler: SessionIdTimeoutHandler = SessionIdTimeoutHandler(),
private val sessionManager: SessionManager = SessionManager(timeoutHandler = timeoutHandler),
private val sessionManager: SessionManager = SessionManagerImpl(timeoutHandler = timeoutHandler),
private val discoverInstrumentations: Boolean,
private val serviceManager: ServiceManager,
) {
Expand Down

This file was deleted.

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

package io.opentelemetry.android.internal.session

import io.opentelemetry.android.internal.services.applifecycle.ApplicationStateListener
import io.opentelemetry.sdk.common.Clock
import java.time.Duration

/**
* This class encapsulates the following criteria about the sessionId timeout:
*
*
* * If the app is in the foreground sessionId should never time out.
* * If the app is in the background and no activity (spans) happens for >15 minutes, sessionId
* should time out.
* * If the app is in the background and some activity (spans) happens in <15 minute intervals,
* sessionId should not time out.
*
*
* Consequently, when the app spent >15 minutes without any activity (spans) in the background,
* after moving to the foreground the first span should trigger the sessionId timeout.
*/
internal class SessionIdTimeoutHandler(
private val clock: Clock,
private val sessionTimeout: Duration,
) : ApplicationStateListener {
@Volatile
private var timeoutStartNanos: Long = 0

@Volatile
private var state = State.FOREGROUND

// for testing
@JvmOverloads
internal constructor(sessionTimeout: Duration = DEFAULT_SESSION_TIMEOUT) : this(
Clock.getDefault(),
sessionTimeout,
)

override fun onApplicationForegrounded() {
state = State.TRANSITIONING_TO_FOREGROUND
}

override fun onApplicationBackgrounded() {
state = State.BACKGROUND
}

fun hasTimedOut(): Boolean {
// don't apply sessionId timeout to apps in the foreground
if (state == State.FOREGROUND) {
return false
}
val elapsedTime = clock.nanoTime() - timeoutStartNanos
return elapsedTime >= sessionTimeout.toNanos()
}

fun bump() {
timeoutStartNanos = clock.nanoTime()

// move from the temporary transition state to foreground after the first span
if (state == State.TRANSITIONING_TO_FOREGROUND) {
state = State.FOREGROUND
}
}

private enum class State {
FOREGROUND,
BACKGROUND,

/** A temporary state representing the first event after the app has been brought back. */
TRANSITIONING_TO_FOREGROUND,
}

companion object {
@JvmField
val DEFAULT_SESSION_TIMEOUT: Duration = Duration.ofMinutes(15)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,24 @@
* SPDX-License-Identifier: Apache-2.0
*/

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

import io.opentelemetry.android.SessionIdTimeoutHandler
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.sdk.common.Clock
import java.util.Collections.synchronizedList
import java.util.concurrent.TimeUnit

internal class SessionManager(
internal class SessionManagerImpl(
private val clock: Clock = Clock.getDefault(),
private val sessionStorage: SessionStorage = SessionStorage.InMemory(),
private val timeoutHandler: SessionIdTimeoutHandler,
private val idGenerator: SessionIdGenerator = SessionIdGenerator.DEFAULT,
private val sessionLifetimeNanos: Long = TimeUnit.HOURS.toNanos(4),
) : SessionProvider,
SessionPublisher {
) : SessionManager {
// TODO: Make thread safe / wrap with AtomicReference?
private var session: Session = Session.NONE
private val observers = synchronizedList(ArrayList<SessionObserver>())
Expand Down Expand Up @@ -70,8 +73,8 @@ internal class SessionManager(
fun create(
timeoutHandler: SessionIdTimeoutHandler,
sessionLifetimeNanos: Long,
): SessionManager =
SessionManager(
): SessionManagerImpl =
SessionManagerImpl(
timeoutHandler = timeoutHandler,
sessionLifetimeNanos = sessionLifetimeNanos,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import io.opentelemetry.android.internal.services.applifecycle.AppLifecycleService;
import io.opentelemetry.android.internal.services.applifecycle.ApplicationStateListener;
import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService;
import io.opentelemetry.android.internal.session.SessionIdTimeoutHandler;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.KeyValue;
import io.opentelemetry.api.common.Value;
Expand Down

This file was deleted.

Loading
Loading