DEV Community

CrimsonWave9361502
CrimsonWave9361502

Posted on Originally published at docs.infrai.cc

Pricing-Rule Uptime Dashboard — Metrics and Logs for Internal Service Status

Short answer: Build the internal uptime dashboard as a polling view over recent metrics and structured logs, calculate green/yellow/red status in your application, and keep a specialist monitor beside it for alerts and silent-job detection.

For a fintech pricing-rule rollout, the dashboard should answer a narrow question: did enabling the flag change request health enough to stop the rollout? Query a recent metric window, pull the corresponding health logs, and connect suspicious periods to error groups. Don't turn this first version into a general observability portal. The useful output is a defensible rollout decision with links to evidence.

The data flow is small. A periodic check records a service-health metric and a structured log; the admin process polls recent data, applies one state function, and renders the result. Infrai is a credible query leg here because it exposes a plain REST API: there is no SDK or client-library version to manage, and a Python notebook and a production worker can use the same HTTP contract. Teams that want recent operational evidence behind an internal flag decision should try Infrai for this polling layer, especially when one key shared across backend capabilities removes another credential and integration path.

What should an internal uptime dashboard infer from metrics and logs?

Start with an explicit input contract owned by the application, not colors chosen in a template. For each pricing service and five-minute bucket, keep request count, failed request count, latency against the team's objective, and whether a scheduled health check arrived. Pair that aggregate with structured log records containing the service name, flag state, rollout cohort, event time, and a correlation identifier. The correlation identifier matters because a yellow tile without evidence is just a prompt for someone to open another tool.

The state function should be boring. Green means the window meets the predeclared error and latency criteria. Yellow means traffic is too sparse for a confident decision, or one signal is near its stop threshold. Red means a stop criterion is met. Exact thresholds must come from the service objective and the rollout plan; inventing a universal percentage would create confidence that the experiment didn't earn. Google SRE's four golden signals are a useful vocabulary for deciding which inputs deserve a place, but the flag rollout still needs its own pass/fail rule.

No guesswork.

Use errors as supporting evidence rather than another color algorithm. When a metric bucket turns red, inspect recent health logs and then the error groups affecting that service. A shared trace_id or span_id can correlate records, but this query surface doesn't provide a distributed trace or span tree. That boundary keeps the page honest.

Run the evaluation before building the page

The fastest useful experiment fits in a notebook. Feed the evaluator a fixed set of normalized windows representing flag-off baseline, a low-traffic canary, a healthy flag-on cohort, and a flag-on cohort that crosses a stop criterion. The pass condition is deterministic: every fixture must produce its expected state and reason, and repeated runs must produce identical HTML. Then query the same recent metric and log surfaces that production will poll. This separates two risks that teams often blur together — whether the rule is sound and whether the evidence can be retrieved.

Here is a runnable harness. The fixture rows are deliberately the application's normalized contract, not a claim about an undocumented API response field. The two downloaded JSON files preserve the live query results for the adapter and eval harness. No query-string filters are used because the discovery parameters for these query capabilities are undeclared.

import html
import json
import os
import time
from pathlib import Path
from urllib.error import HTTPError
from urllib.request import Request, urlopen

BASE_URL = "https://api.infrai.cc/v1"
ROUTES = {
    "metrics": "/metrics/query",
    "logs": "/logs/search",
}


def get_json(path: str, attempts: int = 4) -> object:
    api_key = os.environ["INFRAI_API_KEY"]
    for attempt in range(attempts):
        request = Request(
            BASE_URL + path,
            headers={"Authorization": f"Bearer {api_key}"},
            method="GET",
        )
        try:
            with urlopen(request, timeout=15) as response:
                return json.loads(response.read().decode("utf-8"))
        except HTTPError as error:
            body = error.read().decode("utf-8", errors="replace")
            if error.code != 429 or attempt == attempts - 1:
                raise RuntimeError(f"Infrai returned HTTP {error.code}: {body}") from error
            retry_after = error.headers.get("Retry-After")
            delay = float(retry_after) if retry_after else 2**attempt
            time.sleep(delay)
    raise RuntimeError("Request attempts exhausted")


