Tóm tắt: Tạo biến device (query variable lấy giá trị label source), rồi biến interface lọc theo $device (chained variable). Panel dùng $device / $interface trong query; bật Repeat để mỗi thiết bị một panel hoặc một row. Transformations (Reduce, Join, Organize fields...) xử lý dữ liệu sau khi query về, không cần sửa query.
Luồng hoạt động
flowchart LR DS[Datasource] -->|"label_values(..., source)"| V1["Biến device"] V1 -->|"lọc theo $device"| V2["Biến interface"] V1 --> Q["Query panel"] V2 --> Q Q --> T["Transformations"] T --> P["Panel (repeat theo device)"]
Cấu hình
Query variable
Dashboard settings → Variables → New variable → Type Query.
| Datasource | Biến device |
Biến interface (phụ thuộc device) |
|---|---|---|
| Prometheus | label_values(interfaces_in_octets, source) |
label_values(interfaces_in_octets{source=~"$device"}, name) |
| InfluxDB (Flux) | schema.tagValues(bucket: "telemetry", tag: "source") |
xem đoạn Flux dưới |
| ClickHouse | SELECT DISTINCT source FROM telemetry.interfaces WHERE time > now() - INTERVAL 1 DAY |
SELECT DISTINCT name FROM telemetry.interfaces WHERE source IN (${device:singlequote}) AND time > now() - INTERVAL 1 DAY |
import "influxdata/influxdb/schema"
schema.tagValues(
bucket: "telemetry",
tag: "name",
predicate: (r) => r._measurement == "interfaces" and contains(value: r.source, set: ${device:json}),
start: -1d,
)Hàm khác cho Prometheus: label_names(), metrics(interfaces_.*), query_result(topk(10, rate(interfaces_in_octets[5m]))) (kèm Regex để cắt lấy label).
Tuỳ chọn quan trọng của biến:
| Tuỳ chọn | Ý nghĩa |
|---|---|
| Refresh = On dashboard load / On time range change | Lúc nào chạy lại query lấy danh sách giá trị |
| Multi-value | Cho chọn nhiều giá trị |
Include All + Custom all value .* |
Với Prometheus/Loki, All thành .* thay vì liệt kê hết giá trị (query ngắn hơn) |
| Regex | Lọc/cắt giá trị, ví dụ /^(pe|p)\d+-.*/; nhóm tên (?<text>...) và (?<value>...) tách nhãn hiển thị và giá trị thật |
| Sort | Alphabetical, Numerical... |
Biến khác: Custom (liệt kê tay hni,hcm,dng), Constant, Interval (1m,5m,1h), Ad hoc filters (tự thêm điều kiện label cho mọi query Prometheus/Loki).
Dùng biến trong query
sum by (source, name) (rate(interfaces_in_octets{source=~"$device", name=~"$interface"}[$__rate_interval])) * 8Biến nhiều giá trị phải dùng =~ (Grafana nối thành a|b|c). Định dạng khác theo cú pháp ${var:format}:
| Cú pháp | Kết quả với pe1, pe2 |
Dùng cho |
|---|---|---|
${device:regex} |
pe1|pe2 (escape ký tự regex) |
PromQL, LogQL |
${device:pipe} |
pe1|pe2 |
Regex không cần escape |
${device:singlequote} |
'pe1','pe2' |
SQL IN (...) |
${device:sqlstring} |
'pe1','pe2' (escape ') |
SQL |
${device:json} |
["pe1","pe2"] |
Flux contains(set: ...) |
${device:csv} |
pe1,pe2 |
API, URL |
${device:raw} |
không escape | Khi datasource tự xử lý |
Biến có sẵn: $__interval, $__rate_interval (Prometheus, nên dùng trong rate()), $__range, $__from / $__to, $__dashboard. ClickHouse/SQL có macro $__timeFilter(cột).
Repeat panel và repeat row
- Panel: Edit panel → Panel options → Repeat options → Repeat by variable =
device, Repeat direction = Horizontal (kèm Max per row) hoặc Vertical. Trong query dùngsource="$device": mỗi bản sao nhận một giá trị. - Row: thêm row, đặt panel vào row, ở Row options chọn Repeat for =
device. Cả row (nhiều panel) được nhân theo từng thiết bị. - Biến phải bật Multi-value hoặc Include All, nếu không chỉ có một bản.
Trong JSON model:
{
"type": "timeseries",
"title": "Traffic $device",
"repeat": "device",
"repeatDirection": "h",
"maxPerRow": 3
}Transformations hay dùng
| Transformation | Dùng để |
|---|---|
| Reduce (Series to rows) | Mỗi series thành một dòng Max/Mean/Last, làm bảng tổng hợp interface |
| Labels to fields | Đưa label source, name thành cột của bảng |
| Join by field (OUTER/INNER) | Ghép kết quả nhiều query theo cột chung, ví dụ bps vào và bps ra |
| Organize fields by name | Ẩn, đổi tên, sắp xếp lại cột |
| Rename fields by regex | Rút gọn tên series dài |
| Filter data by values | Chỉ giữ dòng thoả điều kiện (bps > 0) |
| Add field from calculation | Tính cột mới (Binary operation: in + out) |
| Sort by / Limit | Top-N phía Grafana |
| Config from query results | Lấy ngưỡng/max từ một query khác (vd speed interface) |
Transformations chạy trong trình duyệt: dữ liệu lớn thì nên tính ở query (topk, GROUP BY) thay vì dồn về Grafana.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
| Dropdown rỗng | Query variable sai, hoặc time range của biến không có dữ liệu | Bấm Run query trong trang biến xem preview; kiểm tra tên metric/label |
| Chọn nhiều giá trị thì query lỗi | Dùng = với biến multi-value |
Dùng =~"$device", SQL dùng IN (${device:singlequote}) |
Biến interface không đổi khi đổi device |
Query con không tham chiếu $device |
Thêm $device vào query; Grafana chỉ chạy lại biến phụ thuộc |
All làm query rất dài, chậm |
Không đặt Custom all value | Đặt .* (PromQL/LogQL) |
| Repeat chỉ ra một panel | Biến không Multi-value / không chọn All | Bật Multi-value, chọn nhiều giá trị |
| Import dashboard sang Grafana khác báo datasource not found | Query gán cứng uid datasource của môi trường cũ |
Dùng biến kiểu Data source hoặc cố định uid, xem Grafana provisioning |
Flux báo lỗi kiểu ở contains(set: ...) |
Biến không bật Multi-value nên ${device:json} ra chuỗi, không phải mảng |
Bật Multi-value, hoặc dùng r.source == "${device}" |