تخطَّ إلى المحتوى

أوامر Grafana Alloy

Grafana Alloy هو موزع OpenTelemetry مرن وغير متحيز لجمع ومعالجة وتصدير بيانات القياسات (المقاييس والسجلات والتتبعات). خليفة Grafana Agent، يستخدم لغة تكوين قائمة على المكونات.

التثبيت

مستودعات حزم Linux

Debian/Ubuntu

sudo mkdir -p /etc/apt/keyrings/
wget -qO - https://apt.grafana.com/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/grafana.gpg
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install alloy

RHEL/CentOS/Fedora

sudo tee /etc/yum.repos.d/grafana.repo << EOF
[grafana]
name=grafana
baseurl=https://rpm.grafana.com
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://rpm.grafana.com/gpg.key
EOF
sudo dnf install alloy

macOS

brew install grafana/grafana/alloy
alloy --version

تحميل البرنامج الثنائي

# تحميل أحدث إصدار
wget https://github.com/grafana/alloy/releases/download/v1.14.0/alloy-v1.14.0-linux-amd64.zip
unzip alloy-v1.14.0-linux-amd64.zip
sudo mv alloy /usr/local/bin/
alloy --version

Docker

docker pull grafana/alloy:latest
docker run -v /path/to/config.alloy:/etc/alloy/config.alloy \
  grafana/alloy:latest run /etc/alloy/config.alloy --server.http.listen-addr=0.0.0.0:12345

Helm Chart

helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm install alloy grafana/alloy --namespace monitoring --create-namespace \
  -f values.yaml

الأوامر الأساسية

الأمرالوصف
alloy run config.alloyتشغيل Alloy مع ملف التكوين المحدد
alloy run config.alloy --server.http.listen-addr=0.0.0.0:12345التشغيل مع عنوان خادم HTTP مخصص لواجهة المستخدم
alloy fmt config.alloyتنسيق والتحقق من ملف التكوين (تشغيل جاف)
alloy fmt -w config.alloyتنسيق ملف التكوين في المكان
alloy tools parse config.alloyتحليل والتحقق من صيغة التكوين
alloy tools lint config.alloyبحث التكوين عن المشاكل
alloy --versionعرض إصدار Alloy
alloy --helpعرض معلومات المساعدة
alloy run --helpعرض خيارات أمر التشغيل

أساسيات التكوين

امتداد الملف والصيغة

يستخدم Alloy امتداد ملف .alloy مع لغة تكوين قائمة على المكونات (مشابهة لـ HCL).

الهيكل الأساسي

// التعليقات تستخدم //

// إنشاء instance مكون: <component_type>.<unique_name> { ... }
prometheus.scrape "example" {
  targets = [{"__address__" = "localhost:9090"}]
  forward_to = [prometheus.remote_write.grafana.receiver]
}

// تصدير البيانات من مكون إلى آخر
prometheus.remote_write "grafana" {
  endpoint {
    url = "https://prometheus.grafana.net/api/prom/push"
    headers = {
      "Authorization" = "Bearer ${GRAFANA_TOKEN}"
    }
  }
}

المتغيرات والأسرار

// متغيرات البيئة
GRAFANA_TOKEN = env("GRAFANA_TOKEN")
PROMETHEUS_URL = env("PROMETHEUS_URL")

// متغيرات محلية
local "my_targets" {
  value = [
    {"__address__" = "localhost:9090"},
    {"__address__" = "localhost:9100"},
  ]
}

// المرجع المتغيرات
prometheus.scrape "nodes" {
  targets = local.my_targets.value
}

كتل الحجج والتصديرات

// معظم المكونات تقبل الحجج
prometheus.scrape "example" {
  targets    = [{"__address__" = "localhost:9090"}]
  scrape_interval = "30s"
  scrape_timeout  = "10s"
  forward_to = [prometheus.remote_write.grafana.receiver]
}

