Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,29 @@ Two more rules that catch most of the rest:

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

### Measuring Time

**New code that reads a clock uses `io.sentry.time`**, not `System.currentTimeMillis()`,
`System.nanoTime()`, `SystemClock`, `DateUtils.getCurrentDateTime()`, a `SentryDateProvider`, or an
`ICurrentDateProvider`. Those are legacy, not a precedent to follow.

Pick the type by what the number is for:

| You need | Use |
|---|---|
| An instant that leaves the process (event, breadcrumb, session) | `EpochClock` → `Timestamp`. Never subtract two of them |
| How long something took | `Stopwatch` |
| Whether a window has elapsed (TTL, backoff, timeout) | `Deadline` |
| Several instants compared with each other (spans of a transaction) | `AnchoredClock` |
| A raw tick, when none of the above fits | `MonotonicTicker` |

Get the clock from `options.getEpochClock()` or `options.getMonotonicTicker()`, not a
`getInstance()`: on Android the ticker keeps counting through device suspend, and `System.nanoTime()`
does not. Take it as a constructor parameter; tests use `TestMonotonicTicker` instead of sleeping.

If none of these fits, propose a new type, and the clock bug it makes impossible, before writing
call sites against it. Don't inline raw tick arithmetic as a stopgap.

### Testing Requirements
- Write comprehensive unit tests for new features
- Android modules require both unit tests and instrumented tests where applicable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public final class AndroidMonotonicTicker implements MonotonicTicker {

private static final AndroidMonotonicTicker instance = new AndroidMonotonicTicker();

/** Prefer {@link io.sentry.SentryOptions#getMonotonicTicker()}; on Android it returns this. */
public static @NotNull MonotonicTicker getInstance() {
return instance;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public final class JavaMonotonicTicker implements MonotonicTicker {

private static final JavaMonotonicTicker instance = new JavaMonotonicTicker();

/**
* Prefer {@link io.sentry.SentryOptions#getMonotonicTicker()}, which picks the platform's ticker.
* On Android this one stops counting during device suspend, so intervals spanning a deep sleep
* come out short.
*/
public static @NotNull MonotonicTicker getInstance() {
return instance;
}
Expand Down
4 changes: 4 additions & 0 deletions sentry/src/main/java/io/sentry/time/SystemEpochClock.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public final class SystemEpochClock implements EpochClock {

private static final SystemEpochClock instance = new SystemEpochClock();

/**
* Prefer {@link io.sentry.SentryOptions#getEpochClock()}, which is where a platform would
* substitute its own wall clock, the way Android already substitutes the ticker.
*/
public static @NotNull EpochClock getInstance() {
return instance;
}
Expand Down
Loading