Skip to content

Commit 092ccd7

Browse files
docs(platform): add telemetry data verification guide
Signed-off-by: Arnob kumar saha <arnob@appscode.com>
1 parent d727851 commit 092ccd7

1 file changed

Lines changed: 218 additions & 0 deletions

File tree

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
---
2+
layout: docs
3+
menu:
4+
docsplatform_{{.version}}:
5+
identifier: cluster-management-telemetry-data-check
6+
name: Verifying Telemetry Data
7+
parent: cluster-management
8+
weight: 100
9+
menu_name: docsplatform_{{.version}}
10+
section_menu_id: guides
11+
---
12+
13+
# Verifying Telemetry Data (Logs & Metrics)
14+
15+
This guide shows how to confirm your logs and metrics are actually being stored — not just
16+
collected — in the monitoring stack: **ClickHouse** for logs, **Thanos + S3** for metrics.
17+
See [OpenTelemetry Monitoring](otel-monitoring.md) for how the stack is set up.
18+
19+
## Basics
20+
21+
- Logs and metrics are stored in the **same S3 bucket**, under different prefixes:
22+
- Logs → `<bucket>/logs/`
23+
- Metrics → `<bucket>/metrics/`
24+
- Bucket, endpoint, and prefixes are defined in your `TelemetryStack` resource:
25+
```bash
26+
kubectl get telemetrystack -n monitoring -o yaml
27+
```
28+
Look under `spec.logs.clickhouse.s3` and `spec.metrics.thanos.s3`.
29+
- ClickHouse database name is your tenant ID, not a fixed name like `otel` or `default`.
30+
Find it with `SHOW DATABASES` (see below) — the table inside is `otel_logs`.
31+
- All checks below run from inside the cluster via `kubectl exec`, so no port-forwarding
32+
or extra credentials are required except for the optional S3 listing step.
33+
34+
---
35+
36+
## 1. Check logs are landing in ClickHouse
37+
38+
Find the ClickHouse pod:
39+
40+
```bash
41+
kubectl get pods -n monitoring -l app.kubernetes.io/name=clickhouse
42+
```
43+
44+
List databases and confirm the `otel_logs` table exists:
45+
46+
```bash
47+
kubectl exec -n monitoring <clickhouse-pod> -- clickhouse-client --query "SHOW DATABASES"
48+
kubectl exec -n monitoring <clickhouse-pod> -- clickhouse-client --query "SHOW TABLES FROM <your-tenant-db>"
49+
```
50+
51+
Check row count and freshness:
52+
53+
```bash
54+
kubectl exec -n monitoring <clickhouse-pod> -- clickhouse-client --query \
55+
"SELECT count(), min(Timestamp), max(Timestamp), now() FROM <your-tenant-db>.otel_logs"
56+
57+
kubectl exec -n monitoring <clickhouse-pod> -- clickhouse-client --query \
58+
"SELECT count() FROM <your-tenant-db>.otel_logs WHERE Timestamp > now() - INTERVAL 5 MINUTE"
59+
```
60+
61+
**Healthy result:** `max(Timestamp)` is close to `now()`, and the 5-minute count is greater
62+
than zero. If both queries return recent data, logs are flowing end-to-end.
63+
64+
---
65+
66+
## 2. Check metrics are landing in Thanos / S3
67+
68+
Find the Thanos query pod:
69+
70+
```bash
71+
kubectl get pods -n monitoring -l app.kubernetes.io/name=thanos-query
72+
```
73+
74+
Ask it which StoreAPIs it's talking to and what time range each one covers:
75+
76+
```bash
77+
kubectl exec -n monitoring <thanos-query-pod> -- \
78+
wget -qO- --header="THANOS-TENANT: <your-tenant>" "http://localhost:9090/api/v1/stores"
79+
```
80+
81+
Look at the `minTime`/`maxTime` fields (Unix epoch **milliseconds**) for each store:
82+
83+
```bash
84+
date -u -d @<maxTime-in-seconds> # drop the last 3 digits first to convert ms -> s
85+
```
86+
87+
**Healthy result:** `maxTime` should be within the last few minutes for the live/receive
88+
store, and within your compaction interval for the long-term S3-backed store.
89+
90+
For a second confirmation, check the ingester's own TSDB head timestamp:
91+
92+
```bash
93+
kubectl get pods -n monitoring -l app.kubernetes.io/name=thanos-receive-ingester
94+
kubectl exec -n monitoring <thanos-receive-ingester-pod> -- wget -qO- http://localhost:10902/metrics \
95+
| grep prometheus_tsdb_head_max_time
96+
```
97+
98+
If 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.
108+
109+
---
110+
111+
## 3. Check the S3 bucket directly (optional)
112+
113+
Read the bucket, endpoint, and credentials from the `TelemetryStack` spec first — the same
114+
values back both the ClickHouse and Thanos configs:
115+
116+
```bash
117+
kubectl get telemetrystack -n monitoring -o jsonpath='{.spec.metrics.thanos.s3}'
118+
```
119+
120+
Which client you use depends on where the bucket actually lives. The backend is
121+
S3-compatible in every case, so pick the matching variant below.
122+
123+
### a. MinIO (in-cluster or S3-compatible with a custom endpoint)
124+
125+
Use the MinIO client (`mc`) with the endpoint and access credentials from the spec.
126+
The `--insecure` flag is only needed when the endpoint serves a self-signed certificate:
127+
128+
```bash
129+
kubectl run mc-check -n monitoring --rm -it --restart=Never --image=minio/mc:latest -- sh
130+
mc alias set myminio <endpoint> <accessKey> <secretKey> --insecure
131+
mc ls myminio/<bucket>/logs/ --insecure --recursive | tail
132+
mc ls myminio/<bucket>/metrics/ --insecure --recursive | tail
133+
```
134+
135+
### b. Real AWS S3
136+
137+
When the bucket is a genuine AWS S3 bucket, there is no custom endpoint — just pass the
138+
AWS access key, secret, and region. Drop `--endpoint-url` entirely so the CLI talks to
139+
the regional AWS endpoint:
140+
141+
```bash
142+
kubectl run aws-check -n monitoring --rm -it --restart=Never --image=amazon/aws-cli:latest \
143+
--env AWS_ACCESS_KEY_ID=<accessKey> \
144+
--env AWS_SECRET_ACCESS_KEY=<secretKey> \
145+
--env AWS_DEFAULT_REGION=<region> \
146+
-- s3 ls s3://<bucket>/logs/ --recursive | tail
147+
# repeat for the metrics prefix
148+
kubectl run aws-check -n monitoring --rm -it --restart=Never --image=amazon/aws-cli:latest \
149+
--env AWS_ACCESS_KEY_ID=<accessKey> \
150+
--env AWS_SECRET_ACCESS_KEY=<secretKey> \
151+
--env AWS_DEFAULT_REGION=<region> \
152+
-- s3 ls s3://<bucket>/metrics/ --recursive | tail
153+
```
154+
155+
### c. s3grid (S3-compatible service with a custom endpoint)
156+
157+
s3grid is S3-compatible but reached through its own endpoint, so use the AWS CLI with
158+
`--endpoint-url` pointing at the s3grid endpoint from the spec:
159+
160+
```bash
161+
kubectl run s3grid-check -n monitoring --rm -it --restart=Never --image=amazon/aws-cli:latest \
162+
--env AWS_ACCESS_KEY_ID=<accessKey> \
163+
--env AWS_SECRET_ACCESS_KEY=<secretKey> \
164+
--env AWS_DEFAULT_REGION=<region> \
165+
-- s3 ls s3://<bucket>/logs/ --endpoint-url <s3grid-endpoint> --recursive | tail
166+
# repeat for the metrics prefix
167+
kubectl run s3grid-check -n monitoring --rm -it --restart=Never --image=amazon/aws-cli:latest \
168+
--env AWS_ACCESS_KEY_ID=<accessKey> \
169+
--env AWS_SECRET_ACCESS_KEY=<secretKey> \
170+
--env AWS_DEFAULT_REGION=<region> \
171+
-- s3 ls s3://<bucket>/metrics/ --endpoint-url <s3grid-endpoint> --recursive | tail
172+
```
173+
174+
> The same `mc`-based flow from (a) works against s3grid too — `mc alias set` accepts any
175+
> S3-compatible endpoint. Use whichever client you already have handy.
176+
177+
**Healthy result (any variant):** recent objects under both prefixes, with timestamps
178+
matching your retention/compaction schedule.
179+
180+
---
181+
182+
## Summary
183+
184+
| Pipeline | Where to look | Healthy signal |
185+
|---|---|---|
186+
| Logs | ClickHouse `<tenant-db>.otel_logs` | `max(Timestamp)` ≈ now, non-zero rows in last 5 min |
187+
| Metrics | Thanos Query `/api/v1/stores`, receive ingester `/metrics` | `maxTime`/head timestamp advancing, close to now |
188+
| S3 | `<bucket>/logs/` and `<bucket>/metrics/` prefixes | Recent objects under both prefixes |
189+
190+
---
191+
192+
## Troubleshooting: metrics stale but logs healthy
193+
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.
197+
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:
201+
202+
```bash
203+
kubectl get prometheus -n monitoring <prometheus-name> -o jsonpath='{.spec.remoteWrite}'
204+
```
205+
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:
209+
210+
```bash
211+
kubectl get prometheusagents -A
212+
```
213+
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.

0 commit comments

Comments
 (0)