// المكونات تصدر البيانات (مرئية في واجهة المستخدم ضمن التصديرات)
// مثال: prometheus.scrape يصدر scraped_targets و targets

المكونات - المصادر

Prometheus Scrape

prometheus.scrape "kubernetes" {
  targets    = discovery.kubernetes.nodes.targets
  scrape_interval = "30s"
  scrape_timeout  = "10s"
  metrics_path    = "/metrics"
  scheme          = "http"

  forward_to = [prometheus.relabel.drop_internal.receiver]
}

مصدر ملف Loki

loki.source.file "app_logs" {
  targets = [
    {
      __path__ = "/var/log/app/*.log",
      job      = "app",
      env      = "production",
    }
  ]

  forward_to = [loki.relabel.add_labels.receiver]
}

OpenTelemetry Receiver (OTLP)

otelcol.receiver.otlp "default" {
  grpc {
    endpoint = "0.0.0.0:4317"
  }

  http {
    endpoint = "0.0.0.0:4318"
  }

  output {
    traces  = [otelcol.processor.batch.default.input]
    metrics = [otelcol.processor.batch.default.input]
    logs    = [otelcol.processor.batch.default.input]
  }
}

جهاز استقبال Prometheus Remote Write

prometheus.receive_http "example" {
  http {
    address = "0.0.0.0:9009"
  }

  forward_to = [prometheus.relabel.example.receiver]
}

خادم Loki API

loki.relabel "add_labels" {
  forward_to = [loki.write.grafana.receiver]

  rule {
    source_labels = ["__path__"]
    target_label  = "job"
    replacement   = "app-logs"
  }
}

المكونات - المعالجات

معالج الدفع

otelcol.processor.batch "default" {
  send_batch_size    = 1000
  timeout            = "10s"
  send_batch_max_size = 2000

  output {
    traces  = [otelcol.exporter.otlp.grafana.input]
    metrics = [otelcol.exporter.prometheus.grafana.input]
    logs    = [otelcol.exporter.loki.grafana.input]
  }
}

معالج الفلتر

otelcol.processor.filter "drop_internal" {
  metrics {
    exclude {
      match_type = "regexp"
      regexp     = "internal_.*"
    }
  }

  output {
    metrics = [otelcol.exporter.prometheus.grafana.input]
  }
}

معالج كشف المورد

otelcol.processor.resourcedetection "default" {
  detectors = ["env", "system", "gcp", "aws", "azure", "docker", "kubernetes"]

  output {
    traces  = [otelcol.processor.batch.default.input]
    metrics = [otelcol.processor.batch.default.input]
    logs    = [otelcol.processor.batch.default.input]
  }
}

معالج الصفات

otelcol.processor.attributes "add_env" {
  action {
    key    = "environment"
    value  = "production"
    action = "insert"
  }

  action {
    key         = "pod_name"
    from_attribute = "k8s.pod.name"
    action      = "insert"
  }

  output {
    traces  = [otelcol.processor.batch.default.input]
    metrics = [otelcol.processor.batch.default.input]
    logs    = [otelcol.processor.batch.default.input]
  }
}

معالج حد الذاكرة

otelcol.processor.memory_limiter "default" {
  check_interval       = "5s"
  limit_mib            = 512
  spike_limit_mib      = 256

  output {
    traces  = [otelcol.processor.batch.default.input]
    metrics = [otelcol.processor.batch.default.input]
    logs    = [otelcol.processor.batch.default.input]
  }
}

معالج Span (التتبعات)

otelcol.processor.span "extract_attributes" {
  name {
    to_attributes {
      rules = ["^/api/(?P<version>v\\d)/(?P<resource>\\w+)"]
    }
  }

  output {
    traces = [otelcol.processor.batch.default.input]
  }
}

المكونات - الصادرات

Prometheus Remote Write

