A simple Prometheus (aggregated) push gateway allowing stateless/serverless workloads, ephemeral and batch jobs to easily expose their metrics. Aggregated metrics are exposed via /metrics
endpoint and optionally pushed to a remote Prometheus instance.
Powered by Cloudflare Workers, Durable Objects, and CRON Triggers.
- Simple PATCH counter - no need for a client libraries for a counter metric, just send
PATCH /metrics/:metricName?label1=value1&label2=value2
to increment its value. - Aggregated metrics - received values are added up to the current (label matching) metrics. All metrics exposed on
GET /metrics
. - Automatic push to a remote prometheus server - metrics are (optionally) pushed to a
remote_write
prometheus endpoint on each CRON Trigger execution. See Grafana Cloud (generous free tier) for a managed Prometheus with Grafana.
Cloudflare Account with Paid Workers is needed.
yarn
yarn deploy
(optional)
add following secrets (either via Cloudflare Dashboard or withnpx wrangler@beta secret put
)SECRET_PROM_ENDPOINT
(e.g.https://prometheus-us-central1.grafana.net/api/prom/push
)SECRET_PROM_USER
(e.g. 23333)SECRET_PROM_TOKEN
(e.g. xxyy)
There are a couple of easy ways to push your metrics, the POST /metrics
endpoint is compatible with any prometheus client library configured to use it as a push gateway.
In case Cloudflare Workers are the only clients, its recommended to deploy this Workers with no routes attached to it and use Service bindings.
POST /metrics
- accepts prometheus text-based format.PATCH /metrics/:metricName?label1=value1&label2=value2
- simplified counter increments that works well with no libraries needed.
curl
- Send curl
curl -x PATCH https://worker.example.com/metrics/metric_name?foo=bar
- Send
POST
request with body in prometheus text-based formatcat <<EOF | curl --data-binary @- https://worker.example.com/metrics # TYPE some_metric counter some_metric{label="val1"} 42 # TYPE another_metric gauge # HELP another_metric Just an example. another_metric 2398.283 EOF
Workers
- A simple
worker_request
counter that will keep track of request countries.export default { async fetch(request, env, ctx) { ctx.waitUntil( fetch(`https://worker.example.com/metrics/worker_request?country=${request.cf.country}&anotherLabel=value`, { method: "PATCH" }) ) return new Response("Hello World!") } }
- promjs (or any other js library)
import prom from 'promjs'; export default { async fetch(request, env, ctx) { const registry = prom() const counter = registry.create('counter', 'my_counter', 'A counter for things') // process tasks, e.g. orders counter.inc({user: "user1", plan: "pro"}) counter.add(3, {user: "user2", plan: "free"}) counter.inc({user: "user3", plan: "pro"}) ctx.waitUntil( fetch(`https://worker.example.com/metrics`, { method: "POST", body: JSON.stringify(registry.metrics()) }) ) } }
DELETE /metrics/__all
to delete all metricsDELETE /metrics/:metricName
to delete a specific metric,DELETE /metrics/:metricName?foo=bar
to delete a metric matching specific labels only (all labels need to match)
- Max ~100rps, as no Durable Objects sharding is in place. (TODO)
counter
andgauge
metric types supported only. (histogram
WIP)- No auth. If a public route needed, Cloudflare Access is highly recommended.
Inspired by Prometheus Push Gateway and Prometheus Aggregation Gateway