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
81 lines (79 loc) • 3.27 kB
JavaScript
import { AlloyConfigBuilder, componentLabel, escapeString, renderValue } from "../../config-builder.js";
import { credentialEnvVar } from "../types.js";
import { buildProcessBlock, extractProcessingParams, PROCESSING_OPTIONAL_PARAMS } from "./_process-builder.js";
const recipe = {
name: "kafka-logs",
category: "logs",
signal: "logs",
summary: "Consume logs from Apache Kafka topics with optional JSON/label processing",
dashboardTemplate: null,
credentialParams: ["kafkaAuth"],
requiredParams: [
{ name: "brokers", type: "string[]", description: "Kafka broker addresses", example: "kafka:9092" },
{ name: "topics", type: "string[]", description: "Kafka topics to consume", example: "app-logs" },
],
optionalParams: [
{ name: "consumerGroup", type: "string", description: "Kafka consumer group ID", default: "alloy" },
{ name: "kafkaAuth", type: "string", description: "SASL credentials (user:password)", sensitive: true },
...PROCESSING_OPTIONAL_PARAMS,
],
generateConfig(pipelineId, params, targets, pipelineName) {
const brokers = params.brokers;
const topics = params.topics;
const consumerGroup = params.consumerGroup || "alloy";
const kafkaAuth = params.kafkaAuth;
const srcLabel = componentLabel(pipelineId, "kafka");
const writeLabel = componentLabel(pipelineId, "write");
const builder = new AlloyConfigBuilder();
const processing = buildProcessBlock(pipelineId, extractProcessingParams(params), `loki.write.${writeLabel}.receiver`);
const forwardTo = processing
? processing.receiverRef
: `loki.write.${writeLabel}.receiver`;
const brokerList = renderValue(brokers);
const topicList = renderValue(topics);
let srcBlock = `loki.source.kafka "${srcLabel}" {
brokers = [${brokerList}]
topics = [${topicList}]
consumer_group = "${escapeString(consumerGroup)}"
forward_to = [${forwardTo}]
labels = { source = "kafka" }`;
if (kafkaAuth) {
const userEnv = credentialEnvVar("kafka-logs", pipelineName, "kafkaAuth_user");
const passEnv = credentialEnvVar("kafka-logs", pipelineName, "kafkaAuth_pass");
srcBlock += `
authentication {
type = "sasl"
sasl {
mechanism = "PLAIN"
username = sys.env("${userEnv}")
password = sys.env("${passEnv}")
}
}`;
}
srcBlock += "\n}";
builder.addBlock(srcBlock);
if (processing) {
builder.addBlock(processing.block);
}
builder.addBlock(`loki.write "${writeLabel}" {
endpoint {
url = "${escapeString(targets.lokiWriteUrl)}"
}
}`);
return builder.build(pipelineId, "kafka-logs", "kafka-logs");
},
sampleQueries() {
return {
recentLogs: '{source="kafka"}',
errorLogs: '{source="kafka"} |= "error"',
logVolume: 'rate({source="kafka"}[5m])',
};
},
componentIds(pipelineId) {
return [
`loki.source.kafka.${componentLabel(pipelineId, "kafka")}`,
`loki.write.${componentLabel(pipelineId, "write")}`,
];
},
};
export default recipe;