prometheus.remote_write "grafana" {
  endpoint {
    url = "https://prometheus.grafana.net/api/prom/push"

    basic_auth {
      username = "GRAFANA_USER_ID"
      password = "${GRAFANA_TOKEN}"
    }

    headers = {
      "X-Custom-Header" = "value"
    }

    tls_config {
      insecure_skip_verify = false
    }
  }

  wal {
    enabled = true
    directory = "/var/lib/alloy/wal"
  }

  queue_settings {
    capacity = 10000
  }
}

Loki Write

loki.write "grafana" {
  endpoint {
    url = "https://logs.grafana.net/loki/api/v1/push"

    basic_auth {
      username = "GRAFANA_USER_ID"
      password = "${GRAFANA_TOKEN}"
    }
  }

  tenant_id = "production"
}

مصدر OpenTelemetry (OTLP)

otelcol.exporter.otlp "grafana_cloud" {
  client {
    endpoint = "tempo.grafana.net:4317"

    auth = otelcol.auth.basic "grafana" {}

    tls {
      insecure = false
    }
  }

  retry_on_failure {
    enabled       = true
    initial_interval = "5s"
    max_interval  = "30s"
    max_elapsed_time = "5m"
  }
}

مصادقة OTLP

otelcol.auth.basic "grafana" {
  username = "GRAFANA_USER_ID"
  password = "${GRAFANA_TOKEN}"
}

// OTLP مع مصادقة أساسية
otelcol.exporter.otlp "example" {
  client {
    endpoint = "tempo.grafana.net:4317"
    auth = otelcol.auth.basic.grafana.handler
  }
}

مصدّر Prometheus (على نمط Node Exporter)

prometheus.exporter.unix "local_system" {
  disabled_collectors = ["netdev", "netstat"]
}

prometheus.scrape "local_system" {
  targets = prometheus.exporter.unix.local_system.targets
  forward_to = [prometheus.remote_write.grafana.receiver]
}

المكونات - الاكتشاف

اكتشاف Kubernetes

discovery.kubernetes "cluster" {
  role = "pod"
  namespaces {
    names = ["default", "monitoring", "production"]
  }
}

prometheus.scrape "kubernetes" {
  targets    = discovery.kubernetes.cluster.targets
  forward_to = [prometheus.remote_write.grafana.receiver]

  relabel_configurations {
    source_labels = ["__meta_kubernetes_pod_annotation_prometheus_io_scrape"]
    regex         = "true"
    action        = "keep"
  }
}

اكتشاف Docker

discovery.docker "local" {
  host = "unix:///var/run/docker.sock"
}

prometheus.scrape "docker" {
  targets    = discovery.docker.local.targets
  forward_to = [prometheus.remote_write.grafana.receiver]
}

اكتشاف Consul

discovery.consul "example" {
  server   = "localhost:8500"
  datacenter = "dc1"
  services = ["prometheus", "app"]
}

prometheus.scrape "consul" {
  targets    = discovery.consul.example.targets
  forward_to = [prometheus.remote_write.grafana.receiver]
}

اكتشاف قائم على الملفات

discovery.file "dynamic_targets" {
  files = ["/etc/alloy/targets.json"]
  refresh_interval = "30s"
}

prometheus.scrape "file_targets" {
  targets    = discovery.file.dynamic_targets.targets
  forward_to = [prometheus.remote_write.grafana.receiver]
}

جمع المقاييس

Prometheus Scraping مع إعادة التسمية

prometheus.scrape "prometheus" {
  targets = [
    {
      __address__ = "prometheus.example.com:9090",
      job         = "prometheus",
    },
    {
      __address__ = "alertmanager.example.com:9093",
      job         = "alertmanager",
    },
  ]

  metrics_path    = "/metrics"
  scrape_interval = "30s"
  scrape_timeout  = "10s"

  relabel_configurations {
    source_labels = ["__address__"]
    target_label  = "instance"
    regex         = "([^:]+)(?::\\d+)?"
    replacement   = "${1}"
  }

  metric_relabel_configurations {
    source_labels = ["__name__"]
    regex         = "up|job|instance"
    action        = "keep"
  }

  forward_to = [prometheus.relabel.drop_internal.receiver]
}

