Topic 67

Synthetic Monitoring and RUM

Synthetics

Every signal in this book so far is measured from inside Harborline — and the inside can be entirely green while a customer stares at a spinner. DNS, the TLS certificate, and the CDN all live outside the instrumented perimeter, so job="bookings" can report a 0.02% error ratio while the apex record points at a decommissioned load balancer. The trigger for this topic was an old scar: before Chapter 5 deployed the first blackbox probe, Harborline's certificate came within four days of expiring, and nothing then running would have noticed before the browsers did.

Two disciplines close the gap from opposite ends. Synthetic monitoring probes the system from where the user stands, on a fixed schedule, under controlled conditions. Real User Monitoring measures what actual browsers actually experienced. One is controlled and continuous, the other real and messy — and a production service wants both, wired to different destinations.

Synthetics vs RUM — controlled and continuous against real and messy; you want both
Synthetic monitoring
A scripted probe from a fixed location on a fixed schedule — controlled, comparable over time, and working at zero traffic. It tells you the flow can work, so it feeds pages.
Real User Monitoring
Real sessions in real browsers across every device, network, and geography — ground truth, but noisy and traffic-dependent. It tells you how the flow did work, so it feeds dashboards and planning.

The Inside-Out Blind Spot

Internal metrics measure the service, not the path to it. A request that dies at DNS resolution, a TLS handshake against an expired certificate, a CDN edge serving stale errors — none of these ever reach bookings, so none appear in its request counters. "Up" is only meaningful measured from the user's side of that path, which means the measurement has to originate outside the network Harborline controls.

blackbox_exporter

Prometheus's outside-in probe is blackbox_exporter: modules for HTTP, TCP, ICMP, and DNS checks, driven by a relabeling pattern in which the target URL becomes a query parameter — Prometheus scrapes the exporter, and the exporter performs the probe. The result comes back as metrics like any other: probe_success feeds availability alerts, probe_duration_seconds tracks the user-side latency of the whole path.

That scar gets its full treatment here — the Chapter 5 probe grows into a synthetic-monitoring practice. probe_ssl_earliest_cert_expiry reports the certificate's expiry as a timestamp, so the rule probe_ssl_earliest_cert_expiry - time() < 14 * 86400 turns expiry into a ticket with two weeks of runway instead of a Saturday outage. The scrape config is one relabeling dance, learned once.

# probe the public booking URL through the full DNS + TLS + CDN path
- job_name: "blackbox-http"
  metrics_path: /probe
  params:
    module: [http_2xx]
  static_configs:
    - targets: ["https://harborline.example/book"]
  relabel_configs:
    - {source_labels: [__address__], target_label: __param_target}
    - {target_label: __address__, replacement: "blackbox:9115"}

Scripted Synthetic Flows

A single GET proves the homepage answers; it cannot prove a customer can book a ferry. Scripted flows walk the real journey — search a route, hold a seat, reach the payment step — as code. Harborline scripts the flow in k6 and runs it every 5 minutes from outside the network against a sandboxed test account with test-mode processor keys; Grafana Cloud's synthetic checks run k6 under the hood, so the same script scales from a cron job to a managed multi-location service. The flow that earns scripting is the revenue-critical one, and there is exactly one of those.

Real User Monitoring

RUM inverts every property of a probe. The Grafana Faro web SDK rides inside the web SPA and reports what each real browser saw — Core Web Vitals (LCP, INP, CLS), JavaScript errors, frontend traces — shipped to the Faro receiver on Grafana Alloy and stored in the same Loki and Tempo as everything else. A synthetic probe from one clean network will never see the p75 LCP of a phone on ferry-terminal Wi-Fi; RUM sees nothing else. The vitals thresholds are defined at p75, which is the percentile worth tracking.

Both, Deliberately

The two signals route to different destinations by design. Synthetics give a controlled, comparable, alertable baseline that works at zero traffic — a probe fails at 03:00 whether or not any customer is awake, so probe_success == 0 feeds Alertmanager as a page. RUM gives ground truth across real devices, networks, and geographies, but only where traffic exists and only with real-world noise mixed in — so it feeds dashboards and the sprint-planning meeting. Harborline alerts on synthetics and learns from RUM.

