# OpenTelemetry Collector — ready-to-use KVM / libvirt hypervisor config
# Pairs with: https://linkmesh.io/blog/monitor-kvm-libvirt-opentelemetry/
#
# 1. Install a pinned otelcol-contrib release (see the guide, Step 1).
# 2. Save this file as:  /etc/otelcol-contrib/config.yaml
# 3. Pick ONE exporter section below: self-hosted (default) or Grafana Cloud.
# 4. Install prometheus-libvirt-exporter on the host and let it read the
#    read-only libvirt socket (guide, Step 4):
#        usermod -aG libvirt prometheus-libvirt-exporter
# 5. Let the collector read the journal (guide, Step 5):
#        usermod -aG systemd-journal otelcol-contrib
# 6. Validate, then restart:
#        otelcol-contrib validate --config /etc/otelcol-contrib/config.yaml
#        systemctl restart otelcol-contrib
#
# There is no libvirt receiver in the collector (checked against v0.164.0,
# 2026-11-02) — per-domain metrics come from the exporter scraped below.

receivers:
  # Host basics, with history. On a hypervisor the CPU states that matter most
  # are "wait" (slow storage) and "steal" (overcommit).
  hostmetrics:
    collection_interval: 30s
    scrapers:
      cpu: {}
      memory: {}
      load: {}
      disk: {}
      filesystem: {}       # per-mount usage (% and bytes)
      network: {}
      paging: {}
      # Every running domain is a qemu-system-* process, so this gives per-VM
      # CPU and RSS with no exporter at all. It is also the noisiest scraper
      # here (one series group per process) — drop it if cardinality bites.
      process:
        mute_process_name_error: true
        mute_process_exe_error: true
        mute_process_io_error: true

  # Per-domain and storage-pool metrics from libvirt, via
  # github.com/inovex/prometheus-libvirt-exporter (port 9177, path /metrics).
  # Same host, so loopback is enough and nothing listens on the network.
  prometheus/libvirt:
    config:
      scrape_configs:
        - job_name: libvirt
          scrape_interval: 30s
          static_configs:
            - targets: ["127.0.0.1:9177"]

  # The libvirt journal. List BOTH the monolithic daemon and the modular ones:
  # modern distros ship the modular split (virtqemud et al.) and libvirtd is
  # then a near-silent shim; older hosts are the reverse. A unit that does not
  # exist on a host is simply silent, so one list works for a mixed fleet.
  # NOTE: requires the service user to be in the systemd-journal group (step 5).
  journald:
    units:
      - libvirtd
      - virtqemud
      - virtnetworkd
      - virtstoraged
      - virtlogd          # guest serial console output lands here
    priority: info

processors:
  # Hard memory cap so the collector never competes with your guests for RAM.
  memory_limiter:
    check_interval: 1s
    limit_mib: 256
    spike_limit_mib: 64

  # Stamps host.name on every metric and log line — this becomes the
  # host_name label you filter on in Grafana. Needed in BOTH pipelines.
  resourcedetection/system:
    detectors: [system]
    system:
      hostname_sources: [os]

  # Batches telemetry before export.
  batch: {}

exporters:
  # --- Option A: self-hosted Prometheus + Loki (default) --------------------
  # Prometheus must run with --web.enable-otlp-receiver.
  # Loki 3.x accepts OTLP natively under /otlp.
  otlphttp/prometheus:
    metrics_endpoint: "http://prometheus.example.net:9090/api/v1/otlp/v1/metrics"
  otlphttp/loki:
    endpoint: "http://loki.example.net:3100/otlp"

  # --- Option B: Grafana Cloud ----------------------------------------------
  # Paste your values from Grafana Cloud → Connections → OTLP → "Send data",
  # uncomment, and swap it into both pipelines below.
  #
  # otlphttp/grafana:
  #   endpoint: "https://otlp-gateway-<zone>.grafana.net/otlp"
  #   headers:
  #     Authorization: "Basic <base64 of instanceID:token>"

service:
  pipelines:
    metrics:
      receivers: [hostmetrics, prometheus/libvirt]
      processors: [memory_limiter, resourcedetection/system, batch]
      exporters: [otlphttp/prometheus]       # or: [otlphttp/grafana]
    logs:
      receivers: [journald]
      processors: [memory_limiter, resourcedetection/system, batch]
      exporters: [otlphttp/loki]             # or: [otlphttp/grafana]
