β˜€οΈSiang
Dashboard

Cheatsheet Grafana & Node-RED: PromQL, Dashboard, dan Flow Automation

GRATIS

Referensi cepat Grafana & Node-RED β€” PromQL queries, grafana variables, panel types, Node-RED nodes, MQTT, JavaScript function, dan alerting rules



1. PromQL β€” Query Dasar

πŸ’‘ Tips

PromQL adalah bahasa query untuk Prometheus. Gunakan Grafana Explore untuk test query sebelum masuk ke dashboard.

Instant Vector (nilai saat ini)

# Semua nilai metrik
http_requests_total

# Filter label
http_requests_total{job="api-server"}
http_requests_total{method="GET", handler="/api/v1"}
http_requests_total{status=~"5.."}    # Regex match
http_requests_total{handler!~"/admin.*"} # Regex not match

Range Vector (banyak nilai dalam rentang waktu)

# Rate: per detik (counter)
rate(http_requests_total[5m])

# Per-second rate dari gauge
deriv(cpu_temperature[5m])

# Increase: total kenaikan dalam range
increase(http_requests_total[1h])

Fungsi Aggregasi

# Sum total requests
sum(http_requests_total)

# Sum per label
sum by (method) (rate(http_requests_total[5m]))
sum without (instance) (http_requests_total)

# Rata-rata
avg(node_cpu_seconds_total)
avg by (mode) (rate(node_cpu_seconds_total[5m]))

# Min / Max
min(node_memory_MemFree_bytes)
max by (instance) (rate(http_requests_total[5m]))

# Count
count(up == 1)
count by (job) (up)

# Top/Bottom N
topk(5, rate(http_requests_total[5m]))
bottomk(3, node_memory_MemFree_bytes)

2. PromQL β€” Query Lanjutan

Histogram Quantile

# P95 latency
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

# P99 latency per handler
histogram_quantile(0.99, 
  sum by (handler, le) (rate(http_request_duration_seconds_bucket[5m]))
)

# P50 (median)
histogram_quantile(0.50, rate(http_request_duration_seconds_bucket[5m]))

Math Operations

# CPU usage percentage
100 * (1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])))

# Memory usage percentage
100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)

# Disk usage percentage
100 * (1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})

# Error rate
sum(rate(http_requests_total{status=~"5.."}[5m])) 
  / sum(rate(http_requests_total[5m])) * 100

# Request per second by service
sum by (job) (rate(http_requests_total[5m]))

Fungsi Waktu

# Offset: bandingkan dengan sebelumnya
http_requests_total offset 1h        # 1 jam lalu
rate(http_requests_total[5m] offset 1d)  # 1 hari lalu

# Time-based functions
changes(node_boot_time_seconds[24h])   # Berapa kali berubah
resets(http_requests_total[1h])        # Counter resets
absent(up{job="api"})                  # Cek metrik hilang
absent_over_time(up{job="api"}[5m])    # Cek hilang dalam range

# Clamp & clamp_min / clamp_max
clamp_min(node_temperature, 0)
clamp_max(node_temperature, 100)

# Predict linear (prediksi 1 jam ke depan)
predict_linear(node_filesystem_avail_bytes[6h], 3600)

Tabel PromQL Populer

KebutuhanQuery PromQL
Request/detiksum(rate(http_requests_total[5m]))
Error rate (%)sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) * 100
P99 latencyhistogram_quantile(0.99, sum by(le)(rate(http_request_duration_seconds_bucket[5m])))
CPU usage %100*(1-avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])))
Memory usage %100*(1-node_memory_MemAvailable_bytes/node_memory_MemTotal_bytes)
Disk usage %100*(1-node_filesystem_avail_bytes/node_filesystem_size_bytes)
Uptime (jam)(time() - node_boot_time_seconds) / 3600
Container restartsum by(name)(increase(container_restart_count[1h]))

3. Grafana Variables

Tipe Variable

TipeKegunaanContoh Query
QueryAmbil dari data sourcelabel_values(up, job)
CustomDaftar manualprod,staging,dev
IntervalAuto intervalauto,1m,5m,1h,1d
Data SourcePilih data sourceprometheus
ConstantNilai tetapproduction
Ad hoc filtersFilter dinamisβ€”

Variable Functions

# Label values (dari metrik)
label_values(up, job)
label_values(http_requests_total{job="api"}, handler)
label_values(node_uname_info, nodename)

# Query result
query_result(topk(5, http_requests_total))

# Regex filter
label_values(http_requests_total{job=~"$job"}, status)

# Multi-value & All
# Aktifkan "Multi-value" dan "Include All option"
# Gunakan di query: {job=~"$job"}
# Regex match (~=) otomatis handle multi-select

Penggunaan Variable dalam Query

# Variable $job
sum by (handler) (rate(http_requests_total{job="$job"}[5m]))

