Pulse is a self-contained service health monitoring daemon written in Go. It performs scheduled HTTP, TCP, and TLS certificate expiration checks against configured targets, persisting results to an embedded SQLite database with automatic rollup aggregation and retention enforcement.
- Multi-Protocol Checking: Native support for HTTP/HTTPS (status codes and latency boundaries), TCP socket connectivity, and TLS certificate expiration auditing.
- Single Statically Compiled Binary: Zero external runtime dependencies; embeds SQLite migrations and static dashboard assets directly inside the binary.
- Automated Rollup Aggregation: A background aggregator summarizes raw checks into hourly and daily rollups, enabling indefinite long-term historical reporting without unbounded disk growth.
- State-Machine Alerting & Flap Protection: Automatically manages target health states (
HEALTHY,ALERTING,FLAPPING,RECOVERED) with configurable failure thresholds and flapping suppression. - Multi-Channel Notifications: Built-in concurrent notification dispatcher supporting structured JSON Webhooks and SMTP email alerts.
- Embedded Dashboard & REST API: Built-in read-only web dashboard and JSON REST API served directly from the daemon on a single port.
- Prometheus Observability: Native
/metricsendpoint exposing rich operational counters, gauges, and latency histograms.
Detailed technical guides and complete references are maintained in the docs/ directory:
| Guide | Audience | Summary |
|---|---|---|
| Architecture Guide | Developers & Contributors | Subsystem design, startup sequence, execution lifecycle, concurrency model, SQLite WAL storage mechanics, alert FSM, and tiered rollup pipeline. |
| Configuration Reference | Operators & SREs | Complete TOML configuration reference, custom duration parsing, static validation engine rules, startup synchronization, and annotated production defaults. |
| REST API Reference | Developers & Integrators | Complete HTTP REST API specification, JSON response schemas, automatic time-based granularity routing, error formats, and cURL examples. |
graph TD
A["config.toml"] -->|Load & Validate| B("Main Daemon")
B -->|Initialize| C[("SQLite Database")]
B -->|Start| D["Scheduler"]
B -->|Start| L["Aggregator"]
D -->|Spawn| E["Service Worker 1"]
D -->|Spawn| F["Service Worker N"]
E -->|Execute Check| G["Checker Registry"]
F -->|Execute Check| G
G -->|Dial / GET| H["Target Services"]
G -->|Write Result| I["resultCh"]
I -->|Drain Loop| J["Alert Evaluator"]
J -->|Persist Result & State| C
J -->|Dispatch Notification| K["Webhook / Email Notifiers"]
L -->|Read raw results / hourly summaries| C
L -->|Write hourly / daily summaries| C
L -->|Prune aged data| C
style J fill:#fff,stroke:#333
style K fill:#fff,stroke:#333
style L fill:#fff,stroke:#333
Pulse decouples scheduling, execution, alerting, and data retention using Go channels and interfaces. Independent worker goroutines execute checks on scheduled intervals, pushing results to a centralized alerting and storage pipeline. A dedicated background aggregator computes time-bucketed rollups and enforces data retention policies without blocking live checks.
Note
For detailed component workflows, concurrency patterns, and state transitions, see docs/architecture.md.
Launch the complete monitoring stack (Pulse, Prometheus, and Grafana):
git clone https://github.com/slash-init/pulse.git
cd pulse
docker compose up -d- Pulse API & Web UI: http://localhost:8080
- Grafana Dashboard: http://localhost:3000 (default credentials:
admin/admin) - Prometheus TSDB: http://localhost:9090
Compile and run the single binary locally:
# Clone repository and build binary
git clone https://github.com/slash-init/pulse.git
cd pulse
make build
# Copy template configuration and launch daemon
cp config.example.toml config.toml
./bin/pulse -config config.tomlPulse uses a single declarative TOML configuration file. Service targets are synchronized to the local database on startup.
[server]
host = "0.0.0.0"
port = 8080
environment = "production"
log_level = "info"
[database]
driver = "sqlite"
dsn = "./pulse.db"
[retention]
raw_days = 7
hourly_days = 90
aggregator_tick_interval = "15m"
[alerting]
enabled = true
failure_threshold = 2
repeat_interval = "4h"
flap_window = 10
[alerting.webhook]
enabled = true
url = "https://hooks.slack.com/services/T00/B00/XXX"
[[services]]
name = "Production API Health"
enabled = true
type = "http"
url = "https://api.example.com/health"
interval = "30s"
timeout = "5s"
[services.alerts]
status_code = 200
max_latency = "1000ms"
[[services]]
name = "TLS Certificate Expiry"
enabled = true
type = "ssl"
url = "https://api.example.com"
interval = "12h"
timeout = "10s"
[services.alerts]
ssl_expiry_days = 14Note
For complete reference on validation constraints, duration syntax, and notification integrations, see docs/configuration.md.
Pulse includes two complementary visualization options out of the box:
- Embedded Web Dashboard: Accessible at
http://localhost:8080/. Served directly from embedded binary assets, it displays live target health, consecutive failures, latency/uptime history, and an incident timeline. - Grafana Integration: A production-ready dashboard is pre-provisioned in
grafana/dashboards/pulse.jsonwhen running via Docker Compose, visualizing Prometheus metrics across all monitored services.
Pulse exposes read-only HTTP REST endpoints for querying target health, historical checks, and alert events:
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/healthz |
Liveness probe verifying database connectivity. |
GET |
/api/services |
Lists all monitored services with current health state and latest check metadata. |
GET |
/api/services/{id} |
Returns details and state for a specific service. |
GET |
/api/services/{id}/history |
Returns historical check results (raw, hour, or day granularity based on time range). |
GET |
/api/services/{id}/events |
Returns chronological alert state transition events. |
Note
For query parameters, automatic granularity routing rules, and JSON response schemas, see docs/api.md.
Pulse exposes operational metrics at GET /metrics for Prometheus scrapers alongside standard runtime statistics:
| Metric Name | Type | Labels | Description |
|---|---|---|---|
pulse_checks_total |
Counter | service, result |
Total health checks executed (result is pass or fail). |
pulse_check_latency_ms |
Gauge | service |
Latency of the latest check execution in milliseconds. |
pulse_last_check_timestamp |
Gauge | service |
Unix timestamp of the latest health check. |
pulse_alert_state |
Gauge | service, state |
Current alert state (one-hot encoded: HEALTHY, FIRING, ALERTING, FLAPPING, RECOVERED). |
pulse_notifications_sent_total |
Counter | service, event_type, channel |
Total alert notifications successfully dispatched. |
pulse_notification_failures_total |
Counter | channel |
Total notification delivery failures. |
pulse_http_requests_total |
Counter | method, path, status |
Total HTTP requests handled by the REST API server. |
pulse_http_request_duration_seconds |
Histogram | method, path |
HTTP request duration in seconds. |
- SQLite Relational Storage vs. Time-Series DB: Storing check history in SQLite eliminates external database dependencies. To avoid unbounded disk growth without a specialized time-series engine, Pulse rolls up raw data into hourly and daily aggregates before pruning raw records.
- Goroutine-per-Service vs. Worker Pool: Spawning an independent goroutine and ticker per target simplifies scheduling and isolation. Memory footprint scales linearly with service count, making it optimal for hundreds to thousands of targets.
- Declarative Configuration Sync: Monitored targets declared in
config.tomlare synchronized to the database on startup. Removing a target from configuration preserves its historical records in SQLite to prevent accidental audit loss. - Daily Rollups Derived from Hourly Summaries: Because raw data retention (
raw_days) is shorter than hourly summary retention (hourly_days), daily rollups are computed from settled hourly rows using a checks-weighted average to maintain mathematical accuracy.
- PostgreSQL Storage Driver: Backend implementation of the
Storeinterface for distributed or high-concurrency deployments. - Observation Coverage Tracking: Explicit tracking of expected-vs-actual check counts in rollups to distinguish target downtime from monitoring daemon gaps.
make fmt # Format codebase
make lint # Run static analysis (golangci-lint)
make test # Run unit tests with Go race detector (-race)
make test/cover # Generate code coverage reportPulse is open-source software licensed under the MIT License.