Skip to content

Commit 00fa630

Browse files
authored
Remove zero duration span from slow rendering instrumentation. (#1729)
* remove zero duration span from slow rendering instrumentation. * update changelog # Conflicts: # CHANGELOG.md
1 parent 68771b5 commit 00fa630

8 files changed

Lines changed: 32 additions & 264 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
## Unreleased
44

55
### ⚠️⚠️ Breaking changes
6-
6+
7+
- Slow rendering instrumentation no longer generates zero-duration spans, only events.
8+
([#1729](https://github.com/open-telemetry/opentelemetry-android/pull/1729))
79
- Remove deprecated sdk ready listeners. Users should use the otel ready listeners instead.
8-
([#1731](https://github.com/open-telemetry/opentelemetry-android/pull/1731))
10+
([#1731](https://github.com/open-telemetry/opentelemetry-android/pull/1731))
911

1012
## Version 1.3.0 (2026-04-22)
1113

instrumentation/slowrendering/README.md

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,6 @@ Generated when rendering takes more than 700ms within a polling period.
4141
* `app.jank.period` - the polling period duration in seconds during which the frames were detected
4242
* `app.jank.threshold` - the threshold in seconds above which a frame is considered frozen (e.g. `0.7`)
4343

44-
### Deprecated: Zero-Duration Spans
45-
46-
> **Deprecated.** Zero-duration spans are no longer emitted by default. They can be re-enabled
47-
> via `enableDeprecatedZeroDurationSpan()` for backwards compatibility, but this is discouraged.
48-
> Use the `app.jank` events above instead.
49-
50-
When enabled via `enableDeprecatedZeroDurationSpan()`, the instrumentation additionally produces
51-
spans with an instrumentation scope of `io.opentelemetry.slow-rendering`.
52-
53-
#### Slow Renders (Span)
54-
55-
* Type: Span (zero duration)
56-
* Name: `slowRenders`
57-
* Attributes:
58-
* `count` - the number of slow renders
59-
* `activity.name` - the name of the activity for which the slow render was detected
60-
61-
#### Frozen Renders (Span)
62-
63-
* Type: Span (zero duration)
64-
* Name: `frozenRenders`
65-
* Attributes:
66-
* `count` - the number of frozen renders
67-
* `activity.name` - the name of the activity for which the frozen render was detected
68-
6944
## Installation
7045

7146
This instrumentation comes with the [android agent](../../android-agent) out of the box, so

instrumentation/slowrendering/api/slowrendering.api

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
public final class io/opentelemetry/android/instrumentation/slowrendering/SlowRenderingInstrumentation : io/opentelemetry/android/instrumentation/AndroidInstrumentation {
22
public fun <init> ()V
3-
public final fun enableDeprecatedZeroDurationSpan ()Lio/opentelemetry/android/instrumentation/slowrendering/SlowRenderingInstrumentation;
43
public final fun enableVerboseDebugLogging ()Lio/opentelemetry/android/instrumentation/slowrendering/SlowRenderingInstrumentation;
54
public fun getName ()Ljava/lang/String;
65
public fun install (Landroid/content/Context;Lio/opentelemetry/android/OpenTelemetryRum;)V

instrumentation/slowrendering/src/main/java/io/opentelemetry/android/instrumentation/slowrendering/SlowRenderingInstrumentation.kt

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ import io.opentelemetry.android.common.RumConstants
1515
import io.opentelemetry.android.instrumentation.AndroidInstrumentation
1616
import java.time.Duration
1717

18+
internal const val SLOW_THRESHOLD_MS = 16
19+
internal const val FROZEN_THRESHOLD_MS = 700
20+
1821
/**
1922
* Entrypoint for installing the slow rendering detection instrumentation.
2023
*/
2124
@AutoService(AndroidInstrumentation::class)
2225
class SlowRenderingInstrumentation : AndroidInstrumentation {
23-
internal var useDeprecatedSpan: Boolean = false
2426
internal var debugVerbose: Boolean = false
2527
internal var slowRenderingDetectionPollInterval: Duration = Duration.ofSeconds(1)
2628

@@ -57,15 +59,6 @@ class SlowRenderingInstrumentation : AndroidInstrumentation {
5759
return this
5860
}
5961

60-
/**
61-
* Reports jank by using a zero-duration span.
62-
*/
63-
@Deprecated("Use the default event to report jank")
64-
fun enableDeprecatedZeroDurationSpan(): SlowRenderingInstrumentation {
65-
useDeprecatedSpan = true
66-
return this
67-
}
68-
6962
override fun install(context: Context, openTelemetryRum: OpenTelemetryRum) {
7063
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
7164
Log.w(
@@ -86,11 +79,6 @@ class SlowRenderingInstrumentation : AndroidInstrumentation {
8679
var jankReporter: JankReporter = EventJankReporter(logger, SLOW_THRESHOLD_MS / 1000.0, debugVerbose)
8780
jankReporter = jankReporter.combine(EventJankReporter(logger, FROZEN_THRESHOLD_MS / 1000.0, debugVerbose))
8881

89-
if (useDeprecatedSpan) {
90-
val tracer = openTelemetryRum.openTelemetry.getTracer("io.opentelemetry.slow-rendering")
91-
jankReporter = jankReporter.combine(SpanBasedJankReporter(tracer))
92-
}
93-
9482
detector = SlowRenderListener(jankReporter, slowRenderingDetectionPollInterval)
9583

9684
(context as? Application)?.registerActivityLifecycleCallbacks(detector)

instrumentation/slowrendering/src/main/java/io/opentelemetry/android/instrumentation/slowrendering/SpanBasedJankReporter.kt

Lines changed: 0 additions & 69 deletions
This file was deleted.

instrumentation/slowrendering/src/test/java/io/opentelemetry/android/instrumentation/slowrendering/SlowRenderListenerTest.kt

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,10 @@ import io.mockk.junit4.MockKRule
2020
import io.mockk.mockk
2121
import io.mockk.slot
2222
import io.mockk.verify
23-
import io.opentelemetry.api.common.AttributeKey
24-
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions
23+
import io.opentelemetry.api.logs.Logger
2524
import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule
26-
import io.opentelemetry.sdk.trace.data.SpanData
2725
import kotlinx.coroutines.Runnable
2826
import org.assertj.core.api.Assertions.assertThat
29-
import org.assertj.core.api.ThrowingConsumer
3027
import org.junit.Before
3128
import org.junit.Rule
3229
import org.junit.Test
@@ -134,8 +131,7 @@ class SlowRenderListenerTest {
134131

135132
@Test
136133
fun removeWithMetrics() {
137-
val tracer = otelTesting.openTelemetry.getTracer("testTracer")
138-
jankReporter = SpanBasedJankReporter(tracer)
134+
jankReporter = createEventReporter()
139135
val testInstance =
140136
SlowRenderListener(
141137
jankReporter,
@@ -160,8 +156,7 @@ class SlowRenderListenerTest {
160156

161157
testInstance.onActivityPaused(activity)
162158

163-
val spans = otelTesting.spans
164-
assertSpanContent(spans)
159+
assertLogContent(periodSeconds = 0.0)
165160
}
166161

167162
@Test
@@ -180,8 +175,7 @@ class SlowRenderListenerTest {
180175
null
181176
}
182177

183-
val tracer = otelTesting.openTelemetry.getTracer("testTracer")
184-
jankReporter = SpanBasedJankReporter(tracer)
178+
jankReporter = createEventReporter()
185179
val testInstance =
186180
SlowRenderListener(
187181
jankReporter,
@@ -206,8 +200,7 @@ class SlowRenderListenerTest {
206200

207201
testInstance.start()
208202

209-
val spans = otelTesting.spans
210-
assertSpanContent(spans)
203+
assertLogContent(periodSeconds = 1.0)
211204
}
212205

213206
@Test
@@ -235,36 +228,25 @@ class SlowRenderListenerTest {
235228
)
236229
}
237230

238-
companion object {
239-
private val COUNT_KEY: AttributeKey<Long> = AttributeKey.longKey("count")
240-
241-
private fun assertSpanContent(spans: MutableList<SpanData?>) {
242-
assertThat<SpanData>(spans)
243-
.hasSize(2)
244-
.satisfiesExactly(
245-
ThrowingConsumer { span ->
246-
OpenTelemetryAssertions
247-
.assertThat(span)
248-
.hasName("slowRenders")
249-
.endsAt(span!!.startEpochNanos)
250-
.hasAttribute(COUNT_KEY, 3L)
251-
.hasAttribute(
252-
AttributeKey.stringKey("activity.name"),
253-
"io.otel/Komponent",
254-
)
255-
},
256-
ThrowingConsumer { span ->
257-
OpenTelemetryAssertions
258-
.assertThat(span)
259-
.hasName("frozenRenders")
260-
.endsAt(span!!.startEpochNanos)
261-
.hasAttribute(COUNT_KEY, 1L)
262-
.hasAttribute(
263-
AttributeKey.stringKey("activity.name"),
264-
"io.otel/Komponent",
265-
)
266-
},
267-
)
268-
}
231+
private fun createEventReporter(): JankReporter {
232+
val eventLogger: Logger = otelTesting.openTelemetry.logsBridge.get("JANK!")
233+
return EventJankReporter(eventLogger, SLOW_THRESHOLD_MS / 1000.0)
234+
.combine(EventJankReporter(eventLogger, FROZEN_THRESHOLD_MS / 1000.0))
235+
}
236+
237+
private fun assertLogContent(periodSeconds: Double) {
238+
assertThat(otelTesting.logRecords).hasSize(2)
239+
240+
val slowLog = otelTesting.logRecords[0]
241+
assertThat(slowLog.eventName).isEqualTo("app.jank")
242+
assertThat(slowLog.attributes.get(FRAME_COUNT)).isEqualTo(4)
243+
assertThat(slowLog.attributes.get(PERIOD)).isEqualTo(periodSeconds)
244+
assertThat(slowLog.attributes.get(THRESHOLD)).isEqualTo(0.016)
245+
246+
val frozenLog = otelTesting.logRecords[1]
247+
assertThat(frozenLog.eventName).isEqualTo("app.jank")
248+
assertThat(frozenLog.attributes.get(FRAME_COUNT)).isEqualTo(1)
249+
assertThat(frozenLog.attributes.get(PERIOD)).isEqualTo(periodSeconds)
250+
assertThat(frozenLog.attributes.get(THRESHOLD)).isEqualTo(0.7)
269251
}
270252
}

instrumentation/slowrendering/src/test/java/io/opentelemetry/android/instrumentation/slowrendering/SlowRenderingInstrumentationTest.kt

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ class SlowRenderingInstrumentationTest {
9696
@Test
9797
fun `Installing instrumentation on devices with API level equal or higher than 24`() {
9898
val capturedListener = slot<SlowRenderListener>()
99-
every { openTelemetry.getTracer(any()) }.returns(mockk())
10099
every { application.registerActivityLifecycleCallbacks(any()) } just Runs
101100
val openTelemetryRum = mockk<OpenTelemetryRum>()
102101
every { openTelemetryRum.openTelemetry } returns openTelemetry
@@ -106,21 +105,4 @@ class SlowRenderingInstrumentationTest {
106105

107106
verify { application.registerActivityLifecycleCallbacks(capture(capturedListener)) }
108107
}
109-
110-
@Config(sdk = [24, 25])
111-
@Test
112-
fun `can use legacy span`() {
113-
val capturedListener = slot<SlowRenderListener>()
114-
every { openTelemetry.getTracer(any()) }.returns(mockk())
115-
every { application.registerActivityLifecycleCallbacks(any()) } just Runs
116-
val openTelemetryRum = mockk<OpenTelemetryRum>()
117-
every { openTelemetryRum.openTelemetry } returns openTelemetry
118-
every { openTelemetryRum.sessionProvider } returns mockk()
119-
every { openTelemetryRum.clock } returns Clock.getDefault()
120-
@Suppress("DEPRECATION")
121-
slowRenderingInstrumentation.enableDeprecatedZeroDurationSpan().install(application, openTelemetryRum)
122-
123-
verify { openTelemetry.getTracer("io.opentelemetry.slow-rendering") }
124-
verify { application.registerActivityLifecycleCallbacks(capture(capturedListener)) }
125-
}
126108
}

0 commit comments

Comments
 (0)