@@ -96,15 +96,9 @@ kubectl exec -n monitoring <thanos-receive-ingester-pod> -- wget -qO- http://loc
9696```
9797
9898If this timestamp is stale (not advancing over successive checks), metrics are not being
99- ingested. Check that Prometheus (or your agent) has ` remoteWrite ` configured to point at
100- the Thanos receive router:
101-
102- ``` bash
103- kubectl get prometheus -n monitoring < prometheus-name> -o jsonpath=' {.spec.remoteWrite}'
104- ```
105-
106- An empty result means nothing is shipping samples to Thanos, regardless of whether
107- Prometheus itself is scraping normally.
99+ ingested. Metrics are shipped from each connected cluster by the OpenTelemetry stack
100+ (` appscode-otel-stack ` ). See the [ Troubleshooting] ( #troubleshooting-metrics-stale-but-logs-healthy )
101+ section below for how to trace that pipeline.
108102
109103---
110104
@@ -191,28 +185,123 @@ matching your retention/compaction schedule.
191185
192186## Troubleshooting: metrics stale but logs healthy
193187
194- Logs and metrics are independent paths through the same ` TelemetryStack ` — one being
195- healthy says nothing about the other, so always run both checks above rather than
196- assuming one implies the other.
188+ There is no Prometheus doing remote-write in this setup. Telemetry is shipped from each
189+ connected cluster by the ** ` appscode-otel-stack ` ** chart (built on ` opentelemetry-kube-stack ` ),
190+ which runs two OpenTelemetry collectors in the ` monitoring ` namespace of the * connected*
191+ cluster:
197192
198- If the metrics checks show a stale ` maxTime ` /head timestamp that isn't advancing, the
199- most common cause is that nothing is configured to remote-write samples into Thanos.
200- Check the ` Prometheus ` CR's remote-write config:
193+ - ** Daemonset (agent) collector** : runs on every node. Its ` prometheus ` receiver scrapes
194+ targets assigned by the ** Target Allocator** (which discovers ` ServiceMonitor ` /` PodMonitor `
195+ CRs), and its ` filelog ` receiver collects container logs. Everything is forwarded over
196+ OTLP to the gateway collector.
197+ - ** Gateway collector** (deployment): receives OTLP and exports to the monitoring cluster
198+ through ` prom-label-proxy ` :
199+ - ** Metrics** → ` prometheusremotewrite ` exporter → ` https://<ingest-endpoint>:10001/api/v1/receive `
200+ → Thanos receive. The ` THANOS-TENANT ` header is injected per batch by the
201+ ` headers_setter ` extension.
202+ - ** Logs** → ` clickhouse ` exporter → the same ` prom-label-proxy ` endpoint → ClickHouse
203+ (` otel_logs ` table).
204+
205+ The ` <ingest-endpoint> ` depends on how the platform is deployed:
206+
207+ - ** DNS mode** : the exporters point at the monitoring cluster's domain name.
208+ - ** IP mode** : the exporters use the fixed hostname ` prom-label-proxy.monitoring.svc.cluster.local ` ,
209+ which is mapped to the monitoring cluster's IP via a ` hostAliases ` entry on the gateway
210+ collector pod (required for TLS certificate verification against a bare IP).
211+
212+ Confirm the endpoint actually in use from the gateway collector's config:
201213
202214``` bash
203- kubectl get prometheus -n monitoring < prometheus-name > -o jsonpath= ' {.spec.remoteWrite} '
215+ kubectl get opentelemetrycollectors -n monitoring -o yaml | grep -B2 -A2 ' endpoint: '
204216```
205217
206- An empty result means Prometheus may be scraping fine locally, but nothing is shipping
207- samples to the Thanos receive router. Also check for a ` PrometheusAgent ` resource that
208- might be expected to do remote-write instead:
218+ Logs and metrics share the daemon → gateway OTLP hop and the mTLS client cert
219+ (` otel-client-cert ` ), but split into different exporters at the gateway. So if logs are
220+ healthy and metrics are stale, connectivity and certs are fine; the problem is specific
221+ to the metrics path: either ** scraping** (daemon collector / Target Allocator) or the
222+ ** remote-write export** (gateway → Thanos). Run these checks ** on the connected cluster** :
223+
224+ ### a. Collector pods are running
209225
210226``` bash
211- kubectl get prometheusagents -A
227+ kubectl get pods -n monitoring -l otel-collector-type=daemonset
228+ kubectl get pods -n monitoring -l otel-collector-type=deployment
212229```
213230
214- ** Fix:** add ` spec.remoteWrite ` to the ` Prometheus ` CR, pointing at the Thanos receive
215- router's remote-write endpoint (` http://thanos-receive-router-<stack>.monitoring.svc:19291/api/v1/receive ` )
216- with the tenant header the router's hashring expects (e.g. ` THANOS-TENANT: <tenant> ` ).
217- After applying, re-run the ` prometheus_tsdb_head_max_time ` check above over a couple of
218- minutes to confirm the timestamp starts advancing.
231+ The daemonset collector must have one Running pod per node; a node without an agent pod
232+ silently drops that node's scrape targets (allocation is per-node).
233+
234+ ### b. Gateway is exporting metrics without errors
235+
236+ Check the gateway collector's own telemetry for sent vs. failed metric points. The
237+ collector image is minimal (no shell or ` wget ` inside), so ` kubectl exec ` will not work;
238+ port-forward its internal telemetry port (8888) and query it from your machine instead:
239+
240+ ``` bash
241+ kubectl port-forward -n monitoring < gateway-collector-pod> 8888:8888 &
242+ sleep 2 # give the port-forward a moment to establish
243+ curl -s http://localhost:8888/metrics \
244+ | grep -E ' otelcol_exporter_(sent|send_failed|enqueue_failed).*metric_points'
245+ ```
246+
247+ These counters are cumulative since the pod started, so a single reading proves nothing:
248+ a large ` send_failed ` value may just be leftover from a past incident (for example a
249+ monitoring-cluster restart) while everything is healthy now. Run the ` curl ` again after
250+ 30 seconds or so and compare the two readings; only the counters that are still
251+ * advancing* matter. There are three possible outcomes:
252+
253+ 1 . ** ` sent_metric_points{exporter="prometheusremotewrite"} ` is increasing and
254+ ` send_failed ` /` enqueue_failed ` stay flat.** The gateway is exporting successfully, so
255+ this cluster's pipeline is healthy. The problem is downstream (prom-label-proxy or
256+ Thanos receive on the monitoring cluster) or a tenant mismatch; continue with step (d).
257+ 2 . ** ` send_failed_metric_points ` is climbing.** Exports are failing. Read the gateway logs
258+ for the actual ` prometheusremotewrite ` error (HTTP status codes, TLS failures) against
259+ the ` prom-label-proxy ` endpoint:
260+
261+ ``` bash
262+ kubectl logs -n monitoring < gateway-collector-pod> --tail=100 | grep -iE " error|prometheusremotewrite"
263+ ```
264+
265+ TLS or certificate errors point at the ` otel-client-cert ` secret (check it exists and
266+ is not expired). Connection refused or timeout points at a wrong or unreachable ingest
267+ endpoint. HTTP 4xx/5xx responses point at the prom-label-proxy / Thanos receive side
268+ on the monitoring cluster.
269+ 3 . ** All counters are flat or zero.** The gateway has nothing to export, which means the
270+ daemon collectors are not scraping anything. Continue with step (c).
271+
272+ A growing ` enqueue_failed_metric_points ` means the exporter's sending queue is
273+ overflowing because sends are too slow or failing, and those points are dropped; treat
274+ it the same as outcome 2.
275+
276+ Note the exporter retries for a bounded time (` max_elapsed_time: 120s ` ) and then drops the
277+ batch, so persistent export errors mean permanent data loss, not delayed delivery.
278+
279+ When finished, stop the background port-forward with ` kill %1 ` .
280+
281+ ### c. Scrape targets exist and are being allocated
282+
283+ If the gateway shows nothing to export (` sent ` flat, no errors), the daemon collectors
284+ aren't scraping anything. Check that the Target Allocator is running and that
285+ ` ServiceMonitor ` /` PodMonitor ` resources exist for your workloads:
286+
287+ ``` bash
288+ kubectl get pods -n monitoring -l app.kubernetes.io/component=opentelemetry-targetallocator
289+ kubectl get servicemonitors,podmonitors -A
290+ ```
291+
292+ The Target Allocator watches these CRs and distributes their scrape targets across the
293+ daemonset collectors. No matching monitors (or an unhealthy allocator) means the
294+ ` prometheus ` receiver has nothing to scrape: no data flows and no errors are logged
295+ anywhere, which is exactly the "silently stale" symptom.
296+
297+ ### d. Data flowing under the wrong tenant
298+
299+ Metrics may be arriving in Thanos but under a different tenant than the one you're
300+ querying. The gateway derives the tenant from resource attributes: it defaults to
301+ ` default ` , and is set to the source namespace name only for namespaces labeled
302+ ` ace.appscode.com/client-org: "true" ` ; batches with no tenant attribute fall back to
303+ ` anonymous ` . Re-run the store/query checks from section 2 with ` THANOS-TENANT: default `
304+ (and ` anonymous ` ) before concluding data is missing.
305+
306+ After fixing whichever stage was broken, re-run the ` prometheus_tsdb_head_max_time ` check
307+ from section 2 over a couple of minutes to confirm the timestamp starts advancing.
0 commit comments