On this page
  1. What you’ll build
  2. Step 1 — Add a health endpoint
  3. Step 2 — Expose Prometheus metrics
  4. Step 3 — Configure Prometheus to scrape
  5. Step 4 — Build a dashboard in Grafana
  6. Where AI coding assistants get this wrong
  7. Checklist
  8. FAQ
    1. What is a scrape?
    2. Why use Prometheus and Grafana together?
    3. What is the difference between a counter and a gauge?
  9. Related topics
  10. Sources
tutorial

How to Set Up Basic Application Monitoring

Set up basic app monitoring with Prometheus metrics, a health endpoint, and Grafana dashboards. A tool-agnostic tutorial with a concrete example.

Quick answer

  • Start with three things: a health endpoint, a few core metrics, and one dashboard.
  • Use Prometheus to scrape metrics and Grafana to display them; both are free and open source.
  • The success signal is a graph of request rate, error rate, and latency for your service.

What you’ll build

Minimal but real monitoring for a Node.js web app: a /health endpoint, Prometheus metrics scraped on a schedule, and a Grafana dashboard showing request rate, error rate, and latency. The approach is tool-agnostic; the same ideas apply to any stack.

Step 1 — Add a health endpoint

app.get("/health", (req, res) => {
  res.json({ status: "ok", uptime: process.uptime() });
});

How to verify it worked: curl localhost:3000/health returns {"status":"ok",...}. This endpoint is your cheapest alert source and your load balancer’s check.

Step 2 — Expose Prometheus metrics

Using the prom-client library:

const client = require("prom-client");
const collectDefaultMetrics = client.collectDefaultMetrics;
collectDefaultMetrics();

const httpRequests = new client.Counter({
  name: "http_requests_total",
  help: "Total HTTP requests",
  labelNames: ["method", "status"],
});

app.use((req, res, next) => {
  res.on("finish", () => {
    httpRequests.inc({ method: req.method, status: res.statusCode });
  });
  next();
});

app.get("/metrics", async (req, res) => {
  res.set("Content-Type", client.register.contentType);
  res.end(await client.register.metrics());
});

How to verify it worked: curl localhost:3000/metrics prints text lines like http_requests_total{method="GET",status="200"} 42.

Step 3 — Configure Prometheus to scrape

Create prometheus.yml:

global:
  scrape_interval: 15s
scrape_configs:
  - job_name: "my-app"
    static_configs:
      - targets: ["localhost:3000"]

Run Prometheus and open http://localhost:9090. In the query box, type rate(http_requests_total[5m]) and press Execute.

How to verify it worked: the query returns data points, proving Prometheus is scraping your app.

Step 4 — Build a dashboard in Grafana

Start Grafana, add Prometheus as a data source, and create three panels:

  • sum(rate(http_requests_total[5m])) — request rate.
  • sum(rate(http_requests_total{status=~"5.."}[5m])) — error rate.
  • histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) — p95 latency.

How to verify it worked: the panels update as you hit the app, and error rate rises when you trigger a failing route.

Where this bites vibecoders

AI assistants will happily paste a full observability stack — Prometheus, Grafana, Tempo, Loki — for an app with no metrics to scrape. Start with the endpoint and the counter, confirm real data flows, then grow. A monitoring stack with nothing to monitor is the most common false “I set up observability” feeling.

Where AI coding assistants get this wrong

  • Installing dashboards before the app emits any metrics.
  • Hardcoding dashboard JSON with panels that reference nonexistent metric names.
  • Skipping the health endpoint, leaving no simple liveness signal.
  • Emitting high-cardinality labels (like raw request IDs) that blow up storage.

Checklist

  • Add a /health endpoint first.
  • Expose request rate, error rate, and latency as metrics.
  • Confirm Prometheus scrapes real data before building dashboards.
  • Keep metric labels low-cardinality (status codes, methods — not IDs).
  • Alert on user-facing symptoms: error rate and latency, not just CPU.

FAQ

What is a scrape?

In Prometheus, a scrape is the scheduled HTTP fetch of a /metrics endpoint. Prometheus pulls metrics from your app at a fixed interval and stores them as a time series. The pull model means your app needs no agent — it just exposes an endpoint.

Why use Prometheus and Grafana together?

Prometheus collects and stores metrics and provides a query language. Grafana visualizes those metrics as dashboards and alerts. They are separate tools that pair well, but you can use either with alternatives.

What is the difference between a counter and a gauge?

A counter only increases (total requests), while a gauge can go up and down (current memory). For rates, you use the rate() function on counters, which is why request counts are counters, not gauges.

Sources

Share: