Skip to content

Commit b37cc4c

Browse files
runningcodeclaude
andauthored
docs(time): Steer new measurements at the io.sentry.time clock APIs (#6088)
* docs(time): Steer new measurements at the io.sentry.time clock APIs Document on each singleton clock's getInstance() that callers should read the ticker or wall clock off the options object instead, so they get the per-platform implementation rather than pinning themselves to one. Calling JavaMonotonicTicker.getInstance() on Android is the trap worth naming: it stops counting through a device suspend, so intervals spanning a deep sleep come out short. Add an AGENTS.md section so new measurement code reaches for io.sentry.time rather than DateUtils.getCurrentDateTime() or a SentryDateProvider, picks the abstraction by what the number is for, and treats adding a new abstraction as a deliberate step rather than a way around an awkward call site. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(time): Shorten the Measuring Time section in AGENTS.md Name the legacy clock interfaces instead of listing their implementations, which also covers ICurrentDateProvider. Drop the table's notes column and the history of why the old types remain, and cut the two rules to a sentence each. The getInstance() Javadoc already carries the detail where callers see it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(time): Shorten the getInstance() Javadoc on the clock singletons Drop the paragraph on when getInstance() may still be called directly. Only the options accessors and test support do, so it restated the code. Keep the one reason that matters: JavaMonotonicTicker stops counting while an Android device is suspended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent c015af1 commit b37cc4c

4 files changed

Lines changed: 33 additions & 0 deletions

File tree

‎AGENTS.md‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,29 @@ Two more rules that catch most of the rest:
213213

214214
Prefer `AutoClosableReentrantLock` over `synchronized`, matching the rest of the codebase.
215215

216+
### Measuring Time
217+
218+
**New code that reads a clock uses `io.sentry.time`**, not `System.currentTimeMillis()`,
219+
`System.nanoTime()`, `SystemClock`, `DateUtils.getCurrentDateTime()`, a `SentryDateProvider`, or an
220+
`ICurrentDateProvider`. Those are legacy, not a precedent to follow.
221+
222+
Pick the type by what the number is for:
223+
224+
| You need | Use |
225+
|---|---|
226+
| An instant that leaves the process (event, breadcrumb, session) | `EpochClock` → `Timestamp`. Never subtract two of them |
227+
| How long something took | `Stopwatch` |
228+
| Whether a window has elapsed (TTL, backoff, timeout) | `Deadline` |
229+
| Several instants compared with each other (spans of a transaction) | `AnchoredClock` |
230+
| A raw tick, when none of the above fits | `MonotonicTicker` |
231+
232+
Get the clock from `options.getEpochClock()` or `options.getMonotonicTicker()`, not a
233+
`getInstance()`: on Android the ticker keeps counting through device suspend, and `System.nanoTime()`
234+
does not. Take it as a constructor parameter; tests use `TestMonotonicTicker` instead of sleeping.
235+
236+
If none of these fits, propose a new type, and the clock bug it makes impossible, before writing
237+
call sites against it. Don't inline raw tick arithmetic as a stopgap.
238+
216239
### Testing Requirements
217240
- Write comprehensive unit tests for new features
218241
- Android modules require both unit tests and instrumented tests where applicable

‎sentry-android-core/src/main/java/io/sentry/android/core/internal/time/AndroidMonotonicTicker.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public final class AndroidMonotonicTicker implements MonotonicTicker {
1616

1717
private static final AndroidMonotonicTicker instance = new AndroidMonotonicTicker();
1818

19+
/** Prefer {@link io.sentry.SentryOptions#getMonotonicTicker()}; on Android it returns this. */
1920
public static @NotNull MonotonicTicker getInstance() {
2021
return instance;
2122
}

‎sentry/src/main/java/io/sentry/time/JavaMonotonicTicker.java‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ public final class JavaMonotonicTicker implements MonotonicTicker {
99

1010
private static final JavaMonotonicTicker instance = new JavaMonotonicTicker();
1111

12+
/**
13+
* Prefer {@link io.sentry.SentryOptions#getMonotonicTicker()}, which picks the platform's ticker.
14+
* On Android this one stops counting during device suspend, so intervals spanning a deep sleep
15+
* come out short.
16+
*/
1217
public static @NotNull MonotonicTicker getInstance() {
1318
return instance;
1419
}

‎sentry/src/main/java/io/sentry/time/SystemEpochClock.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ public final class SystemEpochClock implements EpochClock {
2424

2525
private static final SystemEpochClock instance = new SystemEpochClock();
2626

27+
/**
28+
* Prefer {@link io.sentry.SentryOptions#getEpochClock()}, which is where a platform would
29+
* substitute its own wall clock, the way Android already substitutes the ticker.
30+
*/
2731
public static @NotNull EpochClock getInstance() {
2832
return instance;
2933
}

0 commit comments

Comments
 (0)