Skip to content

Commit 2fda34d

Browse files
authored
Merge f765bcf into c5ccd8a
2 parents c5ccd8a + f765bcf commit 2fda34d

File tree

16 files changed

+212
-15
lines changed

16 files changed

+212
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- Make user segment a top level property ([#2257](https://github.com/getsentry/sentry-java/pull/2257))
88
- Replace user `other` with `data` ([#2258](https://github.com/getsentry/sentry-java/pull/2258))
9+
- Provide API for attaching custom measurements to transactions ([#2260](https://github.com/getsentry/sentry-java/pull/2260))
910

1011
## 6.5.0-beta.1
1112

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

Lines changed: 7 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.SentryMeasurementUnit;
98
import io.sentry.protocol.MeasurementValue;
109
import io.sentry.protocol.SentryId;
1110
import java.util.HashMap;
@@ -104,9 +103,12 @@ 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 =
107+
new MeasurementValue(totalFrames, SentryMeasurementUnit.NONE.apiName());
108+
final MeasurementValue sfValues =
109+
new MeasurementValue(slowFrames, SentryMeasurementUnit.NONE.apiName());
110+
final MeasurementValue ffValues =
111+
new MeasurementValue(frozenFrames, SentryMeasurementUnit.NONE.apiName());
110112
final Map<String, @NotNull MeasurementValue> measurements = new HashMap<>();
111113
measurements.put("frames_total", tfValues);
112114
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,11 +3,11 @@
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;
109
import io.sentry.SentryEvent;
10+
import io.sentry.SentryMeasurementUnit;
1111
import io.sentry.SpanContext;
1212
import io.sentry.protocol.MeasurementValue;
1313
import io.sentry.protocol.SentryId;
@@ -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, SentryMeasurementUnit.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/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.SentryMeasurementUnit
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, SentryMeasurementUnit.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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
public class MainActivity extends AppCompatActivity {
2828

2929
private int crashCount = 0;
30+
private int screenLoadCount = 0;
3031

3132
@Override
3233
protected void onCreate(Bundle savedInstanceState) {
@@ -200,8 +201,10 @@ protected void onCreate(Bundle savedInstanceState) {
200201
@Override
201202
protected void onResume() {
202203
super.onResume();
204+
screenLoadCount++;
203205
final ISpan span = Sentry.getSpan();
204206
if (span != null) {
207+
span.setMeasurement("screen_load_count", screenLoadCount);
205208
span.finish(SpanStatus.OK);
206209
}
207210
}

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: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,8 @@ public abstract interface class io/sentry/ISpan {
483483
public abstract fun isFinished ()Z
484484
public abstract fun setData (Ljava/lang/String;Ljava/lang/Object;)V
485485
public abstract fun setDescription (Ljava/lang/String;)V
486+
public abstract fun setMeasurement (Ljava/lang/String;F)V
487+
public abstract fun setMeasurement (Ljava/lang/String;FLio/sentry/SentryMeasurementUnit;)V
486488
public abstract fun setOperation (Ljava/lang/String;)V
487489
public abstract fun setStatus (Lio/sentry/SpanStatus;)V
488490
public abstract fun setTag (Ljava/lang/String;Ljava/lang/String;)V
@@ -668,6 +670,8 @@ public final class io/sentry/NoOpSpan : io/sentry/ISpan {
668670
public fun isFinished ()Z
669671
public fun setData (Ljava/lang/String;Ljava/lang/Object;)V
670672
public fun setDescription (Ljava/lang/String;)V
673+
public fun setMeasurement (Ljava/lang/String;F)V
674+
public fun setMeasurement (Ljava/lang/String;FLio/sentry/SentryMeasurementUnit;)V
671675
public fun setOperation (Ljava/lang/String;)V
672676
public fun setStatus (Lio/sentry/SpanStatus;)V
673677
public fun setTag (Ljava/lang/String;Ljava/lang/String;)V
@@ -703,6 +707,8 @@ public final class io/sentry/NoOpTransaction : io/sentry/ITransaction {
703707
public fun scheduleFinish ()V
704708
public fun setData (Ljava/lang/String;Ljava/lang/Object;)V
705709
public fun setDescription (Ljava/lang/String;)V
710+
public fun setMeasurement (Ljava/lang/String;F)V
711+
public fun setMeasurement (Ljava/lang/String;FLio/sentry/SentryMeasurementUnit;)V
706712
public fun setName (Ljava/lang/String;)V
707713
public fun setName (Ljava/lang/String;Lio/sentry/protocol/TransactionNameSource;)V
708714
public fun setOperation (Ljava/lang/String;)V
@@ -1268,6 +1274,21 @@ public final class io/sentry/SentryLevel : java/lang/Enum, io/sentry/JsonSeriali
12681274
public static fun values ()[Lio/sentry/SentryLevel;
12691275
}
12701276

1277+
public final class io/sentry/SentryMeasurementUnit : java/lang/Enum {
1278+
public static final field DAY Lio/sentry/SentryMeasurementUnit;
1279+
public static final field HOUR Lio/sentry/SentryMeasurementUnit;
1280+
public static final field MICROSECOND Lio/sentry/SentryMeasurementUnit;
1281+
public static final field MILLISECOND Lio/sentry/SentryMeasurementUnit;
1282+
public static final field MINUTE Lio/sentry/SentryMeasurementUnit;
1283+
public static final field NANOSECOND Lio/sentry/SentryMeasurementUnit;
1284+
public static final field NONE Lio/sentry/SentryMeasurementUnit;
1285+
public static final field SECOND Lio/sentry/SentryMeasurementUnit;
1286+
public static final field WEEK Lio/sentry/SentryMeasurementUnit;
1287+
public fun apiName ()Ljava/lang/String;
1288+
public static fun valueOf (Ljava/lang/String;)Lio/sentry/SentryMeasurementUnit;
1289+
public static fun values ()[Lio/sentry/SentryMeasurementUnit;
1290+
}
1291+
12711292
public class io/sentry/SentryOptions {
12721293
public fun <init> ()V
12731294
public fun addContextTag (Ljava/lang/String;)V
@@ -1492,6 +1513,8 @@ public final class io/sentry/SentryTracer : io/sentry/ITransaction {
14921513
public fun scheduleFinish ()V
14931514
public fun setData (Ljava/lang/String;Ljava/lang/Object;)V
14941515
public fun setDescription (Ljava/lang/String;)V
1516+
public fun setMeasurement (Ljava/lang/String;F)V
1517+
public fun setMeasurement (Ljava/lang/String;FLio/sentry/SentryMeasurementUnit;)V
14951518
public fun setName (Ljava/lang/String;)V
14961519
public fun setName (Ljava/lang/String;Lio/sentry/protocol/TransactionNameSource;)V
14971520
public fun setOperation (Ljava/lang/String;)V
@@ -1598,6 +1621,8 @@ public final class io/sentry/Span : io/sentry/ISpan {
15981621
public fun isSampled ()Ljava/lang/Boolean;
15991622
public fun setData (Ljava/lang/String;Ljava/lang/Object;)V
16001623
public fun setDescription (Ljava/lang/String;)V
1624+
public fun setMeasurement (Ljava/lang/String;F)V
1625+
public fun setMeasurement (Ljava/lang/String;FLio/sentry/SentryMeasurementUnit;)V
16011626
public fun setOperation (Ljava/lang/String;)V
16021627
public fun setStatus (Lio/sentry/SpanStatus;)V
16031628
public fun setTag (Ljava/lang/String;Ljava/lang/String;)V
@@ -2444,8 +2469,6 @@ public final class io/sentry/protocol/Gpu$JsonKeys {
24442469
}
24452470

24462471
public final class io/sentry/protocol/MeasurementValue : io/sentry/JsonSerializable, io/sentry/JsonUnknown {
2447-
public static final field MILLISECOND_UNIT Ljava/lang/String;
2448-
public static final field NONE_UNIT Ljava/lang/String;
24492472
public fun <init> (FLjava/lang/String;)V
24502473
public fun <init> (FLjava/lang/String;Ljava/util/Map;)V
24512474
public fun getUnit ()Ljava/lang/String;

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,27 @@ ISpan startChild(
169169
*/
170170
@Nullable
171171
Object getData(@NotNull String key);
172+
173+
/**
174+
* Set a measurement with NONE unit.
175+
*
176+
* <p>NOTE: Setting a measurement with the same name on the same transaction multiple times only
177+
* keeps the last value.
178+
*
179+
* @param name the name of the measurement
180+
* @param value the value of the measurement
181+
*/
182+
void setMeasurement(@NotNull String name, float value);
183+
184+
/**
185+
* Set a measurement with specific unit.
186+
*
187+
* <p>NOTE: Setting a measurement with the same name on the same transaction multiple times only
188+
* keeps the last value.
189+
*
190+
* @param name the name of the measurement
191+
* @param value the value of the measurement
192+
* @param unit the unit the value is measured in
193+
*/
194+
void setMeasurement(@NotNull String name, float value, @NotNull SentryMeasurementUnit unit);
172195
}

sentry/src/main/java/io/sentry/NoOpSpan.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,11 @@ public void setData(@NotNull String key, @NotNull Object value) {}
111111
public @Nullable Object getData(@NotNull String key) {
112112
return null;
113113
}
114+
115+
@Override
116+
public void setMeasurement(@NotNull String name, float value) {}
117+
118+
@Override
119+
public void setMeasurement(
120+
@NotNull String name, float value, @NotNull SentryMeasurementUnit unit) {}
114121
}

sentry/src/main/java/io/sentry/NoOpTransaction.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,11 @@ public void setData(@NotNull String key, @NotNull Object value) {}
164164
public @Nullable Object getData(@NotNull String key) {
165165
return null;
166166
}
167+
168+
@Override
169+
public void setMeasurement(@NotNull String name, float value) {}
170+
171+
@Override
172+
public void setMeasurement(
173+
@NotNull String name, float value, @NotNull SentryMeasurementUnit unit) {}
167174
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.sentry;
2+
3+
import java.util.Locale;
4+
import org.jetbrains.annotations.NotNull;
5+
6+
public enum SentryMeasurementUnit {
7+
/** Nanosecond (`"nanosecond"`), 10^-9 seconds. */
8+
NANOSECOND,
9+
10+
/** Microsecond (`"microsecond"`), 10^-6 seconds. */
11+
MICROSECOND,
12+
13+
/** Millisecond (`"millisecond"`), 10^-3 seconds. */
14+
MILLISECOND,
15+
16+
/** Full second (`"second"`). */
17+
SECOND,
18+
19+
/** Minute (`"minute"`), 60 seconds. */
20+
MINUTE,
21+
22+
/** Hour (`"hour"`), 3600 seconds. */
23+
HOUR,
24+
25+
/** Day (`"day"`), 86,400 seconds. */
26+
DAY,
27+
28+
/** Week (`"week"`), 604,800 seconds. */
29+
WEEK,
30+
31+
/** Untyped value without a unit. */
32+
NONE;
33+
34+
public @NotNull String apiName() {
35+
return name().toLowerCase(Locale.ROOT);
36+
}
37+
}

sentry/src/main/java/io/sentry/SentryTracer.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.sentry;
22

3+
import io.sentry.protocol.MeasurementValue;
34
import io.sentry.protocol.SentryId;
45
import io.sentry.protocol.SentryTransaction;
56
import io.sentry.protocol.TransactionNameSource;
@@ -13,6 +14,7 @@
1314
import java.util.Map;
1415
import java.util.Timer;
1516
import java.util.TimerTask;
17+
import java.util.concurrent.ConcurrentHashMap;
1618
import java.util.concurrent.CopyOnWriteArrayList;
1719
import java.util.concurrent.atomic.AtomicBoolean;
1820
import java.util.concurrent.atomic.AtomicReference;
@@ -74,6 +76,7 @@ public final class SentryTracer implements ITransaction {
7476

7577
private final @NotNull Baggage baggage;
7678
private @NotNull TransactionNameSource transactionNameSource;
79+
private final @NotNull Map<String, MeasurementValue> measurements;
7780

7881
public SentryTracer(final @NotNull TransactionContext context, final @NotNull IHub hub) {
7982
this(context, hub, null);
@@ -104,6 +107,7 @@ public SentryTracer(
104107
final @Nullable TransactionFinishedCallback transactionFinishedCallback) {
105108
Objects.requireNonNull(context, "context is required");
106109
Objects.requireNonNull(hub, "hub is required");
110+
this.measurements = new ConcurrentHashMap<>();
107111
this.root = new Span(context, this, hub, startTimestamp);
108112
this.name = context.getName();
109113
this.hub = hub;
@@ -360,6 +364,9 @@ public void finish(@Nullable SpanStatus status) {
360364
// if it's an idle transaction which has no children, we drop it to save user's quota
361365
return;
362366
}
367+
368+
transaction.getMeasurements().putAll(measurements);
369+
363370
hub.captureTransaction(transaction, traceContext(), null, profilingTraceData);
364371
}
365372
}
@@ -506,6 +513,25 @@ public void setData(@NotNull String key, @NotNull Object value) {
506513
return this.root.getData(key);
507514
}
508515

516+
@Override
517+
public void setMeasurement(@NotNull String name, float value) {
518+
if (root.isFinished()) {
519+
return;
520+
}
521+
522+
this.measurements.put(name, new MeasurementValue(value, SentryMeasurementUnit.NONE.apiName()));
523+
}
524+
525+
@Override
526+
public void setMeasurement(
527+
@NotNull String name, float value, @NotNull SentryMeasurementUnit unit) {
528+
if (root.isFinished()) {
529+
return;
530+
}
531+
532+
this.measurements.put(name, new MeasurementValue(value, unit.apiName()));
533+
}
534+
509535
public @Nullable Map<String, Object> getData() {
510536
return this.root.getData();
511537
}
@@ -601,6 +627,12 @@ AtomicBoolean isFinishTimerRunning() {
601627
return isFinishTimerRunning;
602628
}
603629

630+
@TestOnly
631+
@NotNull
632+
Map<String, MeasurementValue> getMeasurements() {
633+
return measurements;
634+
}
635+
604636
private static final class FinishStatus {
605637
static final FinishStatus NOT_FINISHED = FinishStatus.notFinished();
606638

sentry/src/main/java/io/sentry/Span.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,17 @@ public void setData(@NotNull String key, @NotNull Object value) {
313313
return data.get(key);
314314
}
315315

316+
@Override
317+
public void setMeasurement(@NotNull String name, float value) {
318+
this.transaction.setMeasurement(name, value);
319+
}
320+
321+
@Override
322+
public void setMeasurement(
323+
@NotNull String name, float value, @NotNull SentryMeasurementUnit unit) {
324+
this.transaction.setMeasurement(name, value, unit);
325+
}
326+
316327
@Nullable
317328
Long getEndNanos() {
318329
return endNanos;

0 commit comments

Comments
 (0)