You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 864c8cb
Browse filesBrowse the repository at this point in the historyBrowse files
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>
`SystemClock`, or any `SentryDateProvider` implementation (`SentryAutoDateProvider`,
163
+
`SentryNanotimeDateProvider`, `SentryInstantDateProvider`, `SentryAndroidDateProvider`). Those
164
+
remain only because the `SentryDate` protocol types still flow through the event pipeline; they
165
+
are legacy, not a precedent to follow.
166
+
167
+
Pick the abstraction by what the number is *for*, not by what is convenient to call:
168
+
169
+
| You need | Use | Notes |
170
+
|---|---|---|
171
+
| An instant that leaves the process (event, breadcrumb, session) |`EpochClock` → `Timestamp`| Serialize it. Never subtract two of them |
172
+
| How long something took |`Stopwatch`||
173
+
| Whether a window has elapsed (TTL, cache expiry, backoff, timeout) |`Deadline`| Also gives you `remaining(unit)` for scheduling |
174
+
| Several instants that will be compared with each other (spans of a transaction, samples of a chunk) |`AnchoredClock`| One wall-clock read, the rest projected off ticks, so gaps are real elapsed time |
175
+
| A raw monotonic tick, when none of the above fits |`MonotonicTicker`||
176
+
177
+
Two rules on top of that:
178
+
179
+
1.**Get the clock from the options object** — `options.getEpochClock()` and
180
+
`options.getMonotonicTicker()` — not from `SystemEpochClock.getInstance()`,
181
+
`JavaMonotonicTicker.getInstance()`, or `AndroidMonotonicTicker.getInstance()`. The accessor is
182
+
what resolves to the correct per-platform implementation: on Android the ticker is
183
+
`CLOCK_BOOTTIME`, which keeps counting through a device suspend, while `System.nanoTime()` does
184
+
not. Take the clock as a constructor parameter and keep it in a field; `sentry-test-support`
185
+
provides `TestMonotonicTicker` so tests advance time instead of sleeping.
186
+
2.**If no abstraction fits, stop and think hard before adding one.** Adding a type here is a
187
+
deliberate act, not a shortcut around an awkward call site. First re-read the existing types —
188
+
most "missing" cases turn out to be a `Deadline` or a `Stopwatch` described in different words.
189
+
If one is genuinely missing, work out what invariant it exists to enforce (each of these types
190
+
exists to make one class of clock bug unrepresentable — negative durations, unit mix-ups,
191
+
wrap-unsafe comparisons, a tick escaping into serialized output), name that invariant in its
192
+
Javadoc, and propose it before writing call sites against it. Do not inline raw tick arithmetic
193
+
at a call site as a stopgap.
194
+
158
195
### Testing Requirements
159
196
- Write comprehensive unit tests for new features
160
197
- Android modules require both unit tests and instrumented tests where applicable
0 commit comments