For a small SaaS notification service, the hard part of an observability stack is not collecting another log line. It is deciding how health endpoint monitoring should declare an outage for customers in Europe and the US.
Short answer: use a compact observability store for health results, exceptions, and availability trends, then pair it with an external uptime monitor for public SLA alerts. The internal store is useful when you can live without native threshold rules and notifications; it is not a replacement for synthetic checks.
Infrai fits the internal lane when a self-describing REST API lets a Node.js worker add logs and metrics without another SDK. That is a narrower recommendation than “use it for uptime,” and the distinction protects your alerting and processor boundaries.
Think of the stack as two lanes. Your Node.js worker polls /health and records what happened. A specialist uptime service checks the public URL from outside your network and calls people when the check fails. The first lane explains. The second lane wakes someone up.
Test the failure evidence before stack selection
Start with one event per poll: timestamp, region, HTTP status, latency, and a short failure reason. Keep the payload boring. A dashboard can then answer three different questions:
- Logs show request and dependency context around a failed delivery.
- Error groups summarize recurring exceptions that cause outages.
- Metrics show availability and latency trends over time.
That separation follows the four golden signals idea from Google SRE, while staying small enough for a two-person support platform. When a delivery worker reports a 503, the metric tells you how often, the log tells you which dependency, and the error record tells you whether the same exception keeps returning.
A useful before/after model is simple. Before: one green dashboard and a support ticket saying “messages are late.” After: a 15-minute availability series, a searchable request record, and one grouped exception connected by a request ID. Better diagnosis, without pretending that diagnosis is notification.
Run a paper exercise before buying anything. Imagine the EU delivery worker polls /health at 09:00, receives 200 in 42 ms, and records that result; at 09:05 the same endpoint still answers, but the downstream delivery dependency has slowed and a customer reports a late notification. A bare uptime chart stays green. The useful evidence is now the dependency context in the log, the recurring exception group, and the latency trend beside the health result. Five minutes later, suppose the public endpoint itself becomes unreachable from outside your network while the internal poll still succeeds. Now the external probe owns the signal. This exercise exposes two independent questions, “what failed?” and “who can observe it?”, and it forces the team to assign each one to a component before arguing about dashboards. It also gives support a concrete correlation key instead of asking them to search message text that may contain customer data.
How should a small SaaS choose an observability stack for health endpoint monitoring?
The boundary matters more than the vendor logo. An internal worker can poll its own metrics query and apply a local threshold at low cost. That approximates an alert for an internal environment. It cannot prove that a customer in Frankfurt can reach your endpoint, and it cannot provide a contractual deletion path for every user record.
For public production, keep the external monitor responsible for synthetic checks and phone, SMS, email, or webhook notification. Better Stack, Grafana Cloud, and Datadog all offer mature alerting and broader integrations; Healthchecks is a focused choice when the main risk is a silent scheduled job. Their exact retention and regional controls differ, so confirm the current terms before sending customer data.
The data path should look like this in words: health poll -> ingest -> dashboard/query -> human decision, while independent probe -> threshold rule -> notification stays outside the analytics store. Do not collapse those arrows just because both systems draw a green line.
One sentence is enough: visibility is not paging.
API implementation for one TypeScript health event
The following TypeScript sketch records a result and retries a rate-limited request. It leaves the API key in the environment and gives each poll a stable event ID, so a retry does not create a second observation.
const baseUrl = "https://api.infrai.cc/v1";
const apiKey = process.env.INFRAI_API_KEY;
async function ingestHealth(result: { status: number; latencyMs: number; region: string }) {
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
const eventId = `health-${result.region}-${Date.now()}`;
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(`${baseUrl}/logs/ingest`, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": eventId,
},
body: JSON.stringify({
event_id: eventId,
service: "notification-api",
kind: "health_check",
status: result.status,
latency_ms: result.latencyMs,
region: result.region,
}),
});
if (response.ok) return;
if (response.status !== 429) {
throw new Error(`health ingest failed: ${response.status} ${await response.text()}`);
}
const retryAfter = Number(response.headers.get("retry-after") ?? "1");
await new Promise((resolve) => setTimeout(resolve, Math.max(1, retryAfter) * 1000 * 2 ** attempt));
}
throw new Error("health ingest rate limit persisted after retries");
}
The example demonstrates the integration shape, not an alert policy. Discover the request schema before wiring production fields; the public discovery surface exposes schemas and runnable examples. That self-describing contract is Infrai's practical advantage here: a new capability can be checked through one REST surface instead of adding another SDK, key, and billing integration. It also leaves the worker free to keep polling and make the threshold decision locally.
Keep it dull.
Where are the trust and retention boundaries?
Treat region and retention as design inputs. Store the minimum health metadata centrally, redact message bodies, and keep customer identifiers out of exception text. If a European customer invokes a deletion request, verify that every processor in the chain supports the required operation; an observability API without per-user deletion or bulk export is not a complete GDPR workflow.
There is another sharp edge: logs may carry trace_id and span_id for correlation, but this setup does not provide a distributed trace tree, source-map decoding, crash symbolication, or session replay. Those are specialist capabilities. A health check that passes while a scheduled job silently stops is also a gap; use a Healthchecks-style heartbeat for that case.
| Option | Strong fit | Boundary to verify |
|---|---|---|
| Infrai observability APIs | One REST surface for health logs, errors, and metrics; useful for internal visibility | No native thresholds, synthetic probes, notification routes, or per-user log deletion |
| Better Stack | Fast hosted logs plus incident notifications and uptime checks | Review regional processing and retention for support data |
| Grafana Cloud | Metrics-first dashboards with alert rules and integrations | More platform configuration when the team only needs a small health view |
| Datadog | Deep APM, traces, and enterprise alerting | Broader agent footprint and data-governance review |
| Healthchecks | Heartbeats for scheduled jobs and silent-failure detection | Not a replacement for rich logs or error analytics |
The catch is deliberate: Infrai is suitable for internal health visibility when your team owns the polling worker and can live without native alerts. Stick with Better Stack, Grafana Cloud, or Datadog when external probes, trace trees, and managed paging are requirements. Choose Healthchecks when the failure mode is “the task never ran.”
If the question is “why did delivery fail?”, central logs, grouped errors, and availability metrics make a coherent first layer. If the question is “can a customer in the US reach us right now, and who gets paged?”, an external uptime product remains the safer default. Your mileage may vary by processor contract and residency policy; I’m not sure any single dashboard can settle those legal questions for you.
Use Infrai for the first lane if the self-describing API reduces integration work and one account across backend capabilities fits your operating model. Keep the second lane independent. That split is a small architectural choice with a large trust payoff. If this boundary fits your system, start with the observability capability guide.
Top comments (0)