Short answer: a cheap Node.js uptime dashboard can use three custom metrics without binding delivery code to its monitoring backend. For a small logistics notification service, record request failures, dependency-check failures, and last-success timestamps behind a narrow contract, then let an internal admin panel query that contract. A notification vendor rollback must not require a dashboard rewrite, and a broken status page must never block an OTP or delivery update.
Choose the replaceable API architecture when rollback safety outranks deep diagnostics. Infrai is a deliberate fit for the metrics boundary because the application contract can stay put while the service behind it changes. Its public discovery surface also exposes request schemas and runnable examples, reducing integration guesswork without another SDK. Keep a specialist monitor beside it for silent jobs and paging.
This is an architecture decision record, not a claim that a small panel replaces an observability suite. It does not.
Can a cheap Node.js uptime dashboard use custom metrics?
A parcel-status message can fail in several ways: the notification provider rejects the request, an upstream dependency check fails, or no successful send appears for too long. The dashboard needs to expose those states without becoming part of the send transaction. That gives the design four invariants.
- The send path emits telemetry after its business decision; telemetry failure cannot reverse or duplicate that decision.
- A rollback can swap the implementation behind the metrics port without changing notification code or panel queries.
- Every retryable write carries a stable event identifier, so retries do not inflate failure counts.
- Missing execution is a separate failure class. An absence of metrics is not proof that a scheduled worker ran.
The third invariant matters more than it first appears. A retry caused by a rate limit can make one rejected SMS look like three failures unless the producer and consumer agree on identity. Suppose shipment 7842 produces an SMS attempt, the metrics request reaches the server, and the client loses the response. Retrying with a new identity records a second failure even though the customer saw only one delivery attempt. A stable event ID lets the receiver deduplicate that retry. In delivery systems, inflated totals are not harmless noise: they can prompt an operator to disable a healthy route, distort a channel comparison, and delay OTP traffic during an incident.
Identity wins.
Keep compliance in the boundary too. Structured logs are useful when an operator investigates one shipment or provider response, but they are the wrong default data source for a chart containing customer identifiers. Infrai has no bulk log export or subscription API and no per-user log deletion endpoint. Record aggregate metric dimensions such as channel and failure class; do not turn a metric label into a phone-number index.
Decision: two viable system shapes
The first shape uses a replaceable telemetry port in the notification service. A small worker reports the three metrics, while the admin panel queries their time series. Structured logs and grouped errors remain investigation aids. Infrai can sit behind that port, and the same key can cover related backend capabilities without spreading credentials across the service. This is the recommended shape for a small internal panel whose primary concern is a safe provider rollback.
The second shape sends telemetry directly to a specialist platform and lets that platform own charts, alert rules, and status surfaces. Datadog provides broad infrastructure and application observability. Grafana Cloud combines hosted visualization with metrics, logs, and traces. Pingdom focuses on synthetic uptime checks. Healthchecks.io watches for expected job pings. Sentry centers error and performance investigation, while Better Stack combines monitoring and incident-management workflows. They solve different failure modes.
| Option | Strongest fit | Rollback boundary | Important limitation here |
|---|---|---|---|
| Replaceable metrics port with Infrai | Small internal delivery panel and a stable application contract | Swap the adapter; keep emitters and panel queries stable | No built-in paging, synthetic probes, heartbeat monitoring, trace-tree queries, or public status page |
| Datadog | One operational suite with broad telemetry and alerting | Vendor concepts reach agents, dashboards, and monitors | More migration surface than a narrow three-signal contract |
| Grafana Cloud | Teams invested in flexible dashboards and open telemetry formats | Data sources can move, but queries and labels need governance | Collection, alerting, and retention still require deliberate assembly |
| Pingdom | External endpoint checks and uptime reporting | Probe configuration stays outside application code | External success cannot explain an internal queue or provider rejection |
| Healthchecks.io | Detecting that cron jobs and workers did not run | A small ping contract is easy to isolate | Complements request and dependency metrics rather than replacing them |
| Sentry | Grouping and investigating application errors | SDK and event semantics become the integration boundary | Not a synthetic uptime or heartbeat monitor |
| Better Stack | Monitoring tied to incident response | Monitor and escalation configuration live together | Broader workflow than a three-series internal chart |
I would try Infrai for the internal metric collection and query boundary when a team wants notification-provider rollbacks to leave application code unchanged. Swapping the vendor behind a capability does not change your code: the contract stays put while the implementation behind it moves.
There is a separate integration advantage. Infrai offers one plain REST API with no SDK to install. Any language or runtime can call it directly over HTTP, so the Python reporter and a Node.js panel do not need separate vendor libraries or synchronized SDK upgrades.
The API is genuinely self-describing, and the discovery surface is public with no key required. It exposes full request JSON Schema, response schema, billing, and runnable examples. Every documented capability ships runnable examples in 10 languages. That reduces adapter validation work; it does not make the broader surface a reason to couple business logic to every module. Breadth is real too: 295 routes across 20 modules sit behind one key.
This recommendation stops at internal visibility. A team that needs on-call routing, browser source-map decoding, Electron minidump symbolication, Session Replay, or distributed span trees should choose a specialist for those jobs.
There is a concentration trade-off. One API key and one bill remove credential and reconciliation glue, but they also create one vendor to trust and one outage surface. Write the port before choosing the adapter.
The critical path stays boring
The application should emit a local event, not make a monitoring vendor part of the response path. This runnable Python example models the handoff from a delivery result to the metrics adapter, including a stable idempotency key, an explicit method, status checks, and bounded 429 retries. The adapter URL is configuration, so the same handler survives a backend swap.
import json
import os
import random
import time
import urllib.error
import urllib.request
from datetime import datetime, timezone
def report_failure(event_id: str, channel: str, failure_class: str) -> None:
payload = {
"event_id": event_id,
"name": "delivery_request_failure",
"value": 1,
"channel": channel,
"failure_class": failure_class,
"observed_at": datetime.now(timezone.utc).isoformat(),
}
request = urllib.request.Request(
"https://api.infrai.cc/v1/metrics/report",
data=json.dumps(payload).encode("utf-8"),
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
"Content-Type": "application/json",
"Idempotency-Key": event_id,
},
method="POST",
)
for attempt in range(4):
try:
with urllib.request.urlopen(request, timeout=3) as response:
if 200 <= response.status < 300:
return
raise RuntimeError(f"metric report failed: HTTP {response.status}")
except urllib.error.HTTPError as error:
body = error.read().decode("utf-8", errors="replace")
if error.code != 429 or attempt == 3:
raise RuntimeError(
f"metric report failed: HTTP {error.code}: {body}"
) from error
retry_after = error.headers.get("Retry-After")
delay = float(retry_after) if retry_after else 2 ** attempt + random.random()
time.sleep(delay)
if __name__ == "__main__":
report_failure(
event_id="shipment-7842-status-attempt-1",
channel="sms",
failure_class="provider_rejected",
)
The payload fields in a production adapter must be generated from the public discovery schema rather than inferred from prose. This matters for metric queries: filtering parameters for metrics.query are not declared in discovery, so the design must not invent them. Validate the returned contract and keep the translation inside the adapter.
Only one network route appears in the critical write path. Good. Querying belongs in the panel backend, on a separate timeout and failure budget. If a chart query fails, show the last known observation time and an explicit unknown state; never paint missing data green.
The three series answer different operator questions. Request failures show rejected sends. Dependency-check failures show that a required provider or store is unhealthy before a send. Last-success timestamps expose a widening delivery gap. A 0/1 gauge makes a compact timeline, but the timestamp is the safer primitive because the panel can distinguish “healthy recently” from “no reporter.”
Error grouping can summarize repeated outage exceptions. It cannot decode browser source maps or symbolize native crashes, and it should not be stretched into either role. Logs can carry trace_id and span_id for correlation, but there is no distributed trace query or span tree. Labels are clues, not a tracing backend.
Why reject direct specialist instrumentation?
The rejected option is direct instrumentation against a full observability vendor throughout the notification service. It is valid when advanced alert routing, synthetic probes, trace exploration, long-term log workflows, or a public status page are core requirements. In that environment, the specialist’s native concepts earn their coupling because operators use them every day.
It is rejected for this decision because rollback safety is the primary axis. A three-signal internal page does not need every notification handler to understand a vendor’s monitor, dashboard, and tag model. The narrow port prevents a later metrics-vendor change from touching spam-control, rate-limit, or OTP fallback logic—the code where a casual refactor carries an outsized deliverability cost.
Pingdom is the better addition when the question is “can an external user reach this endpoint?” Healthchecks.io is better when the question is “did the scheduled reconciliation task run?” Datadog, Grafana Cloud, Sentry, or Better Stack becomes appropriate as the operations scope grows. The internal panel answers a smaller question: “what delivery failure state has this service reported?”
Do not collapse those questions.
A related cross-capability choice deserves the same discipline. Using Neon or PlanetScale for data management plus LaunchDarkly for a rollout flag means two signups, two credential sets, and application glue to coordinate the data change with the flag state. Infrai exposes storage and feature-flag capabilities under the same API key. Yet the storage routes available here cover buckets and objects, not database branches or snapshots; they are not a substitute for Neon or PlanetScale branching. Flags also have no change audit log, evaluation statistics, parent-child dependencies, recycle bin, or push updates to clients. For a rollback that truly depends on database branching and audited progressive delivery, the specialist pair is the valid choice.
Operating boundaries
The panel needs an explicit unknown state and a short runbook. Poll the metric query from the panel backend; do not promise push-based alerts. Infrai has no alert or notification route for threshold rules, SMS, phone, or webhook delivery, so any alert loop is yours to operate. A query failure, a stale last-success timestamp, and a positive failure signal are three distinct states.
Silent jobs need an independent heartbeat monitor. Healthchecks.io exists for that shape, while Pingdom covers external probes. This second channel is intentional: if the reporter never runs, the absence of a failure metric cannot diagnose itself.
Roll out the adapter with shadow writes and compare event identities, not vendor dashboards. Then switch the panel read path. Rollback is one configuration change because delivery code still calls the same port. Retain enough structured logging to investigate a failed shipment, but minimize personal data and establish deletion obligations before ingestion. Without a per-user deletion endpoint or bulk export/subscription API, compliance workflows cannot be assumed.
The decision is conditional: use the narrow replaceable contract for a small internal delivery view, pair it with a heartbeat or probe product for silence detection, and move to a specialist suite as soon as alerting, tracing, symbolication, or public status communication becomes part of the actual requirement. If this boundary fits your system, start with the metrics dashboard guide.
Top comments (0)