otel P4: render-fold → SVG waterfall

otel/waterfall-rects folds a trace's spans into rect geometry (x by start
offset, width by duration, y by depth via parent-link ancestor count);
otel/waterfall folds those into an inline <svg> (one <rect>+<text> per span).
Renders to real SVG markup via the html tag registry.
This commit is contained in:
2026-07-01 14:55:13 +00:00
parent 06294e964c
commit 5f06b5e8e0
2 changed files with 127 additions and 0 deletions

View File

@@ -126,6 +126,45 @@
(host-ot-test "make-app traces the health request" (not (= host-ot-hs nil)) true)
(host-ot-test "make-app health status 200" (get (get host-ot-hs :attrs) :http.status) 200)
;; ── P4: render-fold → SVG waterfall ────────────────────────────────
;; A trace (tree of spans) folds into an <svg>: one <rect> per span, x by start
;; offset, width by duration, y by depth. Build a root with nested children.
(otel/reset!)
(otel/with-span "root" {}
(fn ()
(begin
(otel/with-span "a" {} (fn () nil))
(otel/with-span "b" {} (fn () (otel/with-span "b1" {} (fn () nil))))
nil)))
(define host-ot-tid (get (first (otel/recent)) :trace))
(define host-ot-rects (otel/waterfall-rects host-ot-tid))
(define host-ot-rect-named
(fn (nm) (first (filter (fn (r) (= (get r :name) nm)) host-ot-rects))))
(host-ot-test "one rect per span" (len host-ot-rects) 4)
(host-ot-test "root depth 0" (get (host-ot-rect-named "root") :depth) 0)
(host-ot-test "child a depth 1" (get (host-ot-rect-named "a") :depth) 1)
(host-ot-test "grandchild b1 depth 2" (get (host-ot-rect-named "b1") :depth) 2)
(host-ot-test "nested span y greater than root y"
(> (get (host-ot-rect-named "a") :y) (get (host-ot-rect-named "root") :y)) true)
(host-ot-test "deeper nesting greater y"
(> (get (host-ot-rect-named "b1") :y) (get (host-ot-rect-named "b") :y)) true)
(host-ot-test "root x is the left pad (starts at trace t0)"
(get (host-ot-rect-named "root") :x) 4)
(host-ot-test "all widths positive"
(every? (fn (r) (> (get r :w) 0)) host-ot-rects) true)
;; the SVG itself: an svg head with one rect + one label per span
(define host-ot-svg (otel/waterfall host-ot-tid))
(host-ot-test "waterfall head is svg" (str (first host-ot-svg)) "svg")
(host-ot-test "svg has one rect per span" (otel/-tree-count host-ot-svg "rect") 4)
(host-ot-test "svg has one label per span" (otel/-tree-count host-ot-svg "text") 4)
;; unknown trace → empty waterfall, still a valid svg
(host-ot-test "unknown trace has no rects" (len (otel/waterfall-rects "no-such-trace")) 0)
(host-ot-test "unknown trace still yields an svg"
(str (first (otel/waterfall "no-such-trace"))) "svg")
(define
host-ot-tests-run!
(fn