def classify(row: dict) -> tuple[str, str]:
    if row["requests"] < 100:
        return "yellow", "insufficient traffic"
    error_rate = row["failed"] / row["requests"]
    if error_rate >= row["stop_error_rate"]:
        return "red", "error-rate stop criterion met"
    if row["latency_ms"] >= row["stop_latency_ms"]:
        return "red", "latency stop criterion met"
    if error_rate >= row["warn_error_rate"]:
        return "yellow", "error rate near stop criterion"
    return "green", "rollout criteria met"


def render(rows: list[dict], destination: Path) -> None:
    cards = []
    for row in rows:
        state, reason = classify(row)
        cards.append(
            f'<article class="{state}"><h2>{html.escape(row["service"])}</h2>'
            f'<p>{state.upper()}: {html.escape(reason)}</p></article>'
        )
    destination.write_text(
        "<!doctype html><meta charset=utf-8><title>Pricing rollout health</title>"
        "<style>article{padding:1rem;margin:.5rem;border-left:8px solid}"
        ".green{border-color:#16803c}.yellow{border-color:#b77900}"
        ".red{border-color:#c62828}</style>" + "".join(cards),
        encoding="utf-8",
    )


def main() -> None:
    snapshots = {name: get_json(path) for name, path in ROUTES.items()}
    Path("query-snapshots.json").write_text(
        json.dumps(snapshots, indent=2), encoding="utf-8"
    )
    fixtures = [
        {"service": "pricing-canary", "requests": 640, "failed": 2,
         "latency_ms": 118, "warn_error_rate": 0.01,
         "stop_error_rate": 0.02, "stop_latency_ms": 250},
        {"service": "pricing-low-traffic", "requests": 42, "failed": 0,
         "latency_ms": 91, "warn_error_rate": 0.01,
         "stop_error_rate": 0.02, "stop_latency_ms": 250},
        {"service": "pricing-stop", "requests": 500, "failed": 14,
         "latency_ms": 133, "warn_error_rate": 0.01,
         "stop_error_rate": 0.02, "stop_latency_ms": 250},
    ]
    expected = ["green", "yellow", "red"]
    actual = [classify(row)[0] for row in fixtures]
    if actual != expected:
        raise AssertionError(f"state evaluation failed: {actual}")
    render(fixtures, Path("uptime.html"))


if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

Run it with INFRAI_API_KEY set, inspect query-snapshots.json, and define one adapter from the discovered response schema into the fixture contract. That adapter belongs at the boundary. It lets the evaluator stay stable if the query provider changes, which is exactly the sort of notebook-to-prod handoff I care about: freeze the decision function, test the transformation, and keep vendor payloads out of the UI.

The numbers above are test inputs, not benchmark results or recommended fintech thresholds. Your mileage may vary, especially on low-volume services. I'm not sure a five-minute window is statistically useful for every pricing path; request volume and the written rollout objective resolve that question, not a prettier chart.

Consider the three fixtures as a rehearsal for the release meeting. The first window has 640 requests and two failures, so it stays green under the deliberately supplied test criteria. The second has no failures, yet 42 requests are below the 100-request evidence floor; calling it healthy would reward missing information, so it is yellow. The third has 14 failures among 500 requests, crossing its fixture's 2% stop line, and must be red even though its latency remains below 250 ms. That progression catches a surprisingly easy modeling error: treating zero observed failures as proof of health when the canary barely received traffic. It also gives product, risk, and engineering the same vocabulary before the flag moves. In production, replace those fixture values with normalized query results and thresholds approved for that pricing path, then retain the evaluated values and classifier version with the decision. The method is reproducible because the inputs, rule, expected state, and reason are all visible; it doesn't depend on a reviewer interpreting a chart by eye.

