otel P2: now-ns wraps host clock-milliseconds as epoch nanoseconds

Clamp against a high-water mark so the clock never steps backwards; span
durations stay non-negative. Real ns-scale timestamps replace the P1
placeholder counter.
This commit is contained in:
2026-07-01 14:24:54 +00:00
parent c8cc4a70dc
commit 51d4224a55
2 changed files with 28 additions and 6 deletions

View File

@@ -9,8 +9,7 @@
;; ── monotonic id + clock ─────────────────────────────────────────────
;; A simple process-monotonic counter gives collision-free ids without needing a
;; random source (Math.random/Date.now aren't available on this host). now-ns is a
;; placeholder tick here (monotonic non-decreasing); P2 wraps the real host clock.
;; random source (Math.random/Date.now aren't available on this host).
(define otel/-id-counter 0)
(define otel/-next-id
(fn (prefix)
@@ -20,12 +19,19 @@
(define otel/gen-trace-id (fn () (otel/-next-id "trace-")))
(define otel/gen-span-id (fn () (otel/-next-id "span-")))
(define otel/-clock 0)
;; now-ns — real epoch time in NANOSECONDS (the unit OTLP wants for
;; start/endTimeUnixNano). The OCaml host exposes `clock-milliseconds`
;; (Unix.gettimeofday, epoch ms); we scale by 1e6. Wall clocks can step
;; backwards (NTP), so we clamp against a high-water mark: now-ns never
;; decreases, keeping span durations non-negative even across a clock step.
(define otel/-last-ns 0)
(define otel/now-ns
(fn ()
(begin
(set! otel/-clock (+ otel/-clock 1))
otel/-clock)))
(let ((raw (* (clock-milliseconds) 1000000)))
(let ((t (if (> raw otel/-last-ns) raw otel/-last-ns)))
(begin
(set! otel/-last-ns t)
t)))))
;; ── the dynamic parent stack ─────────────────────────────────────────
;; head = the innermost (current) span context {:span id :trace id}. Pushing on