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

395 lines (279 loc) 18.5 kB
# Alloy Pipeline Recipes — Full Catalog The `alloy_pipeline` tool uses recipes to create data collection pipelines. Each recipe generates a complete, self-contained Alloy config file. ## Table of Contents - [Recipe Catalog](#recipe-catalog) - [Recipe Details](#recipe-details) - [Log Processing Params](#log-processing-params) - [Credential Handling](#credential-handling) - [Troubleshooting](#troubleshooting) - [Export Targets](#export-targets) ## Recipe Catalog ### Metrics Recipes (11) | Recipe | Required Params | Credential Params | Dashboard Template | |--------|----------------|-------------------|-------------------| | `scrape-endpoint` | `url` (HTTP endpoint) | basicAuth, bearerToken | metric-explorer | | `node-exporter` | (none) | (none) | metric-explorer | | `postgres-exporter` | `connectionString` | connectionString | metric-explorer | | `mysql-exporter` | `connectionString` | connectionString | metric-explorer | | `redis-exporter` | `redisUrl` | password | metric-explorer | | `mongodb-exporter` | `mongodbUri` | mongodbUri | metric-explorer | | `kubernetes-pods` | (none) | (none) | multi-kpi | | `kubernetes-services` | (none) | (none) | multi-kpi | | `blackbox-exporter` | `targets` (array) | (none) | metric-explorer | | `memcached-exporter` | `memcachedAddress` | (none) | metric-explorer | | `self-monitoring` | (none) | (none) | metric-explorer | ### Log Recipes (10) All log recipes support optional [processing params](#log-processing-params) for JSON parsing, label promotion, structured metadata, multi-tenant routing, and more. | Recipe | Required Params | Source | Dashboard Template | |--------|----------------|--------|-------------------| | `docker-logs` | (none) | Docker socket (opt: containerNames, excludeContainers) | (none — use grafana_query_logs) | | `file-logs` | `paths` (glob array) | Local files | (none) | | `syslog` | (none) | TCP/UDP listener (opt: protocol, listenAddress) | (none) | | `kubernetes-logs` | (none) | K8s API | (none) | | `journal-logs` | (none) | systemd journal | (none) | | `loki-push-api` | (none) | HTTP push API (opt: listenPort, listenAddress) | (none) | | `kafka-logs` | `brokers`, `topics` | Apache Kafka (opt: consumerGroup) | (none) | | `secret-filter-logs` | `paths` (glob array) | Local files + secret redaction | (none) | | `faro-frontend` | (none) | Grafana Faro Web SDK (opt: listenPort, corsAllowedOrigins) | (none) | | `gelf-logs` | (none) | GELF over UDP (opt: listenAddress, relabelHost/Level/Facility) | (none) | ### Trace Recipes (4) | Recipe | Required Params | What It Does | Dashboard Template | |--------|----------------|-------------|-------------------| | `otlp-receiver` | (none) | Receive OTLP traces/metrics/logs | (none — use grafana_query_traces) | | `application-traces` | (none) | Traces + enrichment + sampling (simple or multi-policy) | (none) | | `span-metrics` | (none) | RED metrics from traces via spanmetrics connector | metric-explorer | | `service-graph` | (none) | Service dependency graph metrics from traces | metric-explorer | ### Infrastructure Recipes (3) | Recipe | Required Params | What It Monitors | Dashboard Template | |--------|----------------|-----------------|-------------------| | `docker-metrics` | (none) | Container CPU/memory/network | metric-explorer | | `elasticsearch-exporter` | `elasticsearchUrl` | ES cluster health, indices, shards | metric-explorer | | `kafka-exporter` | `kafkaBrokers` (array) | Brokers, topics, consumer lag | metric-explorer | ### Profiling Recipes (1) | Recipe | Required Params | What It Does | Dashboard Template | |--------|----------------|-------------|-------------------| | `continuous-profiling` | `targets` (array of {address, serviceName}) | Pyroscope continuous profiling (CPU, memory, goroutine, mutex, block) | (none) | ## Recipe Details ### scrape-endpoint Scrapes any HTTP endpoint exposing Prometheus metrics. **Required**: `url` — full URL (e.g., `http://myapp:8080/metrics`) **Optional**: `scrapeInterval` (default: 15s), `metricsPath` (default: /metrics), `jobName`, `basicAuth`, `bearerToken`, `tlsInsecure` **Sample queries**: `up{job="..."}`, `scrape_samples_scraped{job="..."}` ### postgres-exporter PostgreSQL metrics via Alloy's built-in exporter. **Required**: `connectionString` — Postgres URI (e.g., `postgres://user:pass@host:5432/db`) **Optional**: `scrapeInterval` **Sample queries**: `pg_up{job="..."}`, `pg_stat_activity_count{job="..."}`, `rate(pg_stat_database_deadlocks{job="..."}[5m])` ### node-exporter System metrics (CPU, memory, disk, network) via Alloy's built-in Unix exporter. No external binary needed. **No required params.** **Optional**: `scrapeInterval` **Sample queries**: - CPU: `100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)` - Memory: `(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100` - Disk: `(1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100` ### docker-logs Collects logs from Docker containers via the Docker socket. Supports container name filtering. **No required params.** **Optional**: `containerNames` (string[] — keep only these containers), `excludeContainers` (string[] — drop these containers). When either is specified, a `discovery.relabel` block filters by `__meta_docker_container_name`. **Labels**: `source="docker"` added to all log entries. **Sample LogQL**: `{source="docker"}`, `{source="docker"} |= "error"`, `rate({source="docker"}[5m])` ### syslog Receives syslog messages via TCP or UDP. **No required params.** **Optional**: `listenAddress` (default: `0.0.0.0:1514`), `protocol` (default: `tcp` — set to `udp` for UDP syslog). **Labels**: `source="syslog"`. **Sample LogQL**: `{source="syslog"}`, `{source="syslog"} |= "error"` ### otlp-receiver Receives OTLP data (metrics, logs, traces) via gRPC and HTTP. Routes all signals through batching to the LGTM stack. **No required params.** **Optional**: `grpcPort` (default: 4317), `httpPort` (default: 4318) **Note**: Binds to `0.0.0.0:{port}` — cannot coexist with `application-traces` on the same default ports. **Sample TraceQL**: `{ resource.service.name =~ ".+" }` ### application-traces Receives traces with service name enrichment, batching, and sampling. Two sampling modes: **Simple mode**: `sampleRate` (0.0–1.0, default: 1.0). Probabilistic sampling — "keep X% of all traces." **Advanced mode**: `samplingPolicies` — multi-policy tail sampling for production cost control. Keep errors, keep slow traces, filter health checks, rate-limit the rest. Takes precedence over `sampleRate`. **No required params.** **Optional**: `environment` (default: `production`), `sampleRate`, `samplingPolicies` (array), `decisionWait` (default: `10s`), `numTraces` (default: `100`). **Note**: Uses same default ports as `otlp-receiver` (4317/4318) — cannot coexist with it on defaults. **samplingPolicies** — Array of policy objects. Policies are OR-ed: trace is kept if ANY policy matches. Policy types: - `status_code` — `{ name, type: "status_code", statusCodes: ["ERROR"] }` - `latency` — `{ name, type: "latency", thresholdMs: 5000 }` - `probabilistic` — `{ name, type: "probabilistic", samplingPercentage: 10 }` - `string_attribute` — `{ name, type: "string_attribute", key: "http.url", values: ["/health"], invertMatch: true }` - `numeric_attribute` — `{ name, type: "numeric_attribute", key: "score", minValue: 70, maxValue: 100 }` **Example** — Keep all errors + slow traces, drop health checks, sample 10% of the rest: ```json { "recipe": "application-traces", "params": { "environment": "production", "samplingPolicies": [ { "name": "keep-errors", "type": "status_code", "statusCodes": ["ERROR"] }, { "name": "keep-slow", "type": "latency", "thresholdMs": 5000 }, { "name": "drop-health", "type": "string_attribute", "key": "http.url", "values": ["/health", "/ready"], "invertMatch": true }, { "name": "sample-rest", "type": "probabilistic", "samplingPercentage": 10 } ] } } ``` **Sample TraceQL**: `{ resource.deployment.environment = "production" }`, `{ status = error }`, `{ duration > 5s }` ### blackbox-exporter Synthetic HTTP/TCP/ICMP probing for endpoint availability. **Required**: `targets` — array of `[{ name, address, module? }]` (e.g., `[{ "name": "web", "address": "http://myapp:8080" }]`) **Optional**: `modules` (inline YAML blackbox config, default: `http_2xx`), `scrapeInterval` **Sample queries**: `probe_success{job="..."}`, `probe_http_duration_seconds{job="..."}`, `probe_http_status_code{job="..."}` ### memcached-exporter Memcached metrics — connections, memory, items, evictions. **Required**: `memcachedAddress` (e.g., `memcached:11211`) **Optional**: `scrapeInterval` **Sample queries**: `memcached_up{job="..."}`, `memcached_current_bytes{job="..."}`, `memcached_current_connections{job="..."}` ### self-monitoring Monitor Alloy itself — component health, evaluation latency, resource usage. **No required params.** **Optional**: `scrapeInterval` **Sample queries**: `alloy_build_info{job="..."}`, `rate(alloy_component_evaluation_slow_seconds_count{job="..."}[5m])`, `alloy_component_controller_running_components{job="..."}` ### loki-push-api Accept logs via Loki-compatible HTTP push API. Covers centralized log gateways and TCP JSON ingestion. **No required params.** **Optional**: `listenPort` (default: 3500), `listenAddress`, + [processing params](#log-processing-params) **Sample LogQL**: `{source="push-api"}`, `rate({source="push-api"}[5m])` ### kafka-logs Consume log messages from Apache Kafka topics. **Required**: `brokers` (string array), `topics` (string array) **Optional**: `consumerGroup` (default: `alloy`), `kafkaAuth` (SASL credentials), + [processing params](#log-processing-params) **Sample LogQL**: `{source="kafka"}`, `{source="kafka"} |= "error"` ### secret-filter-logs Tail log files with automatic secret redaction using built-in Gitleaks patterns. **Required**: `paths` (glob array) **Optional**: `redactWith` (default: `<REDACTED:$SECRET_NAME>`) **Sample LogQL**: `{source="file"} |= "REDACTED"` ### span-metrics Generate RED (Request, Error, Duration) metrics from traces via the spanmetrics connector. Dual-output: traces → Tempo, metrics → Prometheus. **No required params.** **Optional**: `dimensions` (default: `["http.method", "http.status_code"]`), `metricsFlushInterval` (default: `5s`), `grpcPort`, `httpPort` **Sample PromQL**: `sum(rate(traces_spanmetrics_calls_total[5m]))`, `histogram_quantile(0.95, sum(rate(traces_spanmetrics_duration_milliseconds_bucket[5m])) by (le))` **Sample TraceQL**: `{ resource.service.name =~ ".+" }` ### service-graph Generate service dependency graph metrics from traces via the servicegraph connector. Same dual-output as span-metrics. **No required params.** **Optional**: `dimensions` (default: `["service.name", "http.method"]`), `storeMaxItems` (default: 5000), `storeTtl` (default: `30s`), `metricsFlushInterval`, `grpcPort`, `httpPort` **Sample PromQL**: `traces_service_graph_request_total`, `histogram_quantile(0.95, sum(rate(traces_service_graph_request_server_seconds_bucket[5m])) by (le))` ### faro-frontend Receive frontend telemetry from the Grafana Faro Web SDK — browser errors, performance, web vitals, sessions. **No required params.** **Optional**: `listenPort` (default: 12347), `listenAddress` (default: `0.0.0.0`), `corsAllowedOrigins` (default: `["*"]`) **Sample LogQL**: `{service_name="faro-web-sdk"}`, `{service_name="faro-web-sdk"} |= "error"` ### gelf-logs Receive GELF (Graylog Extended Log Format) logs over UDP with automatic metadata relabeling. **No required params.** **Optional**: `listenAddress` (default: `0.0.0.0:12201`), `relabelHost` (default: true), `relabelLevel` (default: true), `relabelFacility` (default: true) **Sample LogQL**: `{source="gelf"}`, `{host=~".+"}`, `{level=~"3|4"}` ### continuous-profiling Continuous profiling via Pyroscope — scrape pprof profiles from Go applications. **Required**: `targets` — array of `[{ address, serviceName }]` (e.g., `[{ "address": "myapp:6060", "serviceName": "my-app" }]`) **Optional**: `scrapeInterval` (default: `15s`), `profileTypes` (default: `["cpu", "memory", "goroutine", "mutex", "block"]`), `pyroscopeUrl` **Sample Pyroscope queries**: `process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name="my-app"}`, `memory:alloc_objects:count:space:bytes{service_name="my-app"}` ## Log Processing Params All log recipes (docker-logs, file-logs, syslog, kubernetes-logs, journal-logs, loki-push-api, kafka-logs, secret-filter-logs) accept these optional processing params. When any are provided, a `loki.process` block is automatically inserted between the source and `loki.write`. | Param | Type | What It Does | |-------|------|-------------| | `jsonExpressions` | object | `stage.json` — Extract fields from JSON. Keys=output names, values=JSON paths ("" = top-level key) | | `regexExpression` | string | `stage.regex` — Extract fields via regex with named capture groups | | `timestampSource` | string | `stage.timestamp` — Parse timestamp from this field (use with `timestampFormat`) | | `timestampFormat` | string | Timestamp format: `RFC3339`, `RFC3339Nano`, `Unix`, `UnixMs`, Go layout | | `labelFields` | object | `stage.labels` — Promote fields to Loki index labels (low-cardinality only) | | `structuredMetadata` | object | `stage.structured_metadata` — Store high-cardinality fields as metadata | | `staticLabels` | object | `stage.static_labels` — Add fixed labels to all entries | | `tenantValue` | string | `stage.tenant` — Static Loki tenant ID (X-Scope-OrgID). Routes all logs to this tenant | | `tenantSource` | string | `stage.tenant` — Dynamic tenant from extracted field (e.g., `"org_id"`) | | `matchRoutes` | object[] | `stage.match` — Conditional multi-tenant routing by label selector | | `outputSource` | string | `stage.output` — Replace log line with extracted field value | **Example**: Parse JSON logs, extract timestamp, promote `level` to label, store `request_id` as metadata: ```json { "recipe": "file-logs", "params": { "paths": ["/var/log/app/*.log"], "jsonExpressions": { "timestamp": "", "level": "", "message": "", "request_id": "ctx.rid" }, "timestampSource": "timestamp", "timestampFormat": "RFC3339", "labelFields": { "level": "" }, "structuredMetadata": { "request_id": "" }, "outputSource": "message" } } ``` **Example**: Multi-tenant routing — route logs to different Loki tenants by environment: ```json { "recipe": "loki-push-api", "params": { "jsonExpressions": { "env": "" }, "labelFields": { "env": "" }, "matchRoutes": [ { "selector": "{env=\"prod\"}", "tenantValue": "prod-tenant" }, { "selector": "{env=\"staging\"}", "tenantValue": "staging-tenant" } ] } } ``` ## Credential Handling Recipes with `credentialParams` generate Alloy config using `sys.env()` references. Secrets are never written to config files. **Env var convention**: `ALLOY_{RECIPE}_{PIPELINE_NAME}_{PARAM}` (all uppercase, hyphens → underscores) Example: `postgres-exporter` pipeline named `analytics-db` → env var `ALLOY_POSTGRES_EXPORTER_ANALYTICS_DB_CONNECTIONSTRING` ### Two-Phase Credential Lifecycle Credential recipes use a two-phase creation flow: 1. **Create**: Config is written to disk. Alloy attempts to reload. 2. **If env vars aren't set**: Alloy reload fails, but the config file stays. Pipeline enters `pending_credentials` status. The response includes `envVarsRequired` with exact env var names. > **Blast radius**: Alloy reload is atomic — a single failed config blocks reload for ALL managed pipelines, not just the new one. Existing healthy pipelines continue running on their last good config, but any subsequent create/update/delete operations will fail until the env vars are set or the broken pipeline is deleted. 3. **User sets env vars** where Alloy runs (shell env, systemd unit, Docker env, K8s secret). 4. **Verify**: Use action `status` — the pipeline auto-promotes to `active` once Alloy components are healthy. If the env vars are already set when the pipeline is created, the reload succeeds immediately and the pipeline starts in `active` status. ## Troubleshooting ### "pending_credentials" status - The pipeline config is on disk but Alloy can't connect — env vars aren't set yet - Check `envVarsRequired` from the create response for exact var names - Set the env vars where Alloy runs, then verify with action `status` - Pipeline will auto-promote to `active` once components pass health check ### "Alloy not reachable" - Check Alloy is running: `curl http://localhost:12345/-/ready` - Check URL in plugin config: `alloy.url` - Check env var: `ALLOY_URL` ### "Config rejected by Alloy" - The pipeline was automatically rolled back (previous config restored) - Check the `alloyError` field in the response for Alloy's error message - Common: unknown component type, invalid attribute name, syntax error ### "Pipeline status: degraded" - One or more Alloy components are unhealthy - Check `remediation` field in status response - Common: target unreachable (wrong host/port), auth failure, DNS resolution ### "Pipeline status: drift" - The config file was modified or deleted externally - Run `alloy_pipeline` action `diagnose` for details - Fix: delete and recreate the pipeline ### "No data in Grafana" - Check pipeline status first (action `status`) - Check env vars are set (for credential recipes) - Check Alloy has access to the data source (network, permissions) - Check LGTM stack is running (Mimir for metrics, Loki for logs, Tempo for traces) ## Export Targets Recipes need to know where to send data. This is auto-resolved: - **Prometheus remote_write**: from `alloy.lgtm.prometheusRemoteWriteUrl` or default `http://localhost:9009/api/prom/push` - **Loki write**: from `alloy.lgtm.lokiUrl` or default `http://localhost:3100/loki/api/v1/push` - **OTLP**: from `alloy.lgtm.otlpEndpoint` or derived from `otlp.endpoint` config Override these in plugin config when using non-default LGTM endpoints: ```json { "alloy": { "enabled": true, "configDir": "/etc/alloy/config.d", "lgtm": { "prometheusRemoteWriteUrl": "http://mimir:9009/api/prom/push", "lokiUrl": "http://loki:3100/loki/api/v1/push" } } } ```