Synthetic Monitoring vs RUM

Synthetic monitoring — a scripted check from a fixed location on a fixed schedule: controlled, comparable over time, and working at zero traffic. Choose it for availability alerting and pre-launch coverage; it tells you the flow can work.

RUM — measurement of real sessions in real browsers: every device, network, and geography, but noisy and traffic-dependent. Choose it for performance truth and for prioritizing frontend work; it tells you how the flow did work.

Common Mistakes
  • Probing from obs-01, one rack away from app-01 — the probe skips the public DNS, CDN, and TLS path entirely and stays green through exactly the outages it exists to catch; probe from outside the network, ideally from 2–3 locations.
  • Paging on a single failed probe — one packet-lossy minute at one vantage point pages Mara at 02:00; require consecutive failures with for: 3m or a multi-location quorum before a probe becomes a page.
  • Discovering certificate expiry from the outage — probe_ssl_earliest_cert_expiry exists precisely so a warning fires 14 days out, and not alerting on it converts a calendar entry into an incident.
  • Letting the synthetic booking flow touch production state — a probe that creates real bookings pollutes the data 288 times a day and, wired to payments, charges a real card; scripted flows need a sandboxed account and test-mode processor keys.
  • Alerting on RUM web vitals as if they were probes — real-user data swings with traffic mix, and a tour group on 2G "degrades" p75 LCP with nothing to fix; RUM feeds dashboards and planning, synthetics feed pages.
Best Practices
  • Probe every public entry point with blackbox_exporter from outside your own network, and alert on probe_ssl_earliest_cert_expiry at 14 days, not on the expiry itself.
  • Script the one revenue-critical journey — search, book, pay — as a k6 synthetic flow against a sandboxed account, and run it on a 5-minute schedule.
  • Instrument the SPA with the Faro web SDK and track Core Web Vitals at p75, the percentile the vitals thresholds are defined against.
  • Route the two signals differently by design: synthetic failures to Alertmanager as pages, RUM trends to dashboards and the planning meeting.
Comparable toolsStack blackbox_exporter + k6 / Grafana Cloud Synthetic Monitoring — the synthetic layerSaaS Checkly, Pingdom, UptimeRobot — dedicated synthetic monitoring servicesRUM Grafana Faro — the stack's RUM SDK; Datadog RUM, New Relic Browser, Sentry as managed equivalents

Knowledge Check

The apex DNS record points at a decommissioned load balancer. Why do the internal RED metrics stay green?

  • Prometheus stopped scraping when the DNS record changed
  • The failed requests never reach the service, so no counter sees them
  • Error ratios only track 5xx responses, never connection or resolution failures
  • The scrape interval is too coarse to catch the outage

Along which axis do synthetics and RUM divide the work?

  • Synthetics are open source while RUM requires a SaaS vendor
  • Synthetics measure outside the network, RUM measures inside it
  • Controlled and continuous versus real and messy
  • Synthetics cover the backend while RUM covers the frontend

Why does a probe running on obs-01 defeat the purpose of synthetic monitoring?

  • It bypasses the public path whose failures the probe exists to catch
  • The probe's load would distort the metrics on the observability host
  • blackbox_exporter only works when deployed on a cloud provider
  • The measured latency numbers would come back slightly too optimistic to trust

Why is p75 LCP from RUM the wrong input for a paging alert?

  • RUM data arrives far too slowly to drive any time-sensitive paging alert
  • The percentile should be p99, which catches more regressions
  • Traffic mix moves the number when nothing is broken or fixable
  • Alertmanager cannot ingest metrics that originate in browsers

The k6 booking flow runs every 5 minutes. What must be true of the account it uses?

  • It needs admin privileges to clean up the bookings it creates
  • It should rotate among real customer accounts to stay realistic
  • It is sandboxed, with test-mode keys on the payment processor
  • It must be blocked from reaching the payment step entirely

You got correct