Adds one top-level telemetry skill covering the observability stack that deploys as one unit: Prometheus (scrape config, recording/alerting rules, relabeling, retention, HA), the OpenTelemetry Collector (pipelines, receivers/processors/exporters, sampling, trace/span correlation), and Loki (ingest, LogQL, retention, labels). Ships the read-only telemetry-check script (stdlib-only, --json): Prometheus rule sanity mirroring promtool check rules plus scrape-target reachability probes, fixture-tested with 16 unittest/pytest cases. Includes five dated references, a human-facing README, and six eval cases covering rule authoring, pipeline design, and retention. Routes up to platform-engineering and grafana without duplicating their content. Regenerates the llms.txt / marketplace / plugin catalogs and adds the README index entry. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
4.8 KiB
Stack Integration and Retention
Last Updated: 2026-08-03
How the three components of the telemetry stack fit together, and how to make retention decisions across them instead of per-component by accident. Sources: Prometheus storage documentation, OpenTelemetry Collector documentation, and Loki retention documentation (all accessed 2026-08-03).
The stack as one unit
The components share a data flow — instrumented services emit metrics, logs, and traces; the OpenTelemetry Collector (or direct exporters) delivers them; Prometheus stores metrics and evaluates rules; Loki stores logs; Grafana queries both and displays the result. The stack is operated as one unit because a change in any layer changes the behavior of every layer above it:
| Layer | Component | Owns |
|---|---|---|
| Collection | OTel Collector receivers, Prometheus scrape jobs | What data enters the stack |
| Processing | Collector processors (batch, sample, resource) | What the data looks like when stored |
| Storage | Prometheus TSDB, Loki chunks/index | How long data lives and how fast queries are |
| Evaluation | Prometheus rules | What the data means (alerts, recording rules) |
| Presentation | Grafana | What humans see (dashboards, Grafana-side alerting) |
Operational decisions therefore cross component boundaries: a label added in
relabeling is a label PromQL sees; a trace_id carried by the collector is a
LogQL matcher; a retention window chosen for Prometheus is a gap in history a
dashboards-as-code change cannot recover.
Retention as a stack decision
Each component has independent retention, and the combined footprint is what the team pays for:
| Component | Setting | Applies to | Default behavior |
|---|---|---|---|
| Prometheus | --storage.tsdb.retention.time / .size |
Raw samples (blocks) | 15 days; lazily enforced by compaction |
| OTel Collector | exporter queue + memory_limiter |
In-flight data | Queue backs up then drops oldest on pressure |
| Loki | retention_enabled, retention_period, retention_size (per tenant) |
Indexed log streams | No retention unless enabled; compactor enforces it |
Decide per component by the question the data answers:
- hot metrics for alerting: keep enough history to evaluate every rule window
plus headroom (a
for: 10mrule needs at least that much history); - samples for trends: retention length is a capacity trade-off, not a correctness requirement — long histories belong in a separate store (Thanos/Mimir) with its own owner;
- logs for debugging and audit: retention is a compliance decision with an owner; short retention on logs destroys the only evidence an incident post-mortem can use.
The failure mode is defaulting every component and discovering the cost when
storage is the incident. Write the decision down: retention_period,
retention flags, and the RPO/RTO framing belong in the deployment config and
its review checklist, not in tribal memory.
Cross-component consistency checks
- Scrape config and collector receivers must agree on the metrics endpoint:
a
metric_relabel_configsdrop on Prometheus side does not stop the collector from exporting the metric elsewhere. - Rule expressions and recording rules must not depend on labels the scrape
config does not produce — validate with
telemetry-check --rulesplus a live query, not by reading the config. - LogQL matchers must match labels the
lokiexporter actually attaches — a matcher onappfails silently when the collector maps it toservice.nameonly. - Trace correlation needs
trace_id/span_idin both the OTLP log records and the metrics exemplars; verify one pivot query end-to-end after any collector pipeline change.
Alerting on the stack itself
The stack needs its own health rules (in a file you also validate with
telemetry-check --rules):
up{job=~"prometheus|otel-collector|loki"}== 0 for component loss;prometheus_tsdb_head_seriesgrowth vs a budget for cardinality;rate(loki_distributor_lines_received_total[5m])vs a floor to catch silent ingest loss;otelcol_exporter_send_failed_ratioabove a threshold for delivery loss;- retention drift:
prometheus_tsdb_storage_blocks_bytesand compactor delete counters vs the decided policy.
These rules live in this skill's scope (the Prometheus rules file); the
dashboards and Grafana-side alert routes for them are grafana territory.
Routing
- Observability strategy — what to instrument, SLI/SLO design, error budgets — is platform-engineering.
- Dashboards, panels, Grafana alert rules, contact points, and notification policies are grafana.
- This skill owns the collection/ingest/retention layer and the Prometheus rules files those layers consume. When a task crosses into those skills, route there instead of duplicating their content.