Skip to content

Commit 54cebc8

Browse files
authored
Provide API for attaching custom measurements to transactions (#2260)
1 parent 7163f07 commit 54cebc8

File tree

22 files changed

+457
-36
lines changed

22 files changed

+457
-36
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Features
6+
7+
- Provide API for attaching custom measurements to transactions ([#2260](https://github.com/getsentry/sentry-java/pull/2260))
8+
39
## 6.5.0-beta.2
410

511
### Features

sentry-android-core/src/main/java/io/sentry/android/core/ActivityFramesTracker.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package io.sentry.android.core;
22

3-
import static io.sentry.protocol.MeasurementValue.NONE_UNIT;
4-
53
import android.app.Activity;
64
import android.util.SparseIntArray;
75
import androidx.core.app.FrameMetricsAggregator;
86
import io.sentry.ILogger;
7+
import io.sentry.MeasurementUnit;
98
import io.sentry.protocol.MeasurementValue;
109
import io.sentry.protocol.SentryId;
1110
import java.util.HashMap;
@@ -104,9 +103,9 @@ public synchronized void setMetrics(
104103
return;
105104
}
106105

107-
final MeasurementValue tfValues = new MeasurementValue(totalFrames, NONE_UNIT);
108-
final MeasurementValue sfValues = new MeasurementValue(slowFrames, NONE_UNIT);
109-
final MeasurementValue ffValues = new MeasurementValue(frozenFrames, NONE_UNIT);
106+
final MeasurementValue tfValues = new MeasurementValue(totalFrames, MeasurementUnit.NONE);
107+
final MeasurementValue sfValues = new MeasurementValue(slowFrames, MeasurementUnit.NONE);
108+
final MeasurementValue ffValues = new MeasurementValue(frozenFrames, MeasurementUnit.NONE);
110109
final Map<String, @NotNull MeasurementValue> measurements = new HashMap<>();
111110
measurements.put("frames_total", tfValues);
112111
measurements.put("frames_slow", sfValues);

sentry-android-core/src/main/java/io/sentry/android/core/PerformanceAndroidEventProcessor.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import static io.sentry.android.core.ActivityLifecycleIntegration.APP_START_COLD;
44
import static io.sentry.android.core.ActivityLifecycleIntegration.APP_START_WARM;
55
import static io.sentry.android.core.ActivityLifecycleIntegration.UI_LOAD_OP;
6-
import static io.sentry.protocol.MeasurementValue.MILLISECOND_UNIT;
76

87
import io.sentry.EventProcessor;
98
import io.sentry.Hint;
9+
import io.sentry.MeasurementUnit;
1010
import io.sentry.SentryEvent;
1111
import io.sentry.SpanContext;
1212
import io.sentry.protocol.MeasurementValue;
@@ -67,7 +67,8 @@ public SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) {
6767
// if appStartUpInterval is null, metrics are not ready to be sent
6868
if (appStartUpInterval != null) {
6969
final MeasurementValue value =
70-
new MeasurementValue((float) appStartUpInterval, MILLISECOND_UNIT);
70+
new MeasurementValue(
71+
(float) appStartUpInterval, MeasurementUnit.Duration.MILLISECOND.apiName());
7172

7273
final String appStartKey =
7374
AppStartState.getInstance().isColdStart() ? "app_start_cold" : "app_start_warm";

sentry-android-core/src/test/java/io/sentry/android/core/ActivityFramesTrackerTest.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class ActivityFramesTrackerTest {
4141
val metrics = sut.takeMetrics(fixture.sentryId)
4242
val totalFrames = metrics!!["frames_total"]
4343

44-
assertEquals(totalFrames!!.value, 1f)
44+
assertEquals(totalFrames!!.value, 1)
4545
assertEquals(totalFrames.unit, "none")
4646
}
4747

@@ -57,7 +57,7 @@ class ActivityFramesTrackerTest {
5757
val metrics = sut.takeMetrics(fixture.sentryId)
5858
val frozenFrames = metrics!!["frames_frozen"]
5959

60-
assertEquals(frozenFrames!!.value, 5f)
60+
assertEquals(frozenFrames!!.value, 5)
6161
assertEquals(frozenFrames.unit, "none")
6262
}
6363

@@ -73,7 +73,7 @@ class ActivityFramesTrackerTest {
7373
val metrics = sut.takeMetrics(fixture.sentryId)
7474
val slowFrames = metrics!!["frames_slow"]
7575

76-
assertEquals(slowFrames!!.value, 5f)
76+
assertEquals(slowFrames!!.value, 5)
7777
assertEquals(slowFrames.unit, "none")
7878
}
7979

@@ -93,13 +93,13 @@ class ActivityFramesTrackerTest {
9393
val metrics = sut.takeMetrics(fixture.sentryId)
9494

9595
val totalFrames = metrics!!["frames_total"]
96-
assertEquals(totalFrames!!.value, 111f)
96+
assertEquals(totalFrames!!.value, 111)
9797

9898
val frozenFrames = metrics["frames_frozen"]
99-
assertEquals(frozenFrames!!.value, 6f)
99+
assertEquals(frozenFrames!!.value, 6)
100100

101101
val slowFrames = metrics["frames_slow"]
102-
assertEquals(slowFrames!!.value, 5f)
102+
assertEquals(slowFrames!!.value, 5)
103103
}
104104

105105
@Test

sentry-android-core/src/test/java/io/sentry/android/core/PerformanceAndroidEventProcessorTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import com.nhaarman.mockitokotlin2.mock
55
import com.nhaarman.mockitokotlin2.whenever
66
import io.sentry.Hint
77
import io.sentry.IHub
8+
import io.sentry.MeasurementUnit
89
import io.sentry.SentryTracer
910
import io.sentry.TracesSamplingDecision
1011
import io.sentry.TransactionContext
1112
import io.sentry.android.core.ActivityLifecycleIntegration.UI_LOAD_OP
1213
import io.sentry.protocol.MeasurementValue
13-
import io.sentry.protocol.MeasurementValue.MILLISECOND_UNIT
1414
import io.sentry.protocol.SentryTransaction
1515
import java.util.Date
1616
import kotlin.test.BeforeTest
@@ -156,7 +156,7 @@ class PerformanceAndroidEventProcessorTest {
156156
val tracer = SentryTracer(context, fixture.hub)
157157
var tr = SentryTransaction(tracer)
158158

159-
val metrics = mapOf("frames_total" to MeasurementValue(1f, MILLISECOND_UNIT))
159+
val metrics = mapOf("frames_total" to MeasurementValue(1f, MeasurementUnit.Duration.MILLISECOND.apiName()))
160160
whenever(fixture.activityFramesTracker.takeMetrics(any())).thenReturn(metrics)
161161

162162
tr = sut.process(tr, Hint())

sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import androidx.appcompat.app.AppCompatActivity;
66
import io.sentry.Attachment;
77
import io.sentry.ISpan;
8+
import io.sentry.MeasurementUnit;
89
import io.sentry.Sentry;
910
import io.sentry.SpanStatus;
1011
import io.sentry.UserFeedback;
@@ -27,6 +28,7 @@
2728
public class MainActivity extends AppCompatActivity {
2829

2930
private int crashCount = 0;
31+
private int screenLoadCount = 0;
3032

3133
@Override
3234
protected void onCreate(Bundle savedInstanceState) {
@@ -200,8 +202,10 @@ protected void onCreate(Bundle savedInstanceState) {
200202
@Override
201203
protected void onResume() {
202204
super.onResume();
205+
screenLoadCount++;
203206
final ISpan span = Sentry.getSpan();
204207
if (span != null) {
208+
span.setMeasurement("screen_load_count", screenLoadCount, new MeasurementUnit.Custom("test"));
205209
span.finish(SpanStatus.OK);
206210
}
207211
}

sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/PersonService.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.sentry.samples.spring.boot;
22

3+
import io.sentry.ISpan;
4+
import io.sentry.Sentry;
35
import io.sentry.spring.tracing.SentrySpan;
46
import org.slf4j.Logger;
57
import org.slf4j.LoggerFactory;
@@ -16,12 +18,19 @@ public class PersonService {
1618
private static final Logger LOGGER = LoggerFactory.getLogger(PersonService.class);
1719

1820
private final JdbcTemplate jdbcTemplate;
21+
private int createCount = 0;
1922

2023
public PersonService(JdbcTemplate jdbcTemplate) {
2124
this.jdbcTemplate = jdbcTemplate;
2225
}
2326

2427
Person create(Person person) {
28+
createCount++;
29+
final ISpan span = Sentry.getSpan();
30+
if (span != null) {
31+
span.setMeasurement("create_count", createCount);
32+
}
33+
2534
jdbcTemplate.update(
2635
"insert into person (firstName, lastName) values (?, ?)",
2736
person.getFirstName(),

sentry/api/sentry.api

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,8 @@ public abstract interface class io/sentry/ISpan {
485485
public abstract fun isFinished ()Z
486486
public abstract fun setData (Ljava/lang/String;Ljava/lang/Object;)V
487487
public abstract fun setDescription (Ljava/lang/String;)V
488+
public abstract fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;)V
489+
public abstract fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;Lio/sentry/MeasurementUnit;)V
488490
public abstract fun setOperation (Ljava/lang/String;)V
489491
public abstract fun setStatus (Lio/sentry/SpanStatus;)V
490492
public abstract fun setTag (Ljava/lang/String;Ljava/lang/String;)V
@@ -599,6 +601,56 @@ public final class io/sentry/MainEventProcessor : io/sentry/EventProcessor, java
599601
public fun process (Lio/sentry/protocol/SentryTransaction;Lio/sentry/Hint;)Lio/sentry/protocol/SentryTransaction;
600602
}
601603

604+
public abstract interface class io/sentry/MeasurementUnit {
605+
public static final field NONE Ljava/lang/String;
606+
public fun apiName ()Ljava/lang/String;
607+
public abstract fun name ()Ljava/lang/String;
608+
}
609+
610+
public final class io/sentry/MeasurementUnit$Custom : io/sentry/MeasurementUnit {
611+
public fun <init> (Ljava/lang/String;)V
612+
public fun name ()Ljava/lang/String;
613+
}
614+
615+
public final class io/sentry/MeasurementUnit$Duration : java/lang/Enum, io/sentry/MeasurementUnit {
616+
public static final field DAY Lio/sentry/MeasurementUnit$Duration;
617+
public static final field HOUR Lio/sentry/MeasurementUnit$Duration;
618+
public static final field MICROSECOND Lio/sentry/MeasurementUnit$Duration;
619+
public static final field MILLISECOND Lio/sentry/MeasurementUnit$Duration;
620+
public static final field MINUTE Lio/sentry/MeasurementUnit$Duration;
621+
public static final field NANOSECOND Lio/sentry/MeasurementUnit$Duration;
622+
public static final field SECOND Lio/sentry/MeasurementUnit$Duration;
623+
public static final field WEEK Lio/sentry/MeasurementUnit$Duration;
624+
public static fun valueOf (Ljava/lang/String;)Lio/sentry/MeasurementUnit$Duration;
625+
public static fun values ()[Lio/sentry/MeasurementUnit$Duration;
626+
}
627+
628+
public final class io/sentry/MeasurementUnit$Fraction : java/lang/Enum, io/sentry/MeasurementUnit {
629+
public static final field PERCENT Lio/sentry/MeasurementUnit$Fraction;
630+
public static final field RATIO Lio/sentry/MeasurementUnit$Fraction;
631+
public static fun valueOf (Ljava/lang/String;)Lio/sentry/MeasurementUnit$Fraction;
632+
public static fun values ()[Lio/sentry/MeasurementUnit$Fraction;
633+
}
634+
635+
public final class io/sentry/MeasurementUnit$Information : java/lang/Enum, io/sentry/MeasurementUnit {
636+
public static final field BIT Lio/sentry/MeasurementUnit$Information;
637+
public static final field BYTE Lio/sentry/MeasurementUnit$Information;
638+
public static final field EXABYTE Lio/sentry/MeasurementUnit$Information;
639+
public static final field EXBIBYTE Lio/sentry/MeasurementUnit$Information;
640+
public static final field GIBIBYTE Lio/sentry/MeasurementUnit$Information;
641+
public static final field GIGABYTE Lio/sentry/MeasurementUnit$Information;
642+
public static final field KIBIBYTE Lio/sentry/MeasurementUnit$Information;
643+
public static final field KILOBYTE Lio/sentry/MeasurementUnit$Information;
644+
public static final field MEBIBYTE Lio/sentry/MeasurementUnit$Information;
645+
public static final field MEGABYTE Lio/sentry/MeasurementUnit$Information;
646+
public static final field PEBIBYTE Lio/sentry/MeasurementUnit$Information;
647+
public static final field PETABYTE Lio/sentry/MeasurementUnit$Information;
648+
public static final field TEBIBYTE Lio/sentry/MeasurementUnit$Information;
649+
public static final field TERABYTE Lio/sentry/MeasurementUnit$Information;
650+
public static fun valueOf (Ljava/lang/String;)Lio/sentry/MeasurementUnit$Information;
651+
public static fun values ()[Lio/sentry/MeasurementUnit$Information;
652+
}
653+
602654
public final class io/sentry/NoOpEnvelopeReader : io/sentry/IEnvelopeReader {
603655
public static fun getInstance ()Lio/sentry/NoOpEnvelopeReader;
604656
public fun read (Ljava/io/InputStream;)Lio/sentry/SentryEnvelope;
@@ -670,6 +722,8 @@ public final class io/sentry/NoOpSpan : io/sentry/ISpan {
670722
public fun isFinished ()Z
671723
public fun setData (Ljava/lang/String;Ljava/lang/Object;)V
672724
public fun setDescription (Ljava/lang/String;)V
725+
public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;)V
726+
public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;Lio/sentry/MeasurementUnit;)V
673727
public fun setOperation (Ljava/lang/String;)V
674728
public fun setStatus (Lio/sentry/SpanStatus;)V
675729
public fun setTag (Ljava/lang/String;Ljava/lang/String;)V
@@ -705,6 +759,8 @@ public final class io/sentry/NoOpTransaction : io/sentry/ITransaction {
705759
public fun scheduleFinish ()V
706760
public fun setData (Ljava/lang/String;Ljava/lang/Object;)V
707761
public fun setDescription (Ljava/lang/String;)V
762+
public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;)V
763+
public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;Lio/sentry/MeasurementUnit;)V
708764
public fun setName (Ljava/lang/String;)V
709765
public fun setName (Ljava/lang/String;Lio/sentry/protocol/TransactionNameSource;)V
710766
public fun setOperation (Ljava/lang/String;)V
@@ -1497,6 +1553,8 @@ public final class io/sentry/SentryTracer : io/sentry/ITransaction {
14971553
public fun scheduleFinish ()V
14981554
public fun setData (Ljava/lang/String;Ljava/lang/Object;)V
14991555
public fun setDescription (Ljava/lang/String;)V
1556+
public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;)V
1557+
public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;Lio/sentry/MeasurementUnit;)V
15001558
public fun setName (Ljava/lang/String;)V
15011559
public fun setName (Ljava/lang/String;Lio/sentry/protocol/TransactionNameSource;)V
15021560
public fun setOperation (Ljava/lang/String;)V
@@ -1603,6 +1661,8 @@ public final class io/sentry/Span : io/sentry/ISpan {
16031661
public fun isSampled ()Ljava/lang/Boolean;
16041662
public fun setData (Ljava/lang/String;Ljava/lang/Object;)V
16051663
public fun setDescription (Ljava/lang/String;)V
1664+
public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;)V
1665+
public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;Lio/sentry/MeasurementUnit;)V
16061666
public fun setOperation (Ljava/lang/String;)V
16071667
public fun setStatus (Lio/sentry/SpanStatus;)V
16081668
public fun setTag (Ljava/lang/String;Ljava/lang/String;)V
@@ -2449,13 +2509,11 @@ public final class io/sentry/protocol/Gpu$JsonKeys {
24492509
}
24502510

24512511
public final class io/sentry/protocol/MeasurementValue : io/sentry/JsonSerializable, io/sentry/JsonUnknown {
2452-
public static final field MILLISECOND_UNIT Ljava/lang/String;
2453-
public static final field NONE_UNIT Ljava/lang/String;
2454-
public fun <init> (FLjava/lang/String;)V
2455-
public fun <init> (FLjava/lang/String;Ljava/util/Map;)V
2512+
public fun <init> (Ljava/lang/Number;Ljava/lang/String;)V
2513+
public fun <init> (Ljava/lang/Number;Ljava/lang/String;Ljava/util/Map;)V
24562514
public fun getUnit ()Ljava/lang/String;
24572515
public fun getUnknown ()Ljava/util/Map;
2458-
public fun getValue ()F
2516+
public fun getValue ()Ljava/lang/Number;
24592517
public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V
24602518
public fun setUnknown (Ljava/util/Map;)V
24612519
}

sentry/src/main/java/io/sentry/ISpan.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,29 @@ ISpan startChild(
169169
*/
170170
@Nullable
171171
Object getData(@NotNull String key);
172+
173+
/**
174+
* Set a measurement without unit. When setting the measurement without the unit, no formatting
175+
* will be applied to the measurement value in the Sentry product, and the value will be shown as
176+
* is.
177+
*
178+
* <p>NOTE: Setting a measurement with the same name on the same transaction multiple times only
179+
* keeps the last value.
180+
*
181+
* @param name the name of the measurement
182+
* @param value the value of the measurement
183+
*/
184+
void setMeasurement(@NotNull String name, @NotNull Number value);
185+
186+
/**
187+
* Set a measurement with specific unit.
188+
*
189+
* <p>NOTE: Setting a measurement with the same name on the same transaction multiple times only
190+
* keeps the last value.
191+
*
192+
* @param name the name of the measurement
193+
* @param value the value of the measurement
194+
* @param unit the unit the value is measured in
195+
*/
196+
void setMeasurement(@NotNull String name, @NotNull Number value, @NotNull MeasurementUnit unit);
172197
}

0 commit comments

Comments
 (0)