# Variable $interval
rate(http_requests_total{job="$job"}[$interval])

# Multi-value $status
http_requests_total{status=~"$status"}

# Variable chaining
label_values(http_requests_total{job="$job"}, handler)

4. Grafana Panel Types

PanelKegunaanKapan Dipakai
Time SeriesGrafik waktuDefault untuk sebagian besar metrik
StatAngka besar dengan warnaKPI, counter, uptime
GaugePengukur analogCPU %, memory %, disk %
Bar GaugeBar horizontal/vertikalPerbandingan antar service
TableTabel dataDaftar host, top-N, log
HeatmapDensitas warnaHistogram latency, distribusi
Pie ChartDiagram lingkaranDistribusi status code, traffic
Bar ChartDiagram batangPerbandingan kategori
LogsLog viewerLoki/ES log exploration
Node GraphGraph topologyService dependency
Alert ListDaftar alert aktifMonitoring dashboard
TextMarkdown/HTMLDokumentasi, judul section

Panel Options Umum

// Override satuan (Panel β†’ Overrides)
// CPU: Unit = percent (0-100)
// Memory: Unit = bytes (IEC)
// Latency: Unit = seconds (s)
// Requests: Unit = requests per second (reqps)

// Thresholds
// Green: < 70% | Yellow: 70-90% | Red: > 90%

// Value mapping
// 0 = "Down" (red) | 1 = "Up" (green)

5. Grafana Alerting Rules

# Contoh alert rule (Unified Alerting)

# Alert: High CPU Usage
# Condition: avg() of query(A, 5m, now) > 80
# PromQL:
100 * (1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])))

# Alert: High Error Rate
# Condition: sum() of query(A, 5m, now) > 5
# PromQL:
sum(rate(http_requests_total{status=~"5.."}[5m])) 
  / sum(rate(http_requests_total[5m])) * 100

# Alert: Disk Almost Full (< 10% free)
# PromQL:
100 * (1 - node_filesystem_avail_bytes{mountpoint="/"} 
  / node_filesystem_size_bytes{mountpoint="/"}) > 90

# Alert: Service Down
# PromQL:
up == 0

# Alert: High Memory Usage (> 90%)
# PromQL:
100 * (1 - node_memory_MemAvailable_bytes 
  / node_memory_MemTotal_bytes) > 90

Notification Channels

ChannelContoh Config
Emailsmtp.server: mail.example.com:587
SlackWebhook URL: https://hooks.slack.com/...
TelegramBot Token + Chat ID
DiscordWebhook URL
PagerDutyIntegration Key
WebhookCustom HTTP endpoint

6. Node-RED Node Types

Input Nodes

NodeFungsiOutput
injectTrigger manual/timerTimestamp atau payload
http inHTTP endpointRequest object
mqtt inSubscribe MQTTPayload message
tcp inTCP connectionBuffer/string
websocket inWebSocket server/clientMessage
file inBaca fileString/buffer
csvParse CSVArray/object
jsonParse JSONObject

Output Nodes

NodeFungsi
debugTampilkan di sidebar debug
http responseKirim HTTP response
mqtt outPublish ke MQTT broker
fileTulis/append ke file
emailKirim email (SMTP)

Logic & Processing

NodeFungsi
functionCustom JavaScript logic
switchRouting berdasarkan kondisi
changeSet/change/delete property
filterFilter pesan (debounce, dedupe)
delayDelay/rate limit pesan
splitSplit array/object
joinJoin messages
batchBatch messages
templateMustache template
execRun shell command
htmlParse HTML (cheerio)

7. Node-RED MQTT

MQTT In Node (Subscribe)

// Config: Server = broker.hivemq.com:1883
// Topic = sensor/+/suhu
// QoS = 1
// Output = auto-detect (string/parsed JSON)

// Wildcard:
// sensor/+/suhu  β€” single level (sensor/ruang1/suhu)
// sensor/#       β€” multi level (sensor/ruang1/suhu, sensor/ruang1/lembab)

MQTT Out Node (Publish)

// Topic: actuator/relay/1
// QoS: 1
// Retain: true/false

// Inject node β†’ Change (set msg.payload = "ON") β†’ MQTT Out

// Publish JSON:
// msg.payload = JSON.stringify({ relay: 1, state: "ON", ts: Date.now() })
// msg.topic = "actuator/relay/1"

Contoh Flow: Sensor β†’ MQTT β†’ Dashboard

// Flow:
// [inject 5s] β†’ [function: baca sensor] β†’ [mqtt out: sensor/suhu]
// [mqtt in: sensor/suhu] β†’ [json] β†’ [chart β†’ dashboard]

// Function node "baca sensor":
msg.payload = {
  suhu: (Math.random() * 15 + 20).toFixed(1),
  kelembaban: (Math.random() * 30 + 50).toFixed(1),
  timestamp: new Date().toISOString()
};
msg.topic = "sensor/ruang1/data";
return msg;

