L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Déploiement et opérations · SKILL.md

grafana-alloy-hcl

grafana-alloy-hcl

Use when editing `.alloy` files, configuring Grafana Alloy pipelines, or debugging log collection and relabeling behavior. Covers HCL syntax, common Loki/Prometheus components, processing stages, Docker discovery, and FnOS-specific patterns.

Independent GitHub snapshot · Automated classification · Original documentation governs

Jjianyun8023 / my-skillsApache-2.0

Documentation de la Skill

GitHub

name: grafana-alloy-hcl description: Use when editing .alloy files, configuring Grafana Alloy pipelines, or debugging log collection and relabeling behavior. Covers HCL syntax, common Loki/Prometheus components, processing stages, Docker discovery, and FnOS-specific patterns.

Grafana Alloy HCL 配置指南

Grafana Alloy 使用 HCL (HashiCorp Configuration Language) 作为配置语言,支持模块化、组件化的数据处理流水线。

适用场景

  • 新增或修改 .alloy 配置文件
  • 配置日志采集、处理流水线或 Loki 写入链路
  • 调试 forward_to、discovery.relabel、stage.* 等配置问题
  • 在 FnOS / Docker 环境下落地 Alloy 日志采集

不适用

  • 安装 Alloy 二进制、systemd 服务或容器编排本身
  • Loki / Grafana 仪表盘查询语句、告警规则设计
  • 不涉及 Alloy 的普通 HCL/Terraform 配置

快速工作流

  1. 先确定链路:source -> process/relabel -> write
  2. 先写最小可运行配置,再逐步增加 stage.* 和标签处理
  3. 涉及 Docker relabel 时,优先确认 .output / .rules 的使用位置
  4. 涉及正则时,优先检查 HCL 双反斜杠转义
  5. 最后用 alloy fmt、livedebugging 或示例配置对照验证

核心概念

Alloy 的配置由 Components(组件) 组成,组件之间通过 Capabilities(能力) 连接(如 forward_to)。

基本语法

// 组件类型 "标签" { 属性... }
component.type "label" {
  attribute = "value"
  
  block {
    sub_attribute = 123
  }
}

HCL 正则转义规则

重要: HCL 字符串中使用 \\ 表示一个字面的 \。正则表达式中常见的 \s、\S、\d、\b 等需要写成 \\s、\\S、\\d、\\b。

// ✅ 正确 — HCL 将 \\s 解析为 \s 传给正则引擎
expression = "(?i)(password|passwd|pwd)\\s*[=:]\\s*\\S+"

// ❌ 错误 — \s 在 HCL 中不是合法转义,会导致语法错误或意外行为
expression = "(?i)(password|passwd|pwd)\s*[=:]\s*\S+"

命名捕获组同理:(?P<name>...) 在 HCL 中写为 (?P<name>...)(尖括号不需要转义)。

常用组件

1. 日志采集 (Loki)

  • loki.source.file: 采集本地文件
  • loki.source.journal: 采集 Systemd Journal
  • loki.source.api: 接收 HTTP 推送
  • loki.source.docker: 采集 Docker 容器日志
loki.source.file "app_logs" {
  targets = [
    {
      __path__ = "/var/log/app/*.log",
      job      = "my-app",
    }
  ]
  forward_to = [loki.write.local.receiver]
}

动态文件发现 — 使用 local.file_match 替代静态 targets:

local.file_match "app_logs" {
  path_targets = [{
    __path__ = "/var/log/app/*.log",
    job      = "app-logs",
  }]
}

loki.source.file "app_logs" {
  targets    = local.file_match.app_logs.targets
  forward_to = [loki.process.pipeline.receiver]
}

2. 数据处理

  • loki.process: 解析、过滤、修改日志
  • discovery.relabel: 修改发现阶段的元数据标签
  • loki.relabel: 运行时修改日志条目标签(区别于 discovery.relabel)
loki.process "json_parser" {
  forward_to = [loki.write.local.receiver]
  
  stage.json {
    expressions = {
      level   = "level",
      message = "msg",
    }
  }
  
  stage.labels {
    values = { level = "" }
  }
}

3. 容器日志 (Docker)

  • discovery.docker: 发现 Docker 容器
  • loki.source.docker: 采集容器日志

discovery.relabel 导出字段说明:

  • .output — relabel 后的 targets 列表 (list(map(string))),用于传递给 loki.source.docker 的 targets
  • .rules — 当前配置的 relabel 规则 (RelabelRules),用于传递给 relabel_rules 参数

推荐写法 (官方文档模式 — 使用 .output):

