LandfallDocs
Integrations · Telemetry

OpenTelemetry Collector & Prometheus

This page is two things at once, and it says up front which is which. Landfall's own dev environment runs a self-hosted OpenTelemetry Collector and Prometheus to observe itself — that pipeline is described below so an operator can reason about where the platform's own metrics come from. Separately, your own Prometheus (self-hosted or otherwise) can be connected as a queryable source the investigator agent reads from during an incident, the same way it reads Datadog or Coralogix. The two are independent: you do not need to run anything like Landfall's own pipeline to connect your Prometheus, and Landfall's own pipeline is not itself "an integration" you configure.

How Landfall's own pipeline works

core-api already builds a full OpenTelemetry span tree on every request via the OpenTelemetry SDK. Two independent paths turn that (and new metrics) into something queryable:

core-api
OTel SDK
OTel Collector
OTLP :4318, spanmetrics
Prometheus
scrapes :8889

The second, independent path: core-api's OpenTelemetry SDK also runs its own PrometheusExporter directly, on its own HTTP server (:9464 by default) — not a route on core-api's normal :3001 port, and not behind Caddy. Prometheus scrapes this endpoint too, as a second, independent job.

  • Traces reach the Collector over OTLP and are consumed by its spanmetrics connector, which derives RED (Rate/Errors/ Duration) metrics — traces_spanmetrics_calls_total and traces_spanmetrics_duration_milliseconds_*, keyed by HTTP method, route, and status code. On this deployment, that is the only way trace data survives: no trace store (Tempo or otherwise) runs in AWS, so an individual span is not queryable there — only the metrics derived from it.
  • Metrics reach Prometheus two ways: via the Collector (OTLP push, then the Collector's own Prometheus exporter on :8889), and directly from core-api's own exporter on :9464. Both are real, independent scrape jobs — losing one does not mean losing the other.

Both the Collector and Prometheus are reachable only from other containers on the same host — neither publishes a port, and neither has a Caddy route. The instance's own security group happens to allow inbound 80/443 from anywhere, so the ONLY thing standing between these two services and the public internet is that absence: no port mapping, no reverse-proxy route. Two small, easy-to-miss lines, which is exactly why this page says so explicitly.

Running it locally

The whole stack (Collector, Prometheus, Alertmanager, plus Tempo and Grafana for local- only trace/dashboard exploration) already exists in deploy/docker/docker-compose.yml, behind the observability compose profile. pnpm dev:up does not start it — five extra containers on every contributor's machine for a stack most feature work never touches was not worth making the default. Start it explicitly:

Terminal
docker compose -f deploy/docker/docker-compose.yml --profile observability up -d
pnpm nx serve core-api  # with OTEL_TRACES_EXPORTER=otlp, OTEL_METRICS_EXPORTER=otlp,prometheus

Confirm the direct exporter with curl localhost:9464/metrics — not :3001/metrics. Prometheus's own UI is at http://localhost:9090; every scrape target (core-api, otel-collector, otel-collector-internal, prometheus) should show up == 1.

Connecting a Prometheus as a queryable source

Whether it's Landfall's own dev-environment Prometheus or your own separately-run instance, an organization connects it the same way every other telemetry source is connected: through the integrations wizard. Once connected, the investigator agent can query it during an incident with zero source-specific agent code — the same dynamic-discovery mechanism every other source uses (see Integrations architecture).

Prometheus
Base URL (+ optional auth)
Landfall
Settings → Integrations

What you'll need

  • A Prometheus server reachable FROM Landfall — a real constraint worth stating plainly. For this deployment's own dogfooding, that is the compose-internal http://prometheus:9090, reachable only because core-api runs on the same host. A customer's own Prometheus, running inside their own network, is typically not reachable from a hosted Landfall the way a public SaaS API (Datadog, Coralogix, Sentry) is — this is a genuine limitation of Prometheus as a customer-facing source, not an oversight, and it's why this integration is documented here rather than promised as turnkey for every deployment topology.
  • An admin on your Landfall organization, to save the connection under Settings → Integrations.
  1. Settings → Integrations → Prometheus

    Enter your Prometheus server's base URL. If it sits behind auth, add either a bearer token or a basic-auth username/password — leave both blank for an unauthenticated instance (the common case for a self-hosted Prometheus already inside a private network).

    Settings → Integrations → Prometheus
    Landfall's Prometheus integration panel: a Base URL field, optional Bearer token field, optional basic-auth username/password fields, and a Test connection button.
  2. Test connection

    Landfall calls your Prometheus's own /api/v1/status/buildinfo endpoint before saving anything — a cheap, read-only call that exists purely to answer "is this actually a reachable Prometheus." A server that can't be reached, or that rejects the supplied credentials, is refused outright rather than stored as "configured but unverified."

    Settings → Integrations → Prometheus
    Landfall's Prometheus integration panel showing a green connected status and the message Prometheus reachable at http://prometheus:9090.
  3. Save integration

    Prometheus now shows Configured alongside your organization's other connectors, and appears in the capability listing an incident's investigator (human or Beacon) can query against.

    Settings → Integrations
    Landfall's Integrations list showing the Prometheus tile with a green Configured status alongside Datadog, Coralogix, and AWS.
Test connection failed?
  • Confirm the base URL is reachable FROM wherever core-api runs, not just from your own browser/laptop — the two are frequently on different networks.
  • If your Prometheus requires auth, confirm you've set exactly one of bearer token OR basic auth; a bearer token takes precedence when both are present.
  • The base URL should be the origin only (e.g. http://prometheus.internal:9090) — Landfall appends /api/v1/… itself.

Alerting → incidents

Connecting Prometheus (above) lets the investigator agent read your metrics during an investigation. Opening an incident automatically the moment a Prometheus alerting rule fires is a separate, independent capability — Prometheus's own Alertmanager, not Prometheus itself, is what calls Landfall. See Triggering Integrations → Alertmanager for that setup. The two are independent; most teams eventually set up both.

Reference

FieldValue
Base URLYour Prometheus server's origin, reachable from Landfall — required
Bearer tokenOptional; sent as Authorization: Bearer
Basic auth username/passwordOptional; ignored when a bearer token is set
Read operationslistMetrics (discover what metric names exist — /api/v1/label/__name__/values), instantQuery (/api/v1/query), rangeQuery (/api/v1/query_range, for correlating a metric against an incident's time window), listAlerts (/api/v1/alerts)
core-api's own direct metrics endpoint<core-api host>:9464/metrics (not :3001)
Collector's republished endpointotel-collector:8889/metrics