Live — hosted & self-host

Production broke. Only the logs noticed.

Your app writes down every failure — then buries it under forty thousand lines of routine noise nobody reads at 3 a.m. Pingtower reads the stream for you: repeats collapse into single alerts, your rules decide what matters, and it keeps paging until a human acks.

The fix

One log stream in. A handful of alerts out.

Point anything that can make an HTTP request at Pingtower. It extracts the shape of every message so repeats collapse into one alert with a counter, declarative rules decide what opens an alert, and escalation ladders decide who hears about it — Slack, Telegram, signed webhooks, or push to the native iOS app.

  • One alert per problem, with a running count
  • Escalation ladders that stop only at ack
  • Ack and resolve with a swipe on your phone

Use cases

For everything that fails while nobody's watching

The 3 a.m. crash

A level 500 opens an alert and starts the ladder. If Slack doesn't get acked, your phone rings next — silent switch or not — until someone answers.

The error on a loop

The same stack trace 40,000 times is one alert with a count of 40,000. Your channel gets one message and a running tally, not a flood.

The quiet failure

A threshold like 5 hits in 10 minutes catches the webhook that fails a little more every hour — the slow bleed no single error would justify paging for.

The one affected user

Group alerts by identifier keys like username, and fifty different errors about the same account become one alert telling one story.

The $5 VPS side project

No agent, no SDK. A curl in the error path is enough for the smallest service you run to reach your phone.

The incident your users noticed

Write the post-mortem as a report and share one link — public by UUID, password-protected if you want.

The API

If it can make an HTTP request, it can page you.

One endpoint, one bearer token per source. Send a message, a severity from 100 to 500, and whatever keys and tags your rules should match on. Every language, cron job, and shell script already speaks it.

  • Levels 100–500, debug to critical
  • Structured keys for conditions and grouping
  • Tags and sources for routing rules
  • A full management API behind per-tenant keys — the app is just a client
anywhere you can run curl
curl -s $PINGTOWER_URL/v1/ingest \
  -H "Authorization: Bearer $SOURCE_TOKEN" \
  -d '{
    "message": "payment worker crashed",
    "level":   500,
    "keys":    { "service": "payments", "signal": "SIGSEGV" },
    "tags":    ["prod"]
  }'

Addons

Some failures never reach a log. Probe them from outside.

The addons agent is one Go binary on any box beyond your infrastructure. It runs HTTP, TCP, DNS, certificate-expiry, and ping checks on a schedule and reports every measurement through the same ingest plane your logs use — metrics are just events, and your rules threshold them.

  • Five core checks + four opt-in privileged probes
  • Down at error level — critical if it should page
  • DNS, connect, TLS, and first byte timed apart
  • Signed tarballs, verified before install runs
any box with an outbound socket
$ addons check httpcheck \
    --param url=https://example.com --report
UP in 101ms — sent, template f5b97ca2, alerted

$ addons check tlscert \
    --param address=example.com:443
{ "days_until_expiry": 14, "handshake_ms": 34.7 }

Why Pingtower

From log line to acknowledged alert

All features →

40,000 repeats become one alert

Pingtower strips the variable parts of each message to recover its shape, then hashes it — so the same failure bumps a counter on one alert instead of flooding a channel. Or group by keys like a username, and get one alert per affected account.

Rules you declare, not regex you babysit

Match on level, source, tags, or message shape; add conditions on structured keys; set thresholds like “fire after 5 hits in 10 minutes” or “only when 3 different sources see it.” One engine, no separate monitor concept.

Escalation that doesn't give up

Ladders move an unacked alert up level by level — Slack first, on-call push later — repeating on the schedule you set until someone acks. Acked alerts hold their place; quiet ones auto-resolve.

Delivery you can audit

Every notification is a durable outbox row, delivered at-least-once and logged per integration — a restart never drops a page. Webhooks are HMAC-SHA256 signed, and failing channels surface their errors instead of hiding them.

Paranoid where it counts

Tenant-supplied URLs pass an SSRF guard — no private ranges, no redirects, DNS-rebinding pinned. Delivery secrets are AES-256-GCM encrypted at rest, tokens compare in constant time, and everything lands in an audit log.

A single binary and a SQLite file

One Go binary, zero CGO, stdlib HTTP, pure-Go SQLite in WAL mode. Each tenant is its own database file, so a backup is a file copy. Self-host the daemon with a handful of flags on any box you own — ingest, rules, escalation, and webhook delivery all run there. The iOS app and its push notifications are hosted by us.

Runbooks that run themselves

Attach an HTTP action to a rule and it fires the moment the alert opens or escalates — restart the worker, flush the queue, open a ticket. Credentials are sealed at rest, every run is logged with status and response, and you can test-fire before you trust it.

Your whole team, one tower

Organizations with owner, admin, and member roles; email invites; API keys you can mint and revoke per tenant. Belong to several orgs with one account, switch between them in the app — and every sensitive change lands in the audit log.

On-call

It doesn't page everyone. It pages whoever's on shift.

Build rotations from your project's members: layers take timed shifts, restrictions carve out business hours and nights in your timezone, and a later layer overrides the ones below — nights on top of a daytime base. When an alert fires, the push goes to the phone of whoever is on shift. Everyone else sleeps.

  • Layered rotations — daytime base, night shift on top
  • One-off overrides for swaps and vacations
  • Your phone stays quiet unless you're on call
  • DST-safe shifts in your schedule's own timezone

The app

Your phone is on silent. The pager isn't.

Alerts that matter shouldn't queue behind muted Slack channels and filtered email. Pingtower has its own native iOS app — critical alerts sound through Silent mode and Focus, a permission you grant once, and one swipe in the app acks the alert and stops the escalation ladder. The whole product is in the app: rules, integrations, runbooks, reports, your team.

  • Critical alerts break through Silent and Focus
  • Ack and resolve with a swipe — the ladder stops for everyone
  • Live feed — alerts land in seconds, not on refresh
  • Native SwiftUI on iPhone and iPad — a full console, not a viewer

How it works

Three steps from noise to a page

  1. Send it a log line

    Create a project, add a source, get a token. One POST with a message, level, keys, and tags — from an error hook, a shell script, anywhere.

  2. Rules turn the stream into state

    Each event's shape is matched against your rules. New problem: an alert opens. Repeat: the count bumps. Threshold not met yet: it waits.

  3. It finds a human

    The on-call rotation picks whose phone rings; integrations fan out — Slack, Telegram, signed webhooks, critical push to the iOS app — and runbook actions fire automatically. Unacked alerts climb the ladder.

Changelog

From the blog

All posts →