Implementation Plan
Phase 1 Telemetry primitives (rage)
Phase 2 Socket & connection metrics (rage & rage-iodine)
rage-iodine exposes no accept-queue depth. We add them, following the existing pattern (task_inc!/task_dec!/stopping? core fn in fio.c, declaration in fio.h and Ruby wrapper + registration in
iodine_defer.c).
Metric:
Phase 3 OpenTelemetry metrics (opentelemetry-instrumentation-rage)
Phase 4 Grafana dashboard
Phase 5 Context propagation (rage)
Phase 6 Benchmark & docs
Implementation Plan
Phase 1 Telemetry primitives (rage)
Rage::Telemetry.every(ms), wrapsIodine.run_everyhandles boot timing internally (Iodine.running?andon_state(:on_start))Phase 2 Socket & connection metrics (rage & rage-iodine)
rage-iodineexposes no accept-queue depth. We add them, following the existing pattern (task_inc!/task_dec!/stopping?core fn infio.c, declaration infio.hand Ruby wrapper + registration iniodine_defer.c).Metric:
Iodine.socket_backlogin iodine: save the listener's fd whenfio_listenruns, then read the kernel's accept-queue length (handshaked (ESTABLISHED) connections waiting foraccept()) viagetsockopt(TCP_INFO)tcpi_unacked.Rage::Telemetry.socket_backlog, method-based reader exposing the Iodine server accept queue.Phase 3 OpenTelemetry metrics (opentelemetry-instrumentation-rage)
Telemetry.everyGC.statsamplingRage rawkeysPhase 4 Grafana dashboard
Phase 5 Context propagation (rage)
Current.user(and all CurrentAttributes) survive every fiber boundary — enqueue, task execution and Fiber.schedulePhase 6 Benchmark & docs