Chapter 43 / 51
Volume 5 · Extensions, Ops & Projects

Ops & observability: teaching the service to speak

No admin backend (ch. 1's trap) doesn't mean no observability — it means observability is part of your application code. This chapter gives the three pillars the XServer treatment.

Overview

Positioning: ch. 06's debugging handbook, operations edition. Deliverables: a structured logging layer, memory-report switches, /health and /stats inspection routes — ready to drop into your modules/.

43.1 Intro

Observability's three questions: is the service alive (health), what did the service do (logs), is the service still healthy (resource trends). In XServer each has a very short path: health = one route; logs = xrtLogger (76 APIs — levels/formatting/multiple sinks) or printf; resources = memory reports + RSS sampling. What matters is installing all three from day one, not bolting them on after an incident.

43.2 Structured logging

From printf to logger
/* development: printf suffices (the demo's way) */
printf("[demo] handler done: %s\n", sPath);

/* operations: xrtLogger — levels, multiple sinks, takeover-capable */
/* create the logger in Init (file + stdout dual sinks, configurable level) */
G_pLog = xrtLoggerCreate(...);
/* request paths: with level and module tag */
xrtLogInfo(G_pLog, "api", "item %lld fetched in %lld us", iId, iUs);
xrtLogWarn(G_pLog, "api", "slow query: %lld us", iUs);
/* destroy in ServiceUnit — the logger is generation state too */
  • Level discipline: INFO for normal flow (disable-able), WARN for auto-recoverable anomalies, ERROR for things needing human eyes
  • Request IDs: generate a short ID at the module layer and thread it through every log line of a request — the "correlation thread" when debugging
  • Output: stdout goes to journald/the service manager; file sinks rotate themselves (or let logrotate split by size)

43.3 Memory observability

  • External trends: RSS sampling (drill's way: PowerShell WorkingSet64 / /proc VmRSS) into monitoring — a flat line is health, a slope needs investigation
  • Internal structure: xrt's memory-debug system (canaries / UAF / allocation reports, TEXT and JSON formats) — enabled in the host build config (see xrt book ch. 06), toggled as needed in production
  • Swap reconciliation: finalize counts (ch. 30) + the report's active allocation count are the daily evidence of "hot reload, zero leaks"

43.4 Inspection routes

/health and /stats (pattern)
/* /health: the minimal endpoint for load balancers and monitoring */
ReplyText(pReq, 200, "ok");            /* keep complex logic out */

/* /stats: application-level metrics (behind auth) */
xvalue* p = xrtValueObject();
xrtValueObjectSetNew(p, "uptime_s",  xrtValueInt64(UpSec()));
xrtValueObjectSetNew(p, "requests",  xrtValueInt64((int64)G_iTotal));
xrtValueObjectSetNew(p, "ws_online", xrtValueInt64(ConnCount()));
xrtValueObjectSetNew(p, "reload",    ReloadSummary()); /* terminal counts */
ReplyJSON(pReq, 200, p);  xrtValueRelease(p);

Pattern points: /health answers life or death only (dependency checks there make LBs kill good instances); /stats reports business metrics behind auth (ch. 27's discipline). Want Prometheus format? xvalue → text in a one-line loop.

43.5 Contract

  • Pillars: health route, structured logging, resource trends — installed on day one.
  • Discipline: /health minimal; /stats authenticated; log levels split three ways.
  • Baselines: the tests and drills (func/drill/routebench) keep running across versions — they are the control group for behavioral regressions.

Common mistakes

Querying the database inside /health
Symptom
The database blips; the LB pulls every instance — full-site avalanche.
Cause
"Deep physicals" mixed into the "liveness probe". The LB probe answers only "can this process serve"; dependency health goes to a separate /deep (for humans or alerts).
Logs with no ID threading
Symptom
Under concurrency the logs interleave; a single request's trace can't be reconstructed.
Cause
Bare printf carries no request context. Generate a short ID at the module layer and carry it in every line (43.2's request-ID discipline).

Exercises

BasicInstalling the three pillars

Add /health, /stats and xrtLogger-based request logging to the demo.

Acceptance: /health <1ms; /stats requires a token; logs filterable by request ID.
AdvancedTrend collection

An external script samples RSS + /stats every 10s into CSV and plots.

Acceptance: through a 10-swap stress segment, the curve stays flat and readable.
ChallengeA Prometheus text endpoint

Implement /metrics: export ws_online, request counts, swap counts and more from your registries.

Acceptance: Prometheus scrapes successfully and a minimal dashboard renders.

Summary

PointConclusion
Three pillars/health (life), logs (traces), resource trends (wellness)
Loggingprintf in dev / xrtLogger in ops; request-ID threading
MemoryRSS trends sampled externally; allocation reports reconciled internally
Inspectionhealth minimal, stats authenticated, deep separated
API references in this chapter
xrt further reading