Skip to content

Commit

Permalink
Merge dcc2252 into a33b076
Browse files Browse the repository at this point in the history
  • Loading branch information
markushi committed Apr 26, 2024
2 parents a33b076 + dcc2252 commit 6a610ad
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Features

- Add start_type to app context ([#3379](https://github.com/getsentry/sentry-java/pull/3379))
- Add ttid/ttfd contribution flags ([#3386](https://github.com/getsentry/sentry-java/pull/3386))

### Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ public SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) {
appContext.setStartType(appStartType);
}

setContributingFlags(transaction);

final SentryId eventId = transaction.getEventId();
final SpanContext spanContext = transaction.getContexts().getTrace();

Expand All @@ -135,6 +137,60 @@ public SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) {
return transaction;
}

private void setContributingFlags(SentryTransaction transaction) {

@Nullable SentrySpan ttidSpan = null;
@Nullable SentrySpan ttfdSpan = null;
for (final @NotNull SentrySpan span : transaction.getSpans()) {
if (ActivityLifecycleIntegration.TTID_OP.equals(span.getOp())) {
ttidSpan = span;
} else if (ActivityLifecycleIntegration.TTFD_OP.equals(span.getOp())) {
ttfdSpan = span;
}
// once both are found we can early exit
if (ttidSpan != null && ttfdSpan != null) {
break;
}
}

if (ttidSpan == null && ttfdSpan == null) {
return;
}

for (final @NotNull SentrySpan span : transaction.getSpans()) {
// as ttid and ttfd spans are artificially created, we don't want to set the flags on them
if (span == ttidSpan || span == ttfdSpan) {
continue;
}

// TODO should we only consider spans running on the main thread?
final boolean withinTtid =
(ttidSpan != null) && isTimestampWithinSpan(span.getStartTimestamp(), ttidSpan);
final boolean withinTtfd =
(ttfdSpan != null) && isTimestampWithinSpan(span.getStartTimestamp(), ttfdSpan);

if (withinTtid || withinTtfd) {
@Nullable Map<String, Object> data = span.getData();
if (data == null) {
data = new ConcurrentHashMap<>();
span.setData(data);
}
if (withinTtid) {
data.put(SpanDataConvention.CONTRIBUTES_TTID, true);
}
if (withinTtfd) {
data.put(SpanDataConvention.CONTRIBUTES_TTFD, true);
}
}
}
}

private static boolean isTimestampWithinSpan(
final double timestamp, final @NotNull SentrySpan target) {
return timestamp >= target.getStartTimestamp()
&& (target.getTimestamp() == null || timestamp <= target.getTimestamp());
}

private boolean hasAppStartSpan(final @NotNull SentryTransaction txn) {
final @NotNull List<SentrySpan> spans = txn.getSpans();
for (final @NotNull SentrySpan span : spans) {
Expand Down Expand Up @@ -253,6 +309,9 @@ private static SentrySpan timeSpanToSentrySpan(
defaultSpanData.put(SpanDataConvention.THREAD_ID, Looper.getMainLooper().getThread().getId());
defaultSpanData.put(SpanDataConvention.THREAD_NAME, "main");

defaultSpanData.put(SpanDataConvention.CONTRIBUTES_TTID, true);
defaultSpanData.put(SpanDataConvention.CONTRIBUTES_TTFD, true);

return new SentrySpan(
span.getStartTimestampSecs(),
span.getProjectedStopTimestampSecs(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import io.sentry.IHub
import io.sentry.MeasurementUnit
import io.sentry.SentryTracer
import io.sentry.SpanContext
import io.sentry.SpanDataConvention
import io.sentry.SpanId
import io.sentry.SpanStatus
import io.sentry.TracesSamplingDecision
Expand Down Expand Up @@ -519,6 +520,164 @@ class PerformanceAndroidEventProcessorTest {
)
}

@Test
fun `adds ttid and ttfd contributing span data`() {
val sut = fixture.getSut()

val context = TransactionContext("Activity", UI_LOAD_OP)
val tracer = SentryTracer(context, fixture.hub)
val tr = SentryTransaction(tracer)

// given a ttid from 0.0 -> 1.0
// and a ttfd from 0.0 -> 2.0
val ttid = SentrySpan(
0.0,
1.0,
tr.contexts.trace!!.traceId,
SpanId(),
null,
ActivityLifecycleIntegration.TTID_OP,
"App Start",
SpanStatus.OK,
null,
emptyMap(),
emptyMap(),
null,
null
)

val ttfd = SentrySpan(
0.0,
2.0,
tr.contexts.trace!!.traceId,
SpanId(),
null,
ActivityLifecycleIntegration.TTFD_OP,
"App Start",
SpanStatus.OK,
null,
emptyMap(),
emptyMap(),
null,
null
)
tr.spans.add(ttid)
tr.spans.add(ttfd)

// and 3 spans
// one from 0.0 -> 0.5
val ttidContrib = SentrySpan(
0.0,
0.5,
tr.contexts.trace!!.traceId,
SpanId(),
null,
"example.op",
"",
SpanStatus.OK,
null,
emptyMap(),
emptyMap(),
null,
null
)

// and another from 1.5 -> 3.5
val ttfdContrib = SentrySpan(
1.5,
3.5,
tr.contexts.trace!!.traceId,
SpanId(),
null,
"example.op",
"",
SpanStatus.OK,
null,
emptyMap(),
emptyMap(),
null,
null
)

// and another from 2.1 -> 2.2
val outsideSpan = SentrySpan(
2.1,
2.2,
tr.contexts.trace!!.traceId,
SpanId(),
null,
"example.op",
"",
SpanStatus.OK,
null,
emptyMap(),
emptyMap(),
null,
mutableMapOf<String, Any>(
"tag" to "value"
)
)

tr.spans.add(ttidContrib)
tr.spans.add(ttfdContrib)

// when the processor processes the txn
sut.process(tr, Hint())

// then the ttid/ttfd spans themselves should have no flags set
assertNull(ttid.data?.get(SpanDataConvention.CONTRIBUTES_TTID))
assertNull(ttid.data?.get(SpanDataConvention.CONTRIBUTES_TTFD))

assertNull(ttfd.data?.get(SpanDataConvention.CONTRIBUTES_TTID))
assertNull(ttfd.data?.get(SpanDataConvention.CONTRIBUTES_TTFD))

// then the first span should have ttid and ttfd contributing flags
assertTrue(ttidContrib.data?.get(SpanDataConvention.CONTRIBUTES_TTID) == true)
assertTrue(ttidContrib.data?.get(SpanDataConvention.CONTRIBUTES_TTFD) == true)

// and the second one should contribute to ttfd only
assertNull(ttfdContrib.data?.get(SpanDataConvention.CONTRIBUTES_TTID))
assertTrue(ttfdContrib.data?.get(SpanDataConvention.CONTRIBUTES_TTFD) == true)

// and the third span should have no flags attached, as it's outside ttid/ttfd
assertNull(outsideSpan.data?.get(SpanDataConvention.CONTRIBUTES_TTID))
assertNull(outsideSpan.data?.get(SpanDataConvention.CONTRIBUTES_TTFD))
}

@Test
fun `adds no ttid and ttfd contributing span data if txn contains no ttid or ttfd`() {
val sut = fixture.getSut()

val context = TransactionContext("Activity", UI_LOAD_OP)
val tracer = SentryTracer(context, fixture.hub)
val tr = SentryTransaction(tracer)

val span = SentrySpan(
0.0,
1.0,
tr.contexts.trace!!.traceId,
SpanId(),
null,
"example.op",
"",
SpanStatus.OK,
null,
emptyMap(),
emptyMap(),
null,
null
)

tr.spans.add(span)

// when the processor processes the txn
sut.process(tr, Hint())

// the span should have no flags attached
assertNull(span.data?.get(SpanDataConvention.CONTRIBUTES_TTID))
assertNull(span.data?.get(SpanDataConvention.CONTRIBUTES_TTFD))
}

private fun setAppStart(options: SentryAndroidOptions, coldStart: Boolean = true) {
AppStartMetrics.getInstance().apply {
appStartType = when (coldStart) {
Expand Down
3 changes: 3 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -2740,6 +2740,8 @@ public final class io/sentry/SpanContext$JsonKeys {
public abstract interface class io/sentry/SpanDataConvention {
public static final field BLOCKED_MAIN_THREAD_KEY Ljava/lang/String;
public static final field CALL_STACK_KEY Ljava/lang/String;
public static final field CONTRIBUTES_TTFD Ljava/lang/String;
public static final field CONTRIBUTES_TTID Ljava/lang/String;
public static final field DB_NAME_KEY Ljava/lang/String;
public static final field DB_SYSTEM_KEY Ljava/lang/String;
public static final field FRAMES_DELAY Ljava/lang/String;
Expand Down Expand Up @@ -4459,6 +4461,7 @@ public final class io/sentry/protocol/SentrySpan : io/sentry/JsonSerializable, i
public fun getUnknown ()Ljava/util/Map;
public fun isFinished ()Z
public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V
public fun setData (Ljava/util/Map;)V
public fun setUnknown (Ljava/util/Map;)V
}

Expand Down
2 changes: 2 additions & 0 deletions sentry/src/main/java/io/sentry/SpanDataConvention.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ public interface SpanDataConvention {
String FRAMES_SLOW = "frames.slow";
String FRAMES_FROZEN = "frames.frozen";
String FRAMES_DELAY = "frames.delay";
String CONTRIBUTES_TTID = "ui.contributes_ttid";
String CONTRIBUTES_TTFD = "ui.contributes_ttfd";
}
6 changes: 5 additions & 1 deletion sentry/src/main/java/io/sentry/protocol/SentrySpan.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public final class SentrySpan implements JsonUnknown, JsonSerializable {

private final @Nullable String origin;
private final @NotNull Map<String, String> tags;
private final @Nullable Map<String, Object> data;
private @Nullable Map<String, Object> data;

private final @NotNull Map<String, @NotNull MeasurementValue> measurements;
private final @Nullable Map<String, List<MetricSummary>> metricsSummaries;
Expand Down Expand Up @@ -159,6 +159,10 @@ public boolean isFinished() {
return data;
}

public void setData(final @Nullable Map<String, Object> data) {
this.data = data;
}

public @Nullable String getOrigin() {
return origin;
}
Expand Down

0 comments on commit 6a610ad

Please sign in to comment.