Skip to content

Commit

Permalink
Instrumentation API part 7 (#465)
Browse files Browse the repository at this point in the history
* Removing fragment lifecycle callbacks from fragment instrumentation

* Adding FragmentLifecycleInstrumentation

* Removing lifecycle module

* Updating tests

* Reusing lifecycle instrumentation scope
  • Loading branch information
LikeTheSalad authored Jul 11, 2024
1 parent be5d084 commit e22ce45
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 246 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class VisibleFragmentTracker(private val visibleScreenService: VisibleScreenServ
fm: FragmentManager,
f: Fragment,
) {
super.onFragmentPaused(fm, f)
visibleScreenService.fragmentPaused(f)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.internal.services.visiblescreen.fragments

import androidx.fragment.app.Fragment
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.verify
import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

class VisibleFragmentTrackerTest {
private lateinit var service: VisibleScreenService
private lateinit var fragment: Fragment
private lateinit var visibleFragmentTracker: VisibleFragmentTracker

@BeforeEach
fun setUp() {
service = mockk()
fragment = mockk()
visibleFragmentTracker = VisibleFragmentTracker(service)
}

@Test
fun `Track fragment resumed`() {
every { service.fragmentResumed(any()) } just Runs

visibleFragmentTracker.onFragmentResumed(mockk(), fragment)

verify {
service.fragmentResumed(fragment)
}
}

@Test
fun `Track fragment paused`() {
every { service.fragmentPaused(any()) } just Runs

visibleFragmentTracker.onFragmentPaused(mockk(), fragment)

verify {
service.fragmentPaused(fragment)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import android.os.Build
import io.opentelemetry.android.OpenTelemetryRum
import io.opentelemetry.android.instrumentation.AndroidInstrumentation
import io.opentelemetry.android.instrumentation.activity.startup.AppStartupTimer
import io.opentelemetry.android.instrumentation.common.Constants.INSTRUMENTATION_SCOPE
import io.opentelemetry.android.instrumentation.common.ScreenNameExtractor
import io.opentelemetry.android.internal.services.ServiceManager
import io.opentelemetry.android.internal.services.visiblescreen.activities.DefaultingActivityLifecycleCallbacks
Expand All @@ -20,10 +21,6 @@ class ActivityLifecycleInstrumentation : AndroidInstrumentation {
private var screenNameExtractor: ScreenNameExtractor = ScreenNameExtractor.DEFAULT
private var tracerCustomizer: (Tracer) -> Tracer = { it }

companion object {
private const val INSTRUMENTATION_SCOPE: String = "io.opentelemetry.lifecycle"
}

fun setTracerCustomizer(customizer: (Tracer) -> Tracer) {
tracerCustomizer = customizer
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.instrumentation.common

object Constants {
const val INSTRUMENTATION_SCOPE = "io.opentelemetry.lifecycle"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.instrumentation.fragment

import android.app.Application
import android.app.Application.ActivityLifecycleCallbacks
import android.os.Build
import io.opentelemetry.android.OpenTelemetryRum
import io.opentelemetry.android.instrumentation.AndroidInstrumentation
import io.opentelemetry.android.instrumentation.common.Constants.INSTRUMENTATION_SCOPE
import io.opentelemetry.android.instrumentation.common.ScreenNameExtractor
import io.opentelemetry.android.internal.services.ServiceManager
import io.opentelemetry.android.internal.services.visiblescreen.fragments.RumFragmentActivityRegisterer
import io.opentelemetry.api.trace.Tracer

class FragmentLifecycleInstrumentation : AndroidInstrumentation {
private var screenNameExtractor = ScreenNameExtractor.DEFAULT
private var tracerCustomizer: (Tracer) -> Tracer = { it }

fun setTracerCustomizer(customizer: (Tracer) -> Tracer) {
tracerCustomizer = customizer
}

fun setScreenNameExtractor(screenNameExtractor: ScreenNameExtractor) {
this.screenNameExtractor = screenNameExtractor
}

override fun install(
application: Application,
openTelemetryRum: OpenTelemetryRum,
) {
application.registerActivityLifecycleCallbacks(buildFragmentRegisterer(openTelemetryRum))
}

private fun buildFragmentRegisterer(openTelemetryRum: OpenTelemetryRum): ActivityLifecycleCallbacks {
val visibleScreenService = ServiceManager.get().getVisibleScreenService()
val delegateTracer: Tracer = openTelemetryRum.openTelemetry.getTracer(INSTRUMENTATION_SCOPE)
val fragmentLifecycle =
RumFragmentLifecycleCallbacks(
tracerCustomizer.invoke(delegateTracer),
visibleScreenService::previouslyVisibleScreen,
screenNameExtractor,
)
return if (Build.VERSION.SDK_INT < 29) {
RumFragmentActivityRegisterer.createPre29(fragmentLifecycle)
} else {
RumFragmentActivityRegisterer.create(fragmentLifecycle)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,24 @@
import androidx.fragment.app.FragmentManager;
import io.opentelemetry.android.common.ActiveSpan;
import io.opentelemetry.android.instrumentation.common.ScreenNameExtractor;
import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService;
import io.opentelemetry.api.trace.Tracer;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

public class RumFragmentLifecycleCallbacks extends FragmentManager.FragmentLifecycleCallbacks {
private final Map<String, FragmentTracer> tracersByFragmentClassName = new HashMap<>();

private final Tracer tracer;
private final VisibleScreenService visibleScreenService;
private final Supplier<String> lastVisibleScreen;
private final ScreenNameExtractor screenNameExtractor;

public RumFragmentLifecycleCallbacks(
Tracer tracer,
VisibleScreenService visibleScreenService,
Supplier<String> lastVisibleScreen,
ScreenNameExtractor screenNameExtractor) {
this.tracer = tracer;
this.visibleScreenService = visibleScreenService;
this.lastVisibleScreen = lastVisibleScreen;
this.screenNameExtractor = screenNameExtractor;
}

Expand Down Expand Up @@ -87,13 +87,11 @@ public void onFragmentResumed(@NonNull FragmentManager fm, @NonNull Fragment f)
.addEvent("fragmentResumed")
.addPreviousScreenAttribute()
.endActiveSpan();
visibleScreenService.fragmentResumed(f);
}

@Override
public void onFragmentPaused(@NonNull FragmentManager fm, @NonNull Fragment f) {
super.onFragmentPaused(fm, f);
visibleScreenService.fragmentPaused(f);
getTracer(f).startSpanIfNoneInProgress("Paused").addEvent("fragmentPaused");
}

Expand Down Expand Up @@ -152,9 +150,7 @@ private FragmentTracer getTracer(Fragment fragment) {
FragmentTracer.builder(fragment)
.setTracer(tracer)
.setScreenName(screenNameExtractor.extract(fragment))
.setActiveSpan(
new ActiveSpan(
visibleScreenService::getPreviouslyVisibleScreen))
.setActiveSpan(new ActiveSpan(lastVisibleScreen))
.build();
tracersByFragmentClassName.put(fragment.getClass().getName(), activityTracer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import io.opentelemetry.android.instrumentation.common.ScreenNameExtractor;
import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService;
Expand Down Expand Up @@ -48,10 +49,7 @@ void setup() {

@Test
void fragmentCreation() {
FragmentCallbackTestHarness testHarness =
new FragmentCallbackTestHarness(
new RumFragmentLifecycleCallbacks(
tracer, visibleScreenService, screenNameExtractor));
FragmentCallbackTestHarness testHarness = getFragmentCallbackTestHarness();

Fragment fragment = mock(Fragment.class);
testHarness.runFragmentCreationLifecycle(fragment);
Expand Down Expand Up @@ -83,10 +81,7 @@ void fragmentCreation() {
@Test
void fragmentRestored() {
when(visibleScreenService.getPreviouslyVisibleScreen()).thenReturn("previousScreen");
FragmentCallbackTestHarness testHarness =
new FragmentCallbackTestHarness(
new RumFragmentLifecycleCallbacks(
tracer, visibleScreenService, screenNameExtractor));
FragmentCallbackTestHarness testHarness = getFragmentCallbackTestHarness();

Fragment fragment = mock(Fragment.class);
testHarness.runFragmentRestoredLifecycle(fragment);
Expand All @@ -113,10 +108,7 @@ void fragmentRestored() {

@Test
void fragmentResumed() {
FragmentCallbackTestHarness testHarness =
new FragmentCallbackTestHarness(
new RumFragmentLifecycleCallbacks(
tracer, visibleScreenService, screenNameExtractor));
FragmentCallbackTestHarness testHarness = getFragmentCallbackTestHarness();

Fragment fragment = mock(Fragment.class);
testHarness.runFragmentResumedLifecycle(fragment);
Expand All @@ -139,10 +131,7 @@ void fragmentResumed() {

@Test
void fragmentPaused() {
FragmentCallbackTestHarness testHarness =
new FragmentCallbackTestHarness(
new RumFragmentLifecycleCallbacks(
tracer, visibleScreenService, screenNameExtractor));
FragmentCallbackTestHarness testHarness = getFragmentCallbackTestHarness();

Fragment fragment = mock(Fragment.class);
testHarness.runFragmentPausedLifecycle(fragment);
Expand All @@ -168,10 +157,7 @@ void fragmentPaused() {

@Test
void fragmentDetachedFromActive() {
FragmentCallbackTestHarness testHarness =
new FragmentCallbackTestHarness(
new RumFragmentLifecycleCallbacks(
tracer, visibleScreenService, screenNameExtractor));
FragmentCallbackTestHarness testHarness = getFragmentCallbackTestHarness();

Fragment fragment = mock(Fragment.class);
testHarness.runFragmentDetachedFromActiveLifecycle(fragment);
Expand Down Expand Up @@ -224,10 +210,7 @@ void fragmentDetachedFromActive() {

@Test
void fragmentDestroyedFromStopped() {
FragmentCallbackTestHarness testHarness =
new FragmentCallbackTestHarness(
new RumFragmentLifecycleCallbacks(
tracer, visibleScreenService, screenNameExtractor));
FragmentCallbackTestHarness testHarness = getFragmentCallbackTestHarness();

Fragment fragment = mock(Fragment.class);
testHarness.runFragmentViewDestroyedFromStoppedLifecycle(fragment);
Expand All @@ -252,10 +235,7 @@ void fragmentDestroyedFromStopped() {

@Test
void fragmentDetachedFromStopped() {
FragmentCallbackTestHarness testHarness =
new FragmentCallbackTestHarness(
new RumFragmentLifecycleCallbacks(
tracer, visibleScreenService, screenNameExtractor));
FragmentCallbackTestHarness testHarness = getFragmentCallbackTestHarness();

Fragment fragment = mock(Fragment.class);
testHarness.runFragmentDetachedFromStoppedLifecycle(fragment);
Expand Down Expand Up @@ -294,10 +274,7 @@ void fragmentDetachedFromStopped() {

@Test
void fragmentDetached() {
FragmentCallbackTestHarness testHarness =
new FragmentCallbackTestHarness(
new RumFragmentLifecycleCallbacks(
tracer, visibleScreenService, screenNameExtractor));
FragmentCallbackTestHarness testHarness = getFragmentCallbackTestHarness();

Fragment fragment = mock(Fragment.class);
testHarness.runFragmentDetachedLifecycle(fragment);
Expand Down Expand Up @@ -326,4 +303,12 @@ private void checkEventExists(List<EventData> events, String eventName) {
events.stream().filter(e -> e.getName().equals(eventName)).findAny();
assertTrue(event.isPresent(), "Event with name " + eventName + " not found");
}

private @NonNull FragmentCallbackTestHarness getFragmentCallbackTestHarness() {
return new FragmentCallbackTestHarness(
new RumFragmentLifecycleCallbacks(
tracer,
visibleScreenService::getPreviouslyVisibleScreen,
screenNameExtractor));
}
}
27 changes: 0 additions & 27 deletions instrumentation/lifecycle/build.gradle.kts

This file was deleted.

Loading

0 comments on commit e22ce45

Please sign in to comment.