8. Function Node JavaScript

// Basic: ubah payload
msg.payload = msg.payload.toUpperCase();
return msg;

// Akses context (penyimpanan antar eksekusi)
let counter = flow.get("counter") || 0;
counter++;
flow.set("counter", counter);
msg.payload = counter;
return msg;

// Global context
global.set("lastUpdate", new Date());

// Conditional output (multi output)
if (msg.payload > 30) {
  return [msg, null];     // Output 1: panas
} else {
  return [null, msg];     // Output 2: normal
}

// Multiple messages
let messages = [null, null];
messages[0] = { payload: "Alert: Suhu tinggi!" };
messages[1] = { payload: msg.payload };
return messages;

// Array manipulation
let data = msg.payload;
let avg = data.reduce((a, b) => a + b, 0) / data.length;
msg.payload = { average: avg.toFixed(2), count: data.length };
return msg;

// HTTP request (pakai node "http request" lebih mudah)
// Tapi bisa juga di function:
const got = global.get("got"); // Perlu install got library

Error Handling di Function Node

// Validasi payload
if (!msg.payload || typeof msg.payload !== 'object') {
    node.error("Invalid payload", msg);
    return null; // Hentikan flow
}

// Try-catch
try {
    let data = JSON.parse(msg.payload);
    msg.payload = data;
    return msg;
} catch (e) {
    node.warn("Parse error: " + e.message);
    return null;
}

// Send to catch node
if (msg.payload.error) {
    node.error("Data error", msg);
    return null;
}

9. Dashboard JSON Structure

Node-RED Dashboard (node-red-dashboard)

// Tab config (ui_base)
// Set tab name di dashboard config

// Widget types:
// ui_button    β€” Tombol aksi
// ui_slider    β€” Input slider (range)
// ui_switch    β€” Toggle on/off
// ui_numeric   β€” Input angka
// ui_text_inputβ€” Input teks
// ui_dropdown  β€” Dropdown select
// ui_colour_picker β€” Pilih warna
// ui_chart     β€” Grafik (line/bar/scatter)
// ui_gauge     β€” Gauge analog
// ui_text      β€” Tampilkan teks
// ui_notification β€” Toast notification
// ui_spacer    β€” Spacer/separator

// Chart configuration (ui_chart node):
{
  "group": "group1",
  "order": 0,
  "width": 6,
  "height": 4,
  "label": "Suhu",
  "chartType": "line",
  "legend": true,
  "xformat": "HH:mm:ss",
  "interpolate": "linear",
  "nodata": "Tidak ada data",
  "options": {
    "yaxis": { "min": 0, "max": 50 }
  }
}

Grafana Dashboard JSON (Export/Import)

// Struktur dasar dashboard JSON Grafana:
{
  "dashboard": {
    "title": "Monitoring IoT",
    "tags": ["iot", "monitoring"],
    "timezone": "browser",
    "panels": [
      {
        "id": 1,
        "type": "timeseries",
        "title": "Suhu Sensor",
        "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 },
        "targets": [
          {
            "expr": "sensor_temperature{location=\"ruang1\"}",
            "legendFormat": "{{sensor}}",
            "refId": "A"
          }
        ],
        "fieldConfig": {
          "defaults": {
            "unit": "celsius",
            "thresholds": {
              "steps": [
                { "value": null, "color": "green" },
                { "value": 35, "color": "yellow" },
                { "value": 40, "color": "red" }
              ]
            }
          }
        }
      }
    ],
    "templating": {
      "list": [
        {
          "name": "location",
          "type": "query",
          "query": "label_values(sensor_temperature, location)"
        }
      ]
    },
    "time": {
      "from": "now-6h",
      "to": "now"
    },
    "refresh": "30s"
  },
  "overwrite": false
}

10. Docker Compose Setup

# docker-compose.yml β€” Full Stack Monitoring
version: "3.8"
services:
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=30d'

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin123
    volumes:
      - grafana-storage:/var/lib/grafana

  nodered:
    image: nodered/node-red:latest
    ports:
      - "1880:1880"
    volumes:
      - nodered-data:/data

  mosquitto:
    image: eclipse-mosquitto:2
    ports:
      - "1883:1883"
      - "9001:9001"
    volumes:
      - ./mosquitto.conf:/mosquitto/config/mosquitto.conf

  node-exporter:
    image: prom/node-exporter:latest
    ports:
      - "9100:9100"
    pid: host

volumes:
  grafana-storage:
  nodered-data:

Prometheus Config (prometheus.yml)

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']

  - job_name: 'grafana'
    static_configs:
      - targets: ['grafana:3000']
← Sebelumnya Dashboard Monitoring IoT Selanjutnya β†’ Artikel Lainnya
πŸ” Zoom
100%
🎨 Tema