DING

Don't store it. Stream it. DING it.

$ brew install zuchka/tap/ding
$ curl -sf https://start.ding.ing | sh

or Docker, binary

What

DING is a stream-based alerting daemon. Pipe metrics into it. It evaluates rules. It fires alerts. That's it.

Single binary. No database. No agents. No cloud account. Works anywhere.

Quickstart

  1. Copy the example config and validate it

    cp ding.yaml.example ding.yaml
    ding validate        # exits 0 if valid, 1 with a clear error if not
  2. Start DING

    ding serve
    
    # point at a specific config
    ding serve --config /etc/myapp/alerts.yaml
    
    # download and start in one shot
    curl -sf https://start.ding.ing | sh && ding serve --config ./ding.yaml
  3. Send an event

    curl -X POST http://localhost:8080/ingest \
      -H "Content-Type: application/json" \
      -d '{"metric":"cpu_usage","value":97,"host":"web-01"}'
  4. Or just pipe

    your-app | ding serve

Rules

One YAML file. Lives in your repo. Ships with your code.

rules:
  # fires on a single bad reading
  - name: cpu_spike
    match:
      metric: cpu_usage
    condition: value > 95
    cooldown: 1m
    message: "CPU spike on {{ .host }}: {{ .value }}%"
    alert:
      - notifier: stdout

  # fires on sustained high CPU (windowed)
  - name: cpu_sustained
    match:
      metric: cpu_usage
    condition: avg(value) over 5m > 80
    cooldown: 10m
    message: "Sustained high CPU: {{ .avg }}% avg on {{ .host }}"
    alert:
      - notifier: stdout

All condition forms:

value > 95                       # single event
avg(value) over 5m > 80         # average over window
max(value) over 1m >= 100
min(value) over 10s < 10
sum(value) over 30s > 0
count(value) over 2m > 50       # number of events, not sum of values

Template variables in message::

VariableWhenDescription
.metricalwaysmetric name
.valuealwaysraw event value
.rulealwaysrule name
.fired_atalwaysRFC3339 timestamp
.host, .region, …alwaysany label from the event
.avg .max .min .sum .countwindowed onlyaggregate result

Notifiers

stdout is built-in. For webhooks, define them once and reference by name.

notifiers:
  alert-slack:
    type: webhook
    url: https://hooks.slack.com/services/T.../B.../...
    max_attempts: 3       # retries on 5xx (default: 3)
    initial_backoff: 1s   # doubles each attempt (default: 1s)

rules:
  - name: cpu_spike
    condition: value > 95
    cooldown: 1m
    alert:
      - notifier: stdout        # always available, no declaration needed
      - notifier: alert-slack   # send to both simultaneously

The webhook receives a JSON POST:

{"rule":"cpu_spike","message":"CPU spike on web-01: 97%",
 "metric":"cpu_usage","value":97.0,"fired_at":"...","host":"web-01"}

4xx responses are dropped. 5xx responses are retried with exponential backoff.

Why

Fires alerts in 4ms. Prometheus default scrape + eval + Alertmanager dispatch: ~62 seconds minimum. That's not a knock on Prometheus — it's a pull-based system built for persistence and fleet-wide aggregation. DING is push-based and stateless. The architecture is the difference.

Performance

4ms
Alert latency p50
p99: 16ms — Prometheus default: ~62s
116k
Requests / second
50 concurrent workers, 30s window
9ms
Cold start p50
fork → first /health — Prometheus: 185ms
106ns
Per rule evaluation
simple threshold — windowed: 157ns

Benchmarked 2026-03-23 on Apple M3. Full methodology and raw results →

Input

JSON lines:

{"metric": "cpu_usage", "value": 92.5, "host": "web-01"}

Prometheus text:

cpu_usage{host="web-01"} 92.5

HTTP API

Method Path Description
POST/ingestSend events
GET/healthHealth check
GET/rulesList rules + cooldown state
POST/reloadHot-reload config

Operations

Reload config without restarting:

kill -HUP <pid>
# or
curl -X POST http://localhost:8080/reload

Survive restarts — persist cooldown state and windowed buffers to disk:

persistence:
  state_file: /var/lib/ding/state.json
  flush_interval: 30s

SIGTERM / SIGINT — drains in-flight requests, flushes state, exits 0.

Install

Homebrew:

brew install zuchka/tap/ding

Binary:

curl -sf https://start.ding.ing | sh

Docker:

docker run -v ./ding.yaml:/etc/ding/ding.yaml \
  ghcr.io/zuchka/ding