HeronGo to dashboard →

Getting started

Know when your business silently breaks

Standard monitoring tells you when your server crashes. Heron tells you when your business flow quietly fails — when payment webhooks stop firing, email jobs silently stall, or background workers die without throwing an error.

Your system looks healthy. But revenue is stopped. Heron catches that.

Early access: Heron is in active development. Core monitoring, incident tracking, Slack alerts, and multi-project support are all working. A hosted SaaS version is on the roadmap.

Common events people monitor with Heron:

  • payment.completeddetect payment pipeline failures
  • user.signupdetect broken signup webhooks
  • email.sentdetect stalled email queues
  • job.processeddetect silent worker failures

How it works

Heron works in three phases: ingest, learn, and detect.

Your app
Heron SDK
Heron server
Pattern learning
Silence detection
Slack alert

When you call heron.track("payment.completed"), Heron records that event with a timestamp. Over time, it computes the average interval between occurrences — for example, payment.completed fires every ~3 minutes.

The background monitor checks each event's last-seen timestamp against its learned interval. If the silence exceeds the expected interval by a meaningful margin, Heron opens an incident and fires a Slack alert. When the event resumes, it automatically closes the incident and reports the total downtime.

Pattern learning: Heron needs at least a few data points before it can reliably detect silence. Events that fire infrequently will have wider tolerance windows. See for details.

Quick start

Get Heron running locally in about 10 minutes.

1

Clone the repository

git clone https://github.com/pranavkp71/Heron.git
cd heron/heron-server
2

Install dependencies

pip install -r requirements.txt
3

Set up PostgreSQL

Create a database, then run the schema. See for the full SQL.

4

Start the server

python run.py

Server runs at https://heron-production.up.railway.app.

5

Create a project and get your API key

curl -X POST "https://heron-production.up.railway.app/v1/projects?name=MyApp"
# Response
{
  "project_id": 1,
  "api_key": "heron_xxxxx"
}
6

Track your first event

# In your application code
import sys
sys.path.append("/path/to/heron-sdk")

import heron

heron.init(api_key="heron_xxxxx")
heron.track("payment.completed")

Heron will now track this event, learn its frequency, and alert you if it stops.


Database setup

Heron requires a PostgreSQL database with four tables. Run the following SQL after creating your database:

