Last9 is built for high-cardinality observability — it handles the label explosion that breaks Prometheus at scale, giving your team reliable metrics on millions of unique time series. But high-cardinality metrics and SLO tracking are internal signals. They tell you what's happening inside your infrastructure. They don't tell you whether a customer hitting your API from the outside can actually reach it. Vigilmon provides that external vantage point: an independent probe that checks reachability and response quality from outside your network, and alerts you instantly when something breaks.
This tutorial covers wiring Vigilmon's external uptime monitoring into applications already instrumented with Last9.
What You'll Build
- A
/healthendpoint exposing dependency status for external probing - A Vigilmon HTTP monitor with JSON assertion on the health response
- A heartbeat monitor for scheduled jobs and SLO-critical batch processes
- A complementary alert strategy that keeps Last9 SLO alerts and Vigilmon uptime alerts distinct
Prerequisites
- A Last9 account with at least one application sending metrics or traces
- A deployed application reachable via a public HTTPS URL
- A free account at vigilmon.online
Step 1: Build a Dependency-Aware Health Endpoint
Last9 collects metrics from exporters and SDKs inside your system. Vigilmon needs an HTTP endpoint it can probe from outside. Make that endpoint meaningful — check your real dependencies rather than returning a static 200.
Go
// internal/health/handler.go
package health
import (
"context"
"database/sql"
"encoding/json"
"net/http"
"time"
)
type response struct {
Status string `json:"status"`
Checks map[string]string `json:"checks"`
}
func Handler(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
checks := make(map[string]string)
ok := true
// Database probe with tight deadline
ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
checks["database"] = "error: " + err.Error()
ok = false
} else {
checks["database"] = "ok"
}
// Downstream service probe
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "http://upstream-svc/ping", nil)
resp, err := http.DefaultClient.Do(req)
if err != nil || resp.StatusCode >= 400 {
msg := "error: unreachable"
if err == nil {
msg = fmt.Sprintf("http_%d", resp.StatusCode)
}
checks["upstream"] = msg
ok = false
} else {
checks["upstream"] = "ok"
}
status := "ok"
code := http.StatusOK
if !ok {
status = "degraded"
code = http.StatusServiceUnavailable
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
json.NewEncoder(w).Encode(response{Status: status, Checks: checks})
}
}
// main.go
mux.HandleFunc("/health", health.Handler(db))
Node.js
// health.js
const axios = require("axios");
const { Pool } = require("pg");
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
module.exports = async function healthHandler(req, res) {
const checks = {};
let ok = true;
try {
await pool.query("SELECT 1");
checks.database = "ok";
} catch (err) {
checks.database = `error: ${err.message}`;
ok = false;
}
try {
const resp = await axios.get(process.env.UPSTREAM_URL + "/ping", { timeout: 3000 });
checks.upstream = resp.status < 400 ? "ok" : `http_${resp.status}`;
if (resp.status >= 400) ok = false;
} catch (err) {
checks.upstream = `error: ${err.message}`;
ok = false;
}
res.status(ok ? 200 : 503).json({ status: ok ? "ok" : "degraded", checks });
};
Verify the endpoint before proceeding:
curl -s https://your-api.example.com/health | jq .
# {"status":"ok","checks":{"database":"ok","upstream":"ok"}}
Step 2: Configure Vigilmon HTTP Monitor
- Log in to Vigilmon → Add Monitor → HTTP.
- URL:
https://your-api.example.com/health - Check interval: 60 seconds.
- Response timeout: 10 seconds.
- Expected status code:
200. - JSON body assertion:
- Path:
status - Expected value:
ok
- Path:
- Save.
From this point on, Vigilmon probes your endpoint every minute from multiple external locations. A non-200 response or a status value other than "ok" triggers an immediate alert.
Multiple environments
Last9 typically collects metrics across staging and production. Mirror that in Vigilmon by creating one monitor per environment:
| Environment | URL | Check interval |
|---|---|---|
| Production | https://api.example.com/health | 60 s |
| Staging | https://api-staging.example.com/health | 120 s |
Group them under separate Monitor groups to keep your dashboard readable.
Step 3: Complementary Alert Routing
Last9 fires SLO burn-rate alerts when your error rate or latency exceeds budget thresholds. Vigilmon fires when the service is unreachable or returns a bad status. They represent different failure modes — route them differently.
| Failure mode | Source | Route to |
|---|---|---|
| SLO burn rate exceeding budget | Last9 | Slack #slo-alerts + PagerDuty L2 |
| External uptime failure | Vigilmon | PagerDuty L1 (immediate page) |
| Scheduled job missed heartbeat | Vigilmon | Slack #ops-critical |
Configure Vigilmon alert channels under Alerts → Add channel. Use separate webhooks for Slack and PagerDuty so the two alert sources stay in different threads.
Why separate lanes? An SLO burn-rate alert fires while the service is still partially up. A Vigilmon uptime alert fires when it's completely down. These require different incident responses — don't mix them.
Step 4: Heartbeat Monitoring for Batch Jobs
Last9 is strong at tracking metrics from long-running services. Batch jobs are harder — if the job stops running, the metrics just disappear. Vigilmon's heartbeat monitor treats silence as a failure.
# jobs/nightly_rollup.py
import os
import requests
def run():
try:
process_daily_aggregates()
# Signal success to Vigilmon
requests.post(os.environ["VIGILMON_HEARTBEAT_URL"], timeout=5)
print("Rollup complete — heartbeat sent")
except Exception as exc:
# Deliberate silence — Vigilmon will alert when heartbeat is missed
print(f"Rollup failed: {exc}")
raise
if __name__ == "__main__":
run()
In Vigilmon, create a Heartbeat monitor and set the grace period to 25 hours for a nightly job (24-hour schedule + 1-hour buffer). Store the URL in your secrets manager and inject it as VIGILMON_HEARTBEAT_URL.
Step 5: Correlating Last9 Metrics with Vigilmon Downtime Events
When Vigilmon fires a downtime alert, you'll want to jump straight to the relevant Last9 dashboard. Add the Vigilmon alert webhook payload to your runbook so on-call engineers know the correlation path:
- Vigilmon alert fires → check alert body for affected URL and start time.
- Open Last9 → filter to the same time window and service name.
- Check error rate and latency histograms → identify whether it's a dependency failure or application error.
- Check Vigilmon check log → confirm which probe regions saw the failure (global vs. regional).
Bookmark the Last9 service dashboard URL in your Vigilmon monitor's Notes field — it appears alongside every alert so the on-call engineer doesn't have to search.
Step 6: Public Status Page
Last9 dashboards are internal. When customers ask "is your API down?", give them a public answer.
- In Vigilmon, go to Status Pages → Create.
- Add your production HTTP monitor and any heartbeat monitors.
- Set a custom subdomain or use the default Vigilmon URL.
- Embed the uptime badge in your documentation:
[](https://status.example.com)
What Vigilmon Adds to a Last9 Stack
| Capability | Last9 | Vigilmon | |---|---|---| | High-cardinality metrics | Yes | No | | SLO burn-rate alerting | Yes | No | | External reachability check | No | Yes | | DNS / CDN failure detection | No | Yes | | Scheduled job heartbeat | No | Yes | | Public status page | No | Yes | | Independent of your cloud provider | No | Yes |
Last9 gives your team precise, high-cardinality visibility into what's happening inside your services. Vigilmon tells you whether those services are reachable from the outside world. Neither replaces the other — together they close every gap in your reliability stack.
Add external uptime monitoring to your Last9 setup today — register free at vigilmon.online.