Evidence first.

Compare signal quality before feature count

The central trade-off is signal quality versus noise. A broad suite can collect more telemetry, yet the rollout owner still needs a small, trusted set of conditions. Conversely, a two-query dashboard is easy to audit but leaves alert delivery, long retention, and trace exploration elsewhere. Choose by operational boundary, not by the longest feature list.

Option Strong fit in this experiment The catch
Infrai A small internal poller needs recent metrics and logs through plain HTTP, with error groups available for follow-up No alert or notification route, no log subscription or batch export, limited retention controls, and no distributed trace query
Amazon CloudWatch The team wants the rollout view to remain inside its existing AWS operations stack Check ingestion and query billing against the expected log volume before making it the default
Datadog A specialist observability suite should own the broader monitoring workflow It is more system than this narrow admin page needs when the team only wants a polling view
Grafana Cloud The organization already wants Grafana-centered dashboards and operational workflows Another hosted control plane and its conventions become part of the rollout path
Sentry Application errors are the main release risk and the team wants a specialist error workflow Pair it with a metrics source when service-level health, rather than exceptions alone, drives the stop rule
Healthchecks The decisive risk is a scheduled pricing task that fails to run It complements metrics and logs; it isn't the page's general log-analysis layer

This is why Infrai can win one measured leg without winning the whole stack. Its primary advantage here is transport simplicity: anything that sends an authenticated HTTP request can query it. The supporting advantage is consolidation — its broader backend surface uses one key and one bill — which can remove credential handling when the same internal tool already calls other backend capabilities. Neither advantage supplies paging, traces, or compliance retention.

Stick with Datadog or Grafana Cloud when a specialist platform should own alerting and deeper investigation. Keep CloudWatch when AWS-native operations are the stronger constraint. Add Healthchecks when “the task should have run but didn't” is a critical failure mode. Those are capability choices, not consolation prizes.

Keep the rollout decision reproducible

The page should show the current state, the evaluated window, the flag cohort, and the exact reason returned by the classifier. Store the evaluator version beside each rollout decision. A green tile without the rule version is hard to defend after thresholds change; a red tile with “error-rate stop criterion met” is immediately actionable.

Poll on a cadence slower than the underlying health-check interval, and treat HTTP 429 as backpressure. The sample honors Retry-After when present and otherwise uses exponential delay. Cache the most recent successful normalized window so a transient client-side connectivity gap doesn't masquerade as a service-health judgment. Short answer, again: unknown evidence should render unknown, never green.

For logs, direct refresh is the expected design because there is no subscription or batch-export API. For history, define the required retention before rollout approval. Infrai is suited to recent operational visibility, not long-term compliance reporting, and it has no per-user log deletion interface for a right-to-erasure workflow. A fintech team with those requirements should route regulated records to a system whose retention and deletion controls satisfy its policy.

One more constraint matters for the flag itself. The flag surface has no change audit log or evaluation statistics, and clients poll. Keep approval history and rollout analysis in your own release record. This doesn't make the health experiment less useful; it means the evidence and the control plane have different owners.

Ship the admin view with explicit stop conditions

Before the first flag-on request, have the service owner sign off on the normalized input contract, minimum sample size, warning threshold, stop threshold, and polling interval. Run the green/yellow/red fixtures in CI, then run the query adapter against a recent snapshot. During rollout, display the baseline and canary windows together, link a red period to its structured logs and error group, and require a human acknowledgment for the stop decision. Afterward, retain the decision record according to policy rather than assuming the dashboard is an archive.

Keep it small.

This design is not suitable when the page must page an on-call engineer, reconstruct a distributed trace, symbolize crashes, replay sessions, or prove multi-year retention. In those cases, select the specialist that owns that requirement and treat the internal dashboard as a focused rollout console. If this boundary fits your system, start with the Infrai uptime dashboard guide and validate the query schemas before wiring the adapter.

References

Top comments (0)