-- Stores your projects and their Slack webhook URLs
CREATE TABLE projects (
    id              SERIAL PRIMARY KEY,
    name            TEXT NOT NULL,
    api_key         TEXT UNIQUE NOT NULL,
    slack_webhook_url TEXT,
    created_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Raw event log — every heron.track() call lands here
CREATE TABLE events (
    id          SERIAL PRIMARY KEY,
    api_key     TEXT,
    event_name  TEXT,
    service     TEXT,
    environment TEXT,
    metadata    JSONB,
    timestamp   BIGINT
);

-- Per-event statistics updated on each track() call
CREATE TABLE event_stats (
    api_key         TEXT,
    event_name      TEXT,
    service         TEXT,
    environment     TEXT,
    last_seen       BIGINT,
    avg_interval    FLOAT,
    event_count     INTEGER,
    incident_active BOOLEAN DEFAULT FALSE
);

-- One row per incident, open or resolved
CREATE TABLE incidents (
    id          SERIAL PRIMARY KEY,
    api_key     TEXT,
    event_name  TEXT,
    service     TEXT,
    environment TEXT,
    started_at  TIMESTAMP,
    resolved_at TIMESTAMP,
    duration    INTEGER
);

Running the server

Start the Heron server from the heron-server directory:

python run.py

The server starts at https://heron-production.up.railway.app. It runs a background monitor that periodically checks for silent events and opens or resolves incidents.

Note: You must configure your database connection before starting the server. Check your .env or config file for the database URL setting.

Creating a project

Each project gets its own API key. Use separate projects to isolate different apps or environments.

curl -X POST "https://heron-production.up.railway.app/v1/projects?name=MyApp"
{
  "project_id": 1,
  "api_key": "heron_xxxxx"
}

Store the api_key securely — it authenticates all SDK calls and API requests for this project.


Slack alerts

Heron sends incident alerts and recovery notifications to a Slack channel via an incoming webhook.

1

Create a Slack incoming webhook

Go to your Slack workspace → Apps → search for Incoming Webhooks → Add to a channel. Copy the webhook URL.

2

Add the webhook to your project

curl -X PATCH "https://heron-production.up.railway.app/v1/projects/1/slack" \
  -H "Content-Type: application/json" \
  -d '{"slack_webhook_url": "https://hooks.slack.com/..."}'

Once set, Heron will automatically post alerts when incidents open or resolve.


SDK installation

The Heron SDK is not yet published on PyPI. Install it by pointing Python to the local SDK directory:

import sys
sys.path.append("/path/to/heron-sdk")  # absolute path to the cloned repo's SDK folder

import heron
PyPI coming soon: Once published, installation will simplify to pip install heron-sdk. Follow progress on X (@pranavk_p).

SDK reference

heron.init()

Call once at application startup to configure the SDK.

heron.init(
    api_key="heron_xxxxx",      # required
    service="payments-service",  # optional — tag events by service
    environment="production"     # optional — "production", "staging", etc.
)
ParameterTypeRequiredDescription
api_keystringrequiredYour project API key from the create project step.
servicestringoptionalTag events with a service name. Useful for multi-service projects.
environmentstringoptionalTag events with an environment. Incidents are scoped per environment.

heron.track()

Call this wherever a business event occurs. Each call records an event occurrence and updates the pattern data.

heron.track(
    event_name="payment.completed",  # required
    metadata={                          # optional
        "amount": 49.99,
        "currency": "USD",
        "user_id": "usr_123"
    }
)
ParameterTypeRequiredDescription
event_namestringrequiredDot-separated event identifier. Use consistent naming — Heron tracks each unique name separately.
metadatadictoptionalArbitrary key-value data stored with the event. Useful for debugging incidents. Stored as JSONB.
SDK failure behavior: If the Heron server is unreachable, the SDK will fail silently by default — your application code will not be interrupted. This is intentional. Monitoring should never break production.

API reference

All endpoints require your project's api_key as a query parameter.

GET/v1/incidents

Returns all incidents (open and resolved) for your project.

curl "https://heron-production.up.railway.app/v1/incidents?api_key=heron_xxxxx"
[
  {
    "id": 1,
    "event_name": "payment.completed",
    "service": "payments-service",
    "environment": "production",
    "started_at": "2024-11-01T14:22:00Z",
    "resolved_at": "2024-11-01T14:40:00Z",
    "duration": 1080
  }
]
GET/v1/incidents/active

Returns only currently open incidents. Useful for status dashboards or health checks.

curl "https://heron-production.up.railway.app/v1/incidents/active?api_key=heron_xxxxx"
[
  {
    "id": 3,
    "event_name": "email.sent",
    "service": "notifications",
    "started_at": "2024-11-01T15:10:00Z",
    "resolved_at": null,
    "duration": null
  }
]

Alert format

Heron sends two types of Slack messages: incident alerts when an event stops, and recovery alerts when it resumes.

Incident alert

🚨 Heron alert
Eventpayment.completed
Last seen18 minutes ago
Expected interval~3 minutes
Servicepayments-service
Environmentproduction

Recovery alert

✅ Heron recovery
Eventpayment.completed
Downtime18 minutes
Servicepayments-service
Environmentproduction

Pattern learning

Heron does not require you to manually configure thresholds. Instead, it learns the natural cadence of each event from observed data.

On every heron.track() call, Heron computes a rolling average of the interval between consecutive events. This becomes the expected interval for that event. The silence detector runs periodically and compares the current gap (time since last_seen) against the expected interval.

SituationBehavior
Event is new (< 3 occurrences)Heron collects data but won't alert yet — not enough history to establish a reliable pattern.
Event fires very infrequentlyAlerts will fire with a wider tolerance. A once-per-day job won't alert after 5 minutes of silence.
Event frequency changesThe rolling average adjusts over time. A sudden permanent change in frequency will stabilize after a few occurrences.
Alert fires too aggressivelyThis may mean your event has high variance (e.g., batch jobs that run irregularly). More sophisticated threshold tuning is on the roadmap.

Troubleshooting

My event is being tracked but I'm not getting alerts

Heron requires a minimum number of data points before it can establish a reliable pattern. Make sure the event has fired at least 3–5 times. Also confirm your Slack webhook URL is correctly set on your project.

I'm getting false positive alerts

This usually means the event fires at irregular intervals (e.g., user-driven events with low volume, or batch jobs that run at unpredictable times). Heron's pattern learning will stabilize over time as more data is collected.

The SDK is not connecting to the server

Check that your Heron server is running at https://heron-production.up.railway.app and that there are no firewall rules blocking the connection. The SDK fails silently by design — check your server logs to confirm events are being received.

Database connection errors on startup

Make sure your PostgreSQL instance is running and the connection string in your config file is correct. Also confirm all four tables exist by running the setup SQL from the section.

Events show the wrong service or environment

The service and environment values are set globally in heron.init(). If you need different values per event, re-call heron.init() before the relevant heron.track() calls, or open a GitHub issue — per-event overrides may be added.