UNPKG

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

118 lines (115 loc) 4.81 kB
/** * Recipe: service-graph * * Generates service dependency graph metrics from traces using the OTel * servicegraph connector. Dual-output: metrics to Prometheus, traces to Tempo. * * Generated Alloy pipeline: * otelcol.receiver.otlp → otelcol.processor.batch → { * otelcol.connector.servicegraph → otelcol.exporter.otlphttp (metrics) * otelcol.exporter.otlp (traces) * } */ import { AlloyConfigBuilder, componentLabel, escapeString, renderValue } from "../../config-builder.js"; import { deriveOtlpMetricsUrl } from "./_shared.js"; const recipe = { name: "service-graph", category: "traces", signal: "traces", summary: "Generate service dependency graph metrics from traces via servicegraph connector", dashboardTemplate: "metric-explorer", credentialParams: [], requiredParams: [], optionalParams: [ { name: "dimensions", type: "string[]", description: "Span attributes to include as metric dimensions", default: ["service.name", "http.method"] }, { name: "storeMaxItems", type: "number", description: "Max items in the span pairing store", default: 5000 }, { name: "storeTtl", type: "string", description: "TTL for span pairing entries", default: "30s" }, { name: "metricsFlushInterval", type: "string", description: "How often to flush generated metrics", default: "10s" }, { name: "grpcPort", type: "number", description: "OTLP gRPC listen port", default: 4317 }, { name: "httpPort", type: "number", description: "OTLP HTTP listen port", default: 4318 }, ], generateConfig(pipelineId, params, targets, _pipelineName) { const dimensions = params.dimensions ?? ["service.name", "http.method"]; const storeMaxItems = params.storeMaxItems ?? 5000; const storeTtl = params.storeTtl || "30s"; const flushInterval = params.metricsFlushInterval || "10s"; const grpcPort = params.grpcPort ?? 4317; const httpPort = params.httpPort ?? 4318; const recvLabel = componentLabel(pipelineId, "otlp"); const batchLabel = componentLabel(pipelineId, "batch"); const connLabel = componentLabel(pipelineId, "servicegraph"); const metricsExpLabel = componentLabel(pipelineId, "metrics_export"); const tracesExpLabel = componentLabel(pipelineId, "traces_export"); const builder = new AlloyConfigBuilder(); builder.addBlock(`otelcol.receiver.otlp "${recvLabel}" { grpc { endpoint = "0.0.0.0:${grpcPort}" } http { endpoint = "0.0.0.0:${httpPort}" } output { traces = [otelcol.processor.batch.${batchLabel}.input] } }`); builder.addBlock(`otelcol.processor.batch "${batchLabel}" { output { traces = [ otelcol.connector.servicegraph.${connLabel}.input, otelcol.exporter.otlp.${tracesExpLabel}.input, ] } }`); const dimensionList = renderValue(dimensions); builder.addBlock(`otelcol.connector.servicegraph "${connLabel}" { metrics_flush_interval = "${escapeString(flushInterval)}" dimensions = [${dimensionList}] store { max_items = ${storeMaxItems} ttl = "${escapeString(storeTtl)}" } output { metrics = [otelcol.exporter.otlphttp.${metricsExpLabel}.input] } }`); // Derive OTLP metrics URL from remote_write URL const metricsOtlpUrl = deriveOtlpMetricsUrl(targets.prometheusRemoteWriteUrl); builder.addBlock(`otelcol.exporter.otlphttp "${metricsExpLabel}" { client { endpoint = "${escapeString(metricsOtlpUrl)}" tls { insecure = true } } }`); builder.addBlock(`otelcol.exporter.otlp "${tracesExpLabel}" { client { endpoint = "${escapeString(targets.otlpEndpoint)}" tls { insecure = true } } }`); return builder.build(pipelineId, "service-graph", "service-graph"); }, sampleQueries(_params, _jobName) { return { requestTotal: 'traces_service_graph_request_total', requestDuration: 'histogram_quantile(0.95, sum(rate(traces_service_graph_request_server_seconds_bucket[5m])) by (le))', traces: '{ resource.service.name =~ ".+" }', }; }, componentIds(pipelineId) { return [ `otelcol.receiver.otlp.${componentLabel(pipelineId, "otlp")}`, `otelcol.processor.batch.${componentLabel(pipelineId, "batch")}`, `otelcol.connector.servicegraph.${componentLabel(pipelineId, "servicegraph")}`, `otelcol.exporter.otlphttp.${componentLabel(pipelineId, "metrics_export")}`, `otelcol.exporter.otlp.${componentLabel(pipelineId, "traces_export")}`, ]; }, boundPorts(params) { return [Number(params.grpcPort), Number(params.httpPort)]; }, }; export default recipe;