OpenTelemetry Metrics Export
Observable-pattern OTel
Meterexporters that snapshot internal state and expose it as gauges/counters for Prometheus/OTLP scraping.
Status: ๐ง Partial ยท Visibility: Public ยท Level: ๐ต Core ยท Category: Observability
๐ฏ What it solves
Operators want Typhon's internal numbers โ page cache utilization, WAL ring fill, per-archetype entity counts,
transient memory pressure โ in the dashboards and scrapers they already run (Prometheus, Grafana, SigNoz,
dotnet-counters). Hand-instrumenting every internal counter as an OTel instrument, and keeping that
instrumentation in sync as resources and archetypes come and go, is repetitive work every host application would
otherwise duplicate. Typhon exposes two purpose-built Meters instead, each translating a different slice of
engine state into standard System.Diagnostics.Metrics instruments.
โ๏ธ How it works (in brief)
Both exporters use the same observable pattern: rather than pushing measurements on every state change, they
register CreateObservableGauge/CreateObservableCounter callbacks that are only invoked when an OTel listener
(a MeterListener, a Prometheus scrape, an OTLP export tick) actually asks for a value. The Resource Graph bridge
reads a periodically-refreshed ResourceSnapshot cache; the ECS exporter reads live engine fields directly (no
cache, no extra counters) since those reads are already cheap. Either way, an idle process with no collector
attached pays nothing beyond โ for the Resource Graph bridge โ the background snapshot timer.
Sub-features
| Sub-feature | Exports | Use it when... |
|---|---|---|
| Resource Graph Metrics Bridge | Memory/Capacity/DiskIO/Throughput/Duration for every IResourceGraph node |
Wiring Prometheus/OTLP/Grafana dashboards for engine-wide resource pressure (page cache, WAL ring, transaction pool, ...) |
| ECS Metrics Exporter | Per-archetype entity/EntityMap gauges, per-component transient memory gauges | Watching archetype growth, EntityMap hashing health, or Transient-mode component memory in a dashboard |
โ ๏ธ Guarantees & limits
- Zero overhead when nothing is listening: observable callbacks only run on a scrape/collection pass, never on a timer of their own.
- The two exporters are independent โ different
Meternames (Typhon.ResourcesvsTyphon.ECS), different registration paths, no shared state. You can wire up either, both, or neither. - Partial coverage โ only resource-graph nodes and ECS archetype/transient state are exported this way today.
The broader metrics catalog in the per-domain named-metrics catalog
(transaction counts, lock contention, B+Tree mutations, WAL/checkpoint counters) is captured by the
Typed-Event Profiler and
TickTelemetryRing, not yet bridged into OTel instruments. EcsMetricsExporterhas no DI registration extension yet (unlike the Resource Graph bridge'sAddTyphonObservabilityBridge) โ construct it directly against aDatabaseEngineand register itsMeterwith yourMeterProvider.- Cardinality is bounded by resource-node count / archetype count / component-type count, not by entity count or operation volume โ these are gauges over current state, not per-event counters.
๐งช Tests
- ObservabilityBridgeTests โ exercises the shared observable-callback pattern (snapshot-backed gauges, per-kind opt-out,
MeterListenerinstrument registration) via the Resource Graph bridge; the ECS exporter sub-feature has no dedicated coverage yet
๐ Related
- Sub-features: Resource Graph Metrics Bridge, ECS Metrics Exporter
- Related features: Resource-Aware Health Checks, Threshold-Based Resource Alerting โ read the same
ResourceMetricsExportersnapshot as this bridge