discovery.docker "containers" {
  host = "unix:///var/run/docker.sock"
  filter {
    name   = "status"
    values = ["running"]
  }
}

// 标签处理(提取容器名、镜像等)
discovery.relabel "docker_labels" {
  targets = discovery.docker.containers.targets
  
  // 提取容器名称 (例如 /my-app -> my-app)
  rule {
    source_labels = ["__meta_docker_container_name"]
    regex         = "/(.*)"
    target_label  = "container"
  }
  
  // 提取镜像名称
  rule {
    source_labels = ["__meta_docker_container_image"]
    target_label  = "image"
  }
}

loki.source.docker "docker_logs" {
  host       = "unix:///var/run/docker.sock"
  targets    = discovery.relabel.docker_labels.output   // ✅ 使用 .output 获取 relabel 后的 targets
  forward_to = [loki.process.process_logs.receiver]
}

替代写法 (使用 relabel_rules,功能等价):

// targets 直接引用 discovery.docker,relabel 在 source 层面执行
loki.source.docker "docker_logs" {
  host          = "unix:///var/run/docker.sock"
  targets       = discovery.docker.containers.targets
  relabel_rules = discovery.relabel.docker_labels.rules  // 使用 .rules
  forward_to    = [loki.process.process_logs.receiver]
}

4. 数据发送

  • loki.write: 发送到 Loki 实例

基本配置:

loki.write "local" {
  endpoint {
    url = "http://loki:3100/loki/api/v1/push"
  }
}

生产级配置 (认证 + 重试 + WAL):

loki.write "production" {
  endpoint {
    url = "https://logs.example.com/loki/api/v1/push"
    
    // 基本认证
    basic_auth {
      username = "user123"
      password = env("LOKI_API_KEY")
    }
    
    // 批次控制
    batch_size = "1MiB"
    batch_wait = "1s"
    
    // 重试策略
    min_backoff_period  = "500ms"
    max_backoff_period  = "5m"
    max_backoff_retries = 10
    
    // 多租户
    tenant_id = "production"
  }
  
  external_labels = {
    cluster = "prod-cluster",
    region  = "us-east-1",
  }
  
  // Write-Ahead Log 持久化(防止数据丢失)
  wal {
    enabled         = true
    dir             = "/var/lib/alloy/wal"
    max_segment_age = "2h"
  }
}

高级数据处理 (Advanced Processing)

完整 Stage 列表

Stage用途备注
stage.json解析 JSON 日志最常用
stage.logfmt解析 logfmt 格式mapping = { "key" = "source_key" }
stage.regex正则提取字段使用命名捕获组 (?P<name>...)
stage.labels将提取值设为标签values = { label = "source" }
stage.templateGo 模板转换值如 {{ .Value | ToUpper }}
stage.replace正则替换日志内容常用于脱敏
stage.drop丢弃匹配的日志支持 expression 或 source+value
stage.match条件处理支持 action = "drop"
stage.output设置最终日志内容source = "extracted_field"
stage.timestamp修正日志时间戳Go 时间格式
stage.docker解析 Docker JSON 日志stage.docker {}
stage.static_labels添加静态标签values = { key = "value" }

1. 敏感数据脱敏 (Masking)

使用 stage.replace 隐藏密码、Token 等敏感信息。

loki.process "masking" {
  forward_to = [loki.write.local.receiver]

  // 隐藏 password=xxx
  stage.replace {
    expression = "(?i)(password|passwd|pwd)\\s*[=:]\\s*[\"']?\\S+"
    replace    = "$1=***"
  }
  
  // 隐藏 Bearer Token
  stage.replace {
    expression = "(?i)(authorization|auth)\\s*:\\s*[\"']?Bearer\\s+\\S+"
    replace    = "$1: Bearer ***"
  }
  
  // 隐藏 API Key / Secret
  stage.replace {
    expression = "(?i)(token|api_key|apikey|secret)\\s*[=:]\\s*[\"']?\\S+"
    replace    = "$1=***"
  }
}

2. 噪音过滤 (Filtering)

使用 stage.drop 或 stage.match 丢弃不需要的日志。

loki.process "filtering" {
  forward_to = [loki.write.local.receiver]

  // 方式1: 按正则匹配日志内容丢弃
  stage.drop {
    expression          = ".*(health|healthcheck|heartbeat).*"
    drop_counter_reason = "health_check"
  }
  
  // 方式2: 按提取值精确匹配丢弃
  stage.drop {
    source = "is_secret"
    value  = "true"
  }
  
  // 方式3: 嵌套在 stage.match 中,仅针对特定容器
  stage.match {
    selector = "{container=\"noisy-app\"}"
    stage.drop {
      expression = ".*DEBUG.*"
    }
  }
  
  // 方式4: stage.match + action="drop" (更简洁的条件丢弃)
  stage.match {
    selector            = "{app=\"example\"} |~ \".*noisy error.*\""
    action              = "drop"
    drop_counter_reason = "discard_noisy_errors"
  }
}

