Prometheus exporter
The Prometheus exporter turns the in-process metrics registry
into the Prometheus text format that Prometheus / Grafana /
Thanos scrape from /metrics.
import { ActorSystem, MetricsExtensionId, exportPrometheus } from 'actor-ts';
const system = ActorSystem.create('my-app');const metrics = system.extension(MetricsExtensionId);
// Inside an HTTP handler:get(async () => { const text = exportPrometheus(metrics.registry); return { status: 200, body: text, contentType: 'text/plain; version=0.0.4' };});Returns a single string in Prometheus 0.0.4 exposition format:
# HELP http_requests_total Total HTTP requests# TYPE http_requests_total counterhttp_requests_total{route="/orders"} 1234http_requests_total{route="/users"} 567
# HELP sessions_active Currently active sessions# TYPE sessions_active gaugesessions_active 123
# HELP http_request_duration_ms HTTP request latency# TYPE http_request_duration_ms histogramhttp_request_duration_ms_bucket{route="/orders",le="10"} 100http_request_duration_ms_bucket{route="/orders",le="50"} 250http_request_duration_ms_bucket{route="/orders",le="+Inf"} 300http_request_duration_ms_count{route="/orders"} 300http_request_duration_ms_sum{route="/orders"} 12450Via the management endpoint
Section titled “Via the management endpoint”The easiest path is via the HttpManagement helper:
import { HttpManagement } from 'actor-ts';
await HttpManagement.start(system, { port: 8558, enableMetricsEndpoint: true, // ← exposes GET /metrics});Prometheus scrape config:
scrape_configs: - job_name: 'actor-ts' static_configs: - targets: ['my-app:8558']The management server runs on a separate port from your app’s main HTTP server. Typical pattern: app on 8080 (public), management on 8558 (internal-only).
Manual wiring
Section titled “Manual wiring”If you’re not using HttpManagement, route a GET /metrics
yourself:
import { path, get } from 'actor-ts/http';import { exportPrometheus } from 'actor-ts';
const routes = path('metrics', get(async () => ({ status: 200, body: exportPrometheus(metrics.registry), contentType: 'text/plain; version=0.0.4', headers: {}, })),);Bind on a dedicated port if you can — Prometheus’s scrapes are periodic and shouldn’t share the app port.
Naming conventions
Section titled “Naming conventions”http_requests_total # counter — `_total` suffixsessions_active # gauge — no suffixhttp_request_duration_seconds # histogram — _bucket / _count / _sumprocess_cpu_seconds_total # counter again — Prometheus namingPrometheus has conventions (naming guide):
- Counters end in
_total(or describe what’s counted). - Histograms / timers include the unit in the name
(
_seconds,_ms,_bytes). _count/_sumare framework-appended suffixes for histograms.- Labels are snake_case strings.
The framework doesn’t enforce these — but Prometheus tooling expects them.
Scrape cadence vs gauge update rate
Section titled “Scrape cadence vs gauge update rate”- Scrape every 15-30 seconds — Prometheus default.
- Update gauges at any cadence — Prometheus only sees the value at scrape time.
- Counters can be incremented at any rate; Prometheus computes the rate from successive scrapes.
For very-fast-changing values (memory usage, mailbox depth), the gauge may be stale by the time it’s scraped. That’s fine — Prometheus is eventually consistent with its samples.
Exposition format details
Section titled “Exposition format details”| Series | Format |
|---|---|
| Counter | One line per series. metric_name{labels} value |
| Gauge | Same as counter. |
| Histogram | One _bucket{le=N} line per bucket + _count + _sum. |
The exporter handles the formatting; you don’t construct it manually.
Where to next
Section titled “Where to next”- Observability overview — the bigger picture.
- Core metrics — the four primitives.
- Management overview —
the easy way to expose
/metrics. - Stock metrics — the framework’s auto-recorded metrics that appear here.
The exportPrometheus
function reference covers the full API.