openclaw-grafana-lens
Version:
OpenClaw plugin that gives AI agents full Grafana access — 18 composable tools for PromQL/LogQL/TraceQL queries, dashboard creation, alerting, SRE investigation, security monitoring, data collection pipeline management via Grafana Alloy (29 recipes), and
74 lines (73 loc) • 3.15 kB
JavaScript
/**
* Recipe: node-exporter
*
* System metrics (CPU, memory, disk, network) via Alloy's built-in
* Unix exporter. No external node_exporter binary needed.
*
* Generated Alloy pipeline:
* prometheus.exporter.unix → prometheus.scrape → prometheus.remote_write
*/
import { AlloyConfigBuilder, componentLabel, escapeString } from "../../config-builder.js";
const recipe = {
name: "node-exporter",
category: "metrics",
signal: "metrics",
summary: "System metrics — CPU, memory, disk, network via built-in Unix exporter",
dashboardTemplate: "metric-explorer",
credentialParams: [],
requiredParams: [],
optionalParams: [
{
name: "scrapeInterval",
type: "string",
description: "How often to collect system metrics",
default: "15s",
},
],
generateConfig(pipelineId, params, targets, _pipelineName) {
const scrapeInterval = params.scrapeInterval || "15s";
const jobName = params.jobName || "node-exporter";
const exporterLabel = componentLabel(pipelineId, "unix");
const scrapeLabel = componentLabel(pipelineId, "scrape");
const relabelLabel = componentLabel(pipelineId, "relabel");
const writeLabel = componentLabel(pipelineId, "write");
const builder = new AlloyConfigBuilder();
builder.addBlock(`prometheus.exporter.unix "${exporterLabel}" { }`);
builder.addBlock(`prometheus.scrape "${scrapeLabel}" {
targets = prometheus.exporter.unix.${exporterLabel}.targets
forward_to = [prometheus.relabel.${relabelLabel}.receiver]
job_name = "${escapeString(jobName)}"
scrape_interval = "${escapeString(scrapeInterval)}"
}`);
// Force job label to pipeline name (built-in exporters override job_name)
builder.addBlock(`prometheus.relabel "${relabelLabel}" {
forward_to = [prometheus.remote_write.${writeLabel}.receiver]
rule {
target_label = "job"
replacement = "${escapeString(jobName)}"
}
}`);
builder.addBlock(`prometheus.remote_write "${writeLabel}" {
endpoint {
url = "${escapeString(targets.prometheusRemoteWriteUrl)}"
}
}`);
return builder.build(pipelineId, "node-exporter", "node-exporter");
},
sampleQueries(_params, jobName) {
return {
cpuUsage: `100 - (avg by(instance) (rate(node_cpu_seconds_total{job="${jobName}",mode="idle"}[5m])) * 100)`,
memoryUsage: `(1 - node_memory_MemAvailable_bytes{job="${jobName}"} / node_memory_MemTotal_bytes{job="${jobName}"}) * 100`,
diskUsage: `(1 - node_filesystem_avail_bytes{job="${jobName}",mountpoint="/"} / node_filesystem_size_bytes{job="${jobName}",mountpoint="/"}) * 100`,
};
},
componentIds(pipelineId) {
return [
`prometheus.exporter.unix.${componentLabel(pipelineId, "unix")}`,
`prometheus.scrape.${componentLabel(pipelineId, "scrape")}`,
`prometheus.relabel.${componentLabel(pipelineId, "relabel")}`,
`prometheus.remote_write.${componentLabel(pipelineId, "write")}`,
];
},
};
export default recipe;