3. 时间戳修正 (Timestamp)

使用 stage.timestamp 提取日志中的时间,解决延迟问题。

loki.process "timestamp_fix" {
  forward_to = [loki.write.local.receiver]

  // 提取时间戳 regex
  stage.regex {
    expression = "^(?P<timestamp>\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3})"
  }
  
  // 应用时间戳
  stage.timestamp {
    source = "timestamp"
    format = "2006-01-02 15:04:05.000"
  }
}

4. 日志级别标准化

使用 stage.regex + stage.template + stage.labels 提取并标准化日志级别。

loki.process "level_extraction" {
  forward_to = [loki.write.local.receiver]

  // 通用日志级别提取正则
  stage.regex {
    expression = "(?i)\\b(?P<extracted_level>TRACE|DEBUG|INFO|NOTICE|WARN|WARNING|ERROR|ERR|CRITICAL|CRIT|FATAL|PANIC)\\b"
  }
  
  // 标准化为大写
  stage.template {
    source   = "extracted_level"
    template = "{{ .Value | ToUpper }}"
  }
  
  // 添加为标签
  stage.labels {
    values = {
      level = "extracted_level",
    }
  }
}

5. Docker 日志专用解析

使用 stage.docker 解析 Docker 默认的 JSON 日志格式。

loki.process "docker_parser" {
  stage.docker {}
  forward_to = [loki.write.local.receiver]
}

6. 设置最终输出内容

使用 stage.output 指定最终日志行的内容来源。

loki.process "custom_output" {
  forward_to = [loki.write.local.receiver]

  stage.json {
    expressions = { log_line = "message" }
  }
  
  // 将 "message" 字段的值作为最终日志输出
  stage.output {
    source = "log_line"
  }
}

discovery.relabel rule 支持的 action

Action说明
replace(默认) 用 replacement 替换 target_label 的值
keep保留 source_labels 匹配 regex 的 targets
drop丢弃 source_labels 匹配 regex 的 targets
hashmod对 source_labels 做哈希取模,写入 target_label
labelmap匹配所有标签名,将匹配的标签复制到新名称
labeldrop删除匹配 regex 的标签
labelkeep仅保留匹配 regex 的标签
discovery.relabel "filter_example" {
  targets = discovery.docker.containers.targets
  
  // 仅保留 app="backend" 的 targets
  rule {
    source_labels = ["app"]
    action        = "keep"
    regex         = "backend"
  }
  
  // 添加静态标签
  rule {
    target_label = "env"
    replacement  = "production"
  }
  
  // 合并多个标签为一个
  rule {
    source_labels = ["__address__", "instance"]
    separator     = "/"
    target_label  = "destination"
    action        = "replace"
  }
}

FnOS 参考

FnOS 路径规范、组件示例和调试技巧已拆到 reference.md。在 FnOS / FPK 场景下,先读该文件,再回到本技能主流程拼装配置。

常见错误清单

错误写法正确写法说明
targets = discovery.docker.X.targets (配合 relabel 使用时)targets = discovery.relabel.X.outputrelabel 后应使用 .output
expression = "\s+"expression = "\\s+"HCL 中 \ 需要双重转义
stage.labels { values = { level = "level" } } 提取同名字段stage.labels { values = { level = "" } }空字符串表示使用同名键
在 loki.process 外使用 stage放在 loki.process 块内所有 stage 必须嵌套在 loki.process 中
forward_to = loki.write.X.receiverforward_to = [loki.write.X.receiver]forward_to 始终是数组

Checklist

实现前:

  • 已明确日志来源、处理链路和最终写入目标
  • 已确认是否需要 discovery.relabel、loki.relabel 或 loki.process
  • 已确认运行环境路径、Docker socket 或 FnOS 日志目录

实现后:

  • 所有 forward_to 都是数组,且接收端存在
  • 正则表达式中的反斜杠已按 HCL 规则双重转义
  • Docker relabel 相关配置正确使用 .output 或 .rules
  • 已参考 resources/example.alloy 验证整体结构是否一致

完整示例

请参考 resources/example.alloy 获取包含系统日志、Docker 发现及高级处理的完整配置示例。

Skills enregistrées