تكامل Node Exporter

prometheus.exporter.unix "node_metrics" {
  collectors = ["cpu", "diskstats", "filesystem", "loadavg", "meminfo", "netdev", "netstat"]
  disabled_collectors = ["netdev"]
  set_collectors = ["textfile"]
  textfile_directory = "/var/lib/node_exporter/textfile_collector"
}

prometheus.scrape "node_exporter" {
  targets    = prometheus.exporter.unix.node_metrics.targets
  forward_to = [prometheus.remote_write.grafana.receiver]
}

نقطة نهاية مقاييس مخصصة

prometheus.scrape "custom_app" {
  targets = [
    {
      __address__ = "app.example.com:8080",
      __metrics_path__ = "/api/metrics",
      job = "custom-app",
      env = "production",
    },
  ]

  scrape_interval = "15s"
  forward_to = [prometheus.remote_write.grafana.receiver]
}

جمع السجلات

تتبع الملفات مع Loki

loki.source.file "application" {
  targets = [
    {
      __path__ = "/var/log/app/app.log",
      job      = "app",
      service  = "web",
      env      = "production",
    },
    {
      __path__ = "/var/log/app/error.log",
      job      = "app",
      level    = "error",
    },
  ]

  forward_to = [loki.relabel.add_labels.receiver]
}

سجلات Journal (systemd)

loki.source.journal "systemd" {
  path   = "/var/log/journal"
  labels = {
    job = "systemd",
  }

  forward_to = [loki.relabel.add_labels.receiver]
}

تحليل سجلات JSON

loki.relabel "parse_json" {
  forward_to = [loki.process.extract_json.receiver]

  rule {
    source_labels = ["__path__"]
    target_label  = "filename"
  }
}

loki.process "extract_json" {
  forward_to = [loki.write.grafana.receiver]

  stage {
    json {
      expressions = {
        timestamp = "ts",
        message   = "msg",
        level     = "level",
        service   = "service",
      }
    }
  }

  stage {
    labels {
      values = {
        level   = "level",
        service = "service",
      }
    }
  }

  stage {
    timestamp {
      source = "timestamp"
      format = "Unix"
    }
  }
}

السجلات متعددة الأسطر (Stack Traces)

loki.process "multiline" {
  forward_to = [loki.write.grafana.receiver]

  stage {
    multiline {
      line_start_pattern = "^\\d{4}-\\d{2}-\\d{2}"
    }
  }

  stage {
    regex {
      expression = "^(?P<timestamp>\\d{4}-\\d{2}-\\d{2}) (?P<level>\\w+) (?P<message>.*)"
    }
  }

  stage {
    labels {
      values = {
        level = "level",
      }
    }
  }
}

جمع التتبعات

أنبوب OpenTelemetry Traces

otelcol.receiver.otlp "app" {
  grpc {
    endpoint = "0.0.0.0:4317"
  }

  http {
    endpoint = "0.0.0.0:4318"
  }

  output {
    traces = [otelcol.processor.memory_limiter.default.input]
  }
}

otelcol.processor.memory_limiter "default" {
  check_interval  = "5s"
  limit_mib       = 512
  spike_limit_mib = 256

  output {
    traces = [otelcol.processor.batch.default.input]
  }
}

otelcol.processor.batch "default" {
  send_batch_size = 100
  timeout         = "10s"

  output {
    traces = [otelcol.exporter.otlp.grafana.input]
  }
}

otelcol.exporter.otlp "grafana" {
  client {
    endpoint = "tempo.grafana.net:4317"
    auth = otelcol.auth.basic.grafana.handler
  }
}

otelcol.auth.basic "grafana" {
  username = "GRAFANA_USER_ID"
  password = "${GRAFANA_TOKEN}"
}

جهاز استقبال Jaeger

