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

568 lines (436 loc) 12.9 kB
# Alloy Component Reference — Escape Hatch Companion When no recipe fits, compose raw Alloy configs using these component patterns. Use `alloy_pipeline` with `config` param + optional `sampleQueries` for data verification. ## Table of Contents - [Log Sources](#log-sources) - [Log Processing](#log-processing) - [Metrics Exporters](#metrics-exporters) - [OTel Processors](#otel-processors) - [OTel Connectors](#otel-connectors) - [Profiling](#profiling) - [Frontend](#frontend) - [Wiring Patterns](#wiring-patterns) --- ## Log Sources ### loki.source.gelf — GELF UDP Log Source Receives GELF (Graylog Extended Log Format) logs over UDP. Common with Graylog, Docker GELF driver. ```alloy loki.source.gelf "my_gelf" { forward_to = [loki.write.default.receiver] } ``` Default: listens on `0.0.0.0:12201` (UDP). Override with `use_incoming_timestamp = true`. Labels: Auto-extracts `__gelf_message_host`, `__gelf_message_level`, `__gelf_message_facility`. Use `loki.relabel` to promote `__gelf_*` labels. **Sample queries**: `{source="gelf"}`, `{source="gelf"} |= "error"` ### loki.source.api — Loki Push API Endpoint Accepts logs via Loki-compatible HTTP push API. Use for centralized log gateways, TCP JSON ingestion. ```alloy loki.source.api "push" { http { listen_address = "0.0.0.0" listen_port = 3500 } forward_to = [loki.process.parse.receiver] } ``` **Sample queries**: `{source="push-api"}`, `rate({source="push-api"}[5m])` ### loki.source.kafka — Kafka Log Consumer Consumes log messages from Apache Kafka topics. ```alloy loki.source.kafka "logs" { brokers = ["kafka:9092"] topics = ["app-logs"] consumer_group = "alloy" forward_to = [loki.process.parse.receiver] } ``` Authentication: Add `authentication { type = "sasl" ... }` block for SASL/SCRAM. **Sample queries**: `{source="kafka"}`, `{source="kafka", topic="app-logs"}` ### loki.source.windowsevent — Windows Event Logs Collects Windows Event Log entries. Windows-only. ```alloy loki.source.windowsevent "events" { eventlog_name = "Application" forward_to = [loki.process.parse.receiver] } ``` Common event logs: `"Application"`, `"System"`, `"Security"`. **Sample queries**: `{source="windowsevent"}`, `{source="windowsevent"} |= "error"` --- ## Log Processing Insert `loki.process` between source and `loki.write` for parsing, enrichment, and routing. ### stage.json — JSON Field Extraction ```alloy loki.process "parse" { stage.json { expressions = { "timestamp" = "", "level" = "", "message" = "", "request_id" = "context.request_id", } } forward_to = [loki.write.default.receiver] } ``` Empty string `""` extracts the top-level key matching the name. Dotted paths extract nested fields. ### stage.labels — Promote Fields to Labels ```alloy stage.labels { values = { "level" = "", "service" = "", } } ``` Promotes extracted fields to Loki index labels. Use sparingly — high-cardinality labels hurt performance. ### stage.structured_metadata — High-Cardinality Fields ```alloy stage.structured_metadata { values = { "request_id" = "", "user_id" = "", } } ``` For high-cardinality data. Queryable via `| request_id="abc"` but not indexed as labels. ### stage.timestamp — Parse Log Timestamps ```alloy stage.timestamp { source = "timestamp" format = "RFC3339" } ``` Formats: `"RFC3339"`, `"RFC3339Nano"`, `"Unix"`, `"UnixMs"`, or Go time layout strings. ### stage.static_labels — Add Fixed Labels ```alloy stage.static_labels { values = { "environment" = "production", "service_name" = "my-app", } } ``` ### stage.output — Set Log Line Content ```alloy stage.output { source = "message" } ``` Replaces the log line with the extracted `message` field. ### stage.regex — Regex Extraction ```alloy stage.regex { expression = "^(?P<timestamp>\\S+) (?P<level>\\w+) (?P<message>.*)$" } ``` Named capture groups become available for subsequent stages. ### stage.match — Conditional Processing ```alloy stage.match { selector = '{app="frontend"}' stage.json { expressions = { "url" = "" } } stage.labels { values = { "url" = "" } } } ``` Apply stages only to logs matching the LogQL selector. ### stage.tenant — Multi-Tenant Routing ```alloy stage.tenant { source = "tenant_id" } ``` Routes logs to different Loki tenants based on extracted field. ### loki.secretfilter — Secret Redaction ```alloy loki.secretfilter "redact" { forward_to = [loki.write.default.receiver] } ``` Uses built-in Gitleaks patterns to redact secrets. Optional: `redact_with = "<REDACTED:$SECRET_NAME>"`, `types = "all"`. ### Full Processing Pipeline Example ```alloy loki.source.api "push" { http { listen_port = 3500 } forward_to = [loki.process.parse.receiver] } loki.process "parse" { stage.json { expressions = { "timestamp" = "", "level" = "", "message" = "", "user_id" = "" } } stage.timestamp { source = "timestamp" format = "RFC3339" } stage.labels { values = { "level" = "" } } stage.structured_metadata { values = { "user_id" = "" } } stage.output { source = "message" } forward_to = [loki.write.default.receiver] } loki.write "default" { endpoint { url = "http://loki:3100/loki/api/v1/push" } } ``` --- ## Metrics Exporters All follow: `prometheus.exporter.X → prometheus.scrape → prometheus.remote_write`. ### prometheus.exporter.blackbox — Synthetic HTTP Probing ```alloy prometheus.exporter.blackbox "probes" { config = "{ modules: { http_2xx: { prober: http, timeout: 5s } } }" target { name = "web" address = "http://myapp:8080" module = "http_2xx" } } prometheus.scrape "blackbox" { targets = prometheus.exporter.blackbox.probes.targets forward_to = [prometheus.remote_write.default.receiver] } ``` Modules: `http_2xx` (HTTP), `tcp_connect` (TCP), `icmp` (ICMP/ping). **Sample queries**: `probe_success{instance="..."}`, `probe_http_duration_seconds`, `probe_http_status_code` ### prometheus.exporter.memcached — Memcached Metrics ```alloy prometheus.exporter.memcached "cache" { address = "memcached:11211" } prometheus.scrape "memcached" { targets = prometheus.exporter.memcached.cache.targets forward_to = [prometheus.remote_write.default.receiver] } ``` **Sample queries**: `memcached_up`, `memcached_current_bytes`, `memcached_current_connections` ### prometheus.exporter.snmp — SNMP Device Monitoring ```alloy prometheus.exporter.snmp "devices" { config_file = "/etc/alloy/snmp.yml" target "switch" { address = "192.168.1.1" module = "if_mib" } } ``` Requires external `snmp.yml` config file (MIB definitions). **Sample queries**: `ifOperStatus`, `ifInOctets`, `ifOutOctets` ### prometheus.exporter.windows — Windows System Metrics ```alloy prometheus.exporter.windows "system" { enabled_collectors = ["cpu", "cs", "logical_disk", "net", "os", "system"] } ``` Windows-only. Collectors: `cpu`, `cs`, `logical_disk`, `memory`, `net`, `os`, `process`, `system`. **Sample queries**: `windows_cpu_time_total`, `windows_logical_disk_free_bytes` ### prometheus.exporter.self — Alloy Self-Monitoring ```alloy prometheus.exporter.self "alloy" {} prometheus.scrape "self" { targets = prometheus.exporter.self.alloy.targets forward_to = [prometheus.remote_write.default.receiver] } ``` **Sample queries**: `alloy_build_info`, `rate(alloy_component_evaluation_slow_seconds_count[5m])`, `alloy_component_controller_running_components` --- ## OTel Processors ### otelcol.processor.tail_sampling — Trace Sampling Policies ```alloy otelcol.processor.tail_sampling "smart" { decision_wait = "10s" num_traces = 100 // Always keep error traces policy { name = "errors" type = "status_code" status_code { status_codes = ["ERROR"] } } // Keep slow traces (>5s) policy { name = "latency" type = "latency" latency { threshold_ms = 5000 } } // Drop health checks policy { name = "drop-health" type = "string_attribute" string_attribute { key = "http.url" values = ["/health", "/metrics", "/ready"] invert_match = true } } // Sample 10% of remaining policy { name = "probabilistic" type = "probabilistic" probabilistic { sampling_percentage = 10 } } output { traces = [otelcol.processor.batch.default.input] } } ``` Policy types: `status_code`, `latency`, `probabilistic`, `string_attribute`, `numeric_attribute`, `always_sample`, `rate_limiting`. ### otelcol.processor.transform — Attribute Transformation ```alloy otelcol.processor.transform "enrich" { metric_statements { context = "datapoint" statements = [ "set(attributes[\"environment\"], \"production\")", ] } output { metrics = [otelcol.exporter.otlphttp.default.input] } } ``` Uses OTTL (OpenTelemetry Transformation Language). Contexts: `resource`, `scope`, `span`, `spanevent`, `metric`, `datapoint`, `log`. ### otelcol.processor.resourcedetection — Auto-Detect Host Metadata ```alloy otelcol.processor.resourcedetection "env" { detectors = ["env", "system"] system { hostname_sources = ["os"] } output { traces = [otelcol.processor.batch.default.input] } } ``` Detectors: `env`, `system`, `docker`, `gcp`, `aws`, `azure`. --- ## OTel Connectors Connectors consume one signal type and produce another. ### otelcol.connector.spanmetrics — RED Metrics from Traces ```alloy otelcol.connector.spanmetrics "red" { histogram { explicit {} } dimension { name = "http.method" } dimension { name = "http.status_code" } metrics_flush_interval = "5s" output { metrics = [otelcol.exporter.otlphttp.prometheus.input] } } ``` Produces: `traces_spanmetrics_calls_total`, `traces_spanmetrics_duration_milliseconds_bucket`. Wire: `batch.output.traces = [spanmetrics.input, exporter.input]` (dual output). ### otelcol.connector.servicegraph — Service Dependency Graphs ```alloy otelcol.connector.servicegraph "graph" { metrics_flush_interval = "10s" dimensions = ["service.name", "http.method"] store { max_items = 5000 ttl = "30s" } output { metrics = [otelcol.exporter.otlphttp.prometheus.input] } } ``` Produces: `traces_service_graph_request_total`, `traces_service_graph_request_server_seconds_bucket`. Same dual-output wiring as spanmetrics. ### otelcol.connector.count — Count Signals ```alloy otelcol.connector.count "req" { spans { "request.count" { description = "Total request count" } } output { metrics = [otelcol.exporter.otlphttp.prometheus.input] } } ``` Derives count metrics from traces, logs, or spans. --- ## Profiling ### pyroscope.scrape + pyroscope.write — Continuous Profiling ```alloy pyroscope.scrape "profiles" { targets = [ { "__address__" = "myapp:6060", "service_name" = "myapp" }, ] profiling_config { profile.process_cpu { enabled = true } profile.memory { enabled = true } profile.goroutine { enabled = true } } forward_to = [pyroscope.write.default.receiver] } pyroscope.write "default" { endpoint { url = "http://pyroscope:4040" } } ``` Profiles: `process_cpu`, `memory`, `goroutine`, `mutex`, `block`. Go apps expose at `:6060/debug/pprof`. --- ## Frontend ### faro.receiver — Browser RUM/Web Vitals ```alloy faro.receiver "frontend" { server { listen_address = "0.0.0.0" listen_port = 12347 cors_allowed_origins = ["*"] } output { logs = [loki.write.default.receiver] } } ``` Collects frontend telemetry via Grafana Faro SDK. Signals: logs, traces, measurements (web vitals). --- ## Wiring Patterns ### Source → Write (simplest) ``` loki.source.X → loki.write prometheus.exporter.X → prometheus.scrape → prometheus.remote_write ``` ### Source → Process → Write (log enrichment) ``` loki.source.X → loki.process → loki.write ``` ### Source → Multiple Destinations (fan-out) ``` otelcol.receiver.otlp → otelcol.processor.batch → [ otelcol.connector.spanmetrics (→ metrics export), otelcol.exporter.otlp (→ traces export) ] ``` ### Discovery → Relabel → Scrape → Write (dynamic targets) ``` discovery.docker → discovery.relabel → loki.source.docker → loki.write ``` ### Common `prometheus.remote_write` + `loki.write` blocks Always end metrics pipelines with: ```alloy prometheus.remote_write "default" { endpoint { url = "PROMETHEUS_REMOTE_WRITE_URL" } } ``` Always end log pipelines with: ```alloy loki.write "default" { endpoint { url = "LOKI_WRITE_URL" } } ``` Replace URLs with the values from your LGTM stack config (`alloy.lgtm` settings).