otelcol.receiver.jaeger "default" {
  protocols {
    grpc {
      endpoint = "0.0.0.0:14250"
    }

    thrift_http {
      endpoint = "0.0.0.0:14268"
    }
  }

  output {
    traces = [otelcol.processor.batch.default.input]
  }
}

جهاز استقبال Zipkin

otelcol.receiver.zipkin "default" {
  endpoint = "0.0.0.0:9411"

  output {
    traces = [otelcol.processor.batch.default.input]
  }
}

نشر Kubernetes

قيم Helm (values.yaml)

config: |
  otelcol.receiver.otlp "default" {
    grpc {
      endpoint = "0.0.0.0:4317"
    }
    http {
      endpoint = "0.0.0.0:4318"
    }
    output {
      traces = [otelcol.processor.batch.default.input]
    }
  }

  otelcol.processor.batch "default" {
    send_batch_size = 100
    output {
      traces = [otelcol.exporter.otlp.grafana.input]
    }
  }

  otelcol.exporter.otlp "grafana" {
    client {
      endpoint = "tempo.grafana.net:4317"
      auth = otelcol.auth.basic.grafana.handler
    }
  }

  otelcol.auth.basic "grafana" {
    username = "GRAFANA_USER_ID"
    password = "${GRAFANA_TOKEN}"
  }

alloy:
  remoteConfigUrl: ""

serviceAccount:
  create: true

rbac:
  create: true

daemonset:
  enabled: true

deployment:
  enabled: true
  replicas: 1

configMap:
  content: ""

livenessProbe:
  enabled: true

readinessProbe:
  enabled: true

تثبيت Helm

# تثبيت مع قيم مخصصة
helm install alloy grafana/alloy \
  --namespace monitoring \
  --create-namespace \
  -f values.yaml

# ترقية التثبيت الموجود
helm upgrade alloy grafana/alloy \
  --namespace monitoring \
  -f values.yaml

# إلغاء التثبيت
helm uninstall alloy --namespace monitoring

مثال DaemonSet

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: alloy
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: alloy
  template:
    metadata:
      labels:
        app: alloy
    spec:
      serviceAccountName: alloy
      containers:
      - name: alloy
        image: grafana/alloy:latest
        args:
        - run
        - /etc/alloy/config.alloy
        - --server.http.listen-addr=0.0.0.0:12345
        ports:
        - name: http
          containerPort: 12345
        - name: otlp-grpc
          containerPort: 4317
        - name: otlp-http
          containerPort: 4318
        volumeMounts:
        - name: config
          mountPath: /etc/alloy
        - name: varlog
          mountPath: /var/log
          readOnly: true
      volumes:
      - name: config
        configMap:
          name: alloy-config
      - name: varlog
        hostPath:
          path: /var/log
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: alloy-config
  namespace: monitoring
data:
  config.alloy: |
    prometheus.scrape "kubernetes" {
      targets = discovery.kubernetes.nodes.targets
      forward_to = [prometheus.remote_write.grafana.receiver]
    }

    discovery.kubernetes "nodes" {
      role = "node"
    }

    prometheus.remote_write "grafana" {
      endpoint {
        url = "https://prometheus.grafana.net/api/prom/push"
        basic_auth {
          username = "GRAFANA_USER_ID"
          password = "${GRAFANA_TOKEN}"
        }
      }
    }

مثال ServiceMonitor

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: app-metrics
  namespace: production
spec:
  selector:
    matchLabels:
      app: myapp
  endpoints:
  - port: metrics
    interval: 30s
    path: /metrics

تكوين Docker

ملف Compose

version: '3.8'
services:
  alloy:
    image: grafana/alloy:latest
    container_name: alloy
    command:
      - run
      - /etc/alloy/config.alloy
      - --server.http.listen-addr=0.0.0.0:12345
    ports:
      - "12345:12345"
      - "4317:4317"
      - "4318:4318"
    volumes:
      - ./alloy-config.alloy:/etc/alloy/config.alloy
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/log:/var/log:ro
    environment:
      - GRAFANA_TOKEN=${GRAFANA_TOKEN}
    networks:
      - monitoring

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
      - monitoring

networks:
  monitoring:
    driver: bridge

تشغيل حاوية

# التشغيل مع ملف التكوين
docker run -d \
  --name alloy \
  -v /path/to/config.alloy:/etc/alloy/config.alloy \
  -p 12345:12345 \
  -p 4317:4317 \
  -p 4318:4318 \
  -e GRAFANA_TOKEN=$GRAFANA_TOKEN \
  grafana/alloy:latest run /etc/alloy/config.alloy \
  --server.http.listen-addr=0.0.0.0:12345

# عرض السجلات
docker logs -f alloy

# إيقاف الحاوية
docker stop alloy
docker rm alloy

التصحيح

وصول واجهة الويب

# وصول واجهة Alloy (منفذ افتراضي 12345)
# يعرض حالة المكون والتصديرات والمقاييس
curl http://localhost:12345
# المتصفح: http://localhost:12345/graph

مستويات السجل

# التشغيل مع تسجيل التصحيح
alloy run config.alloy --log.level=debug

# التشغيل مع تسجيل المعلومات (افتراضي)
alloy run config.alloy --log.level=info

# التشغيل مع تسجيل التحذير
alloy run config.alloy --log.level=warn

التحقق من التكوين

# تحليل التكوين بدون تشغيل
alloy tools parse config.alloy

# التحقق من أخطاء الصيغة
alloy fmt config.alloy

# بحث والتحقق
alloy tools lint config.alloy

فحص المكونات

# عرض جميع أنواع المكونات
alloy tools component list

# الحصول على توثيق المكون
alloy tools component doc prometheus.scrape

# عرض مخطط المكون
alloy tools component schema prometheus.scrape

تحليل Pprof

# تفعيل خادم pprof (افتراضي: http://localhost:6060/debug/pprof)
alloy run config.alloy --pprof.enabled=true --pprof.address=0.0.0.0:6060

# عرض ملف heap
curl http://localhost:6060/debug/pprof/heap > heap.prof
go tool pprof heap.prof

# عرض ملف goroutine
curl http://localhost:6060/debug/pprof/goroutine

فحص التتبعات

# تفعيل التتبع الموزع
alloy run config.alloy --traces.enabled=true

# الوصول إلى واجهة المستخدم trace (إذا تم تعريضها)
curl http://localhost:12345/traces

متغيرات البيئة

المتغيرالوصف
ALLOY_CONFIG_FILEمسار ملف التكوين
GRAFANA_TOKENرمز المصادقة لـ Grafana Cloud
PROMETHEUS_URLنقطة نهاية خادم Prometheus
LOKI_URLنقطة نهاية Loki API
TEMPO_URLنقطة نهاية Tempo API
OTEL_EXPORTER_OTLP_ENDPOINTنقطة نهاية OTLP exporter لـ OpenTelemetry
OTEL_EXPORTER_OTLP_HEADERSرؤوس OTLP exporter
OTEL_SDK_DISABLEDتعطيل OpenTelemetry SDK
LOG_LEVELمستوى السجل: debug, info, warn, error
ALLOY_REMOTE_CONFIG_URLعنوان URL للتكوين البعيد
NODE_NAMEمعرّف العقدة (اسم عقدة k8s)
POD_NAMEاسم Pod (للـ k8s)
NAMESPACEمساحة اسم Kubernetes

استخدام متغيرات البيئة

# تصدير المتغيرات
export GRAFANA_TOKEN="glc_xxx"
export PROMETHEUS_URL="https://prometheus.grafana.net"

# تشغيل Alloy
alloy run config.alloy

# في config.alloy، المرجع مع ${ }
prometheus.remote_write "grafana" {
  endpoint {
    url = "${PROMETHEUS_URL}/api/prom/push"
    basic_auth {
      password = "${GRAFANA_TOKEN}"
    }
  }
}

الموارد