Logstash 数据采集与处理:输入、过滤器、输出

我把 Logstash 的 pipeline 理解成一个流水线车间。

输入是原料入口,过滤器是加工环节,输出是把成品送到仓库。告警数据的质量,就看这条流水线设计得够不够精细。

1. 输入阶段:数据从哪来

我最早做 ELK 时,习惯把所有日志都塞进 Logstash,结果发现告警触发了一堆假的。后来才明白——输入阶段就要筛选,不要什么数据都往里倒。

输入插件适用场景告警注意事项
beatsFilebeat / Metricbeat 推送建议带上 @metadata 字段,别在告警 payload 里混入无用指标
tcp网络设备 syslog注意端口和安全组,我曾经因为默认 tcp 端口被墙耽误了半天排查
file本地文件 tail要配合 sincedb,重启后不会重读已处理行,这点容易踩坑
httpWebhook 推送建议加 basic auth 或 验证,不然外部恶意推送能刷爆你的告警
我个人习惯在 input 阶段就打一个 type 标签,这样后面 filter 可以按类型做不同处理,代码清爽很多。

2. 过滤器:告警数据的核心加工

告警规则好不好用,很大程度上取决于过滤器的配置。说白了,就是要从杂乱日志中把关键字段提取出来,并且清洗干净。

2.1 Grok:正则提取的艺术

Grok 是 Logstash 最常用的解析方式。它把正则表达式包装成 %{PATTERN:field} 的语法,省了你手写正则的痛苦。

filter {
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} \[%{DATA:service}\] %{GREEDYDATA:message_body}" }
    overwrite => [ "message" ]
  }
}

我在项目中遇到过这样的事:有一条 RDS 慢查询日志,时间戳格式里混了毫秒和时区,默认的 TIMESTAMP_ISO8601 匹配不上。后来我自己写了个 %{YEAR}-%{MONTHNUM}-%{MONTHDAY} %{HOUR}:%{MINUTE}:%{SECOND},%{INT:msec} 才搞定。记住,不要完全依赖内置模式,日志格式千奇百怪,要灵活组合。

我曾经因为 grok 匹配失败导致整条日志被丢弃,告警直接哑了。建议加一个 _grokparsefailure 的 tag,然后输出到一个 dead letter queue,方便事后排查。

2.2 Mutate:字段整形

告警场景里,经常需要把字符串转数字、改名、删掉冗余字段。Mutate 插件就是干这个的。

filter {
  mutate {
    convert => { "[response_time]" => "float" }
    rename => { "host" => "[host][name]" }
    remove_field => [ "path", "offset", "type" ]
  }
}

你想想看,如果不把 response_time 转成数值,后面告警阈值比较根本没法做。我见过有同事直接把字符串 "120" 扔进告警规则,结果永远是字符串比较,出不来正确结果。

2.3 Date:时间归一化

Logstash 默认用 @timestamp 作为事件时间,但很多日志自带的时间戳格式不标准。用 date 插件把它转成统一格式,能让告警时序更准确。

filter {
  date {
    match => [ "timestamp", "ISO8601", "yyyy-MM-dd HH:mm:ss,SSS" ]
    target => "@timestamp"
    timezone => "Asia/Shanghai"
  }
}
注意:如果日志时间戳和 Logstash 服务器时间差太多,告警规则里的“最近5分钟”可能会乱套。一定要检查时区,我吃过这个亏。

2.4 其他常用过滤器

  • kv:解析键值对格式,比如 URL 参数或应用日志里的 k=v
  • geoip:从 IP 获取地理位置,用于告警源 IP 分析
  • drop:直接丢弃不需要的事件,节省下游算力
  • clone:复制事件,便于同一份数据走不同告警流程

3. 输出阶段:数据去哪

告警数据经过过滤器处理之后,需要送到告警引擎或者 ES 索引里。输出阶段也要做基本的校验,避免把垃圾数据写入。

输出插件告警用途注意事项
elasticsearch写入 ES 索引,供告警规则查询建议按天或按类型分索引,设置 ILM 策略,防止磁盘爆满
email直接发邮件告警(简单场景)频率限制很重要,我曾经一个错误日志循环触发上千封邮件,把公司邮箱打挂了
http调用外部 webhook(例如钉钉、Slack)注意重试机制和超时时间,网络波动会导致告警丢失
stdout调试用别在生产环境保留 stdout 输出,日志量大会撑爆日志文件
我个人习惯在 output 里加一个 if [type] == "alert" 的分支,专门把告警相关的事件写到专用索引,这样查询更快。

4. 完整 pipeline 示例:为 CPU 告警准备数据

我拿一个实际案例来说。假设我们用 Metricbeat 采集服务器 CPU 指标,想要在 CPU 使用率超过 90% 时触发告警。

input {
  beats {
    port => 5044
    codec => "plain"   # 有时 metricbeat 会发 json,这里用 plain 做演示
  }
}

filter {
  # 只处理 CPU 指标,过滤掉其他 system 数据
  if [metricset][module] == "system" and [metricset][name] == "cpu" {
    grok {
      match => { "message" => "host=%{DATA:host} cpu_pct=%{NUMBER:cpu_pct:float} time=%{TIMESTAMP_ISO8601:timestamp}" }
    }
    mutate {
      convert => { "cpu_pct" => "float" }
      # 帮告警规则简化判断:直接生成一个布尔字段
      if [cpu_pct] > 90.0 {
        mutate { add_field => { "[alert][critical]" => "true" } }
      }
    }
    date {
      match => [ "timestamp", "ISO8601" ]
      target => "@timestamp"
    }
  } else {
    drop { }
  }
}

output {
  if [alert][critical] == "true" or [cpu_pct] > 85.0 {
    elasticsearch {
      hosts => ["localhost:9200"]
      index => "cpu-alert-%{+YYYY.MM.dd}"
      manage_template => false   # 我用自建模板
    }
    # 同时发一份到消息队列,供其他系统消费
    kafka {
      topic_id => "alert-cpu"
      codec => "json"
    }
  } else {
    # 非告警数据也保存,用于趋势分析
    elasticsearch {
      hosts => ["localhost:9200"]
      index => "cpu-non-alert-%{+YYYY.MM.dd}"
    }
  }
}

这个配置里,我故意在 filter 阶段就打了 alert 标记,输出时根据这个标记分流。这样做的好处是——告警规则写起来特别简单,直接查 alert.critical: true 就行,不用再写复杂的计算逻辑。

注意那个 manage_template => false。我刚开始没关,Logstash 自动创建了一个很松的 mapping,后面字段类型全乱了,告警阈值判断全失效。建议自己设计 ES 模板,然后关掉自动管理。

5. 本章知识体系图

下面这张图总结了 Logstash 告警数据处理的核心流程——从输入到输出,每一步都在为告警规则准备好数据。

Logstash 告警数据处理流程 输入 Input Beats / TCP / File / HTTP Grok 正则提取字段 Mutate 类型/改名/删除 Date 时间归一化 其他(kv/geoip/…) 键值对/IP属地/丢弃 输出 Output 核心要点 1. 输入阶段就要打标签分类,避免无效数据进入 pipeline 2. Grok 匹配失败时不要丢弃,用 dead letter queue 保留原始数据 3. Mutate 做类型转换,Date 做时间归一化,两者缺一不可 4. 输出分流:告警事件写专用索引,非告警也保留用于趋势分析 5. 关闭 Logstash 自动 mapping 管理,用自定义 ES 模板保证字段类型

6. 避坑与实战建议

  • 测试先行:我在本地用 stdout { codec => dots } 观察流量,确认 pipeline 没问题再上生产
  • 不要在一个 filter 块里做太多事:拆成多个 filter 块,每个只负责一件事,便于调试和复用
  • 善用条件判断:Logstash 的 if 语句很强大,但别写太复杂,可以把判断逻辑拆到不同 stage
  • 监控 pipeline 健康度:用 monitoring.elasticsearch.hosts 把运行指标上报到 ES,实时看丢弃率和处理延迟
记住一条原则:Logstash pipeline 的最终输出,应该是一个结构清晰、字段类型正确、时间一致的数据对象。告警规则只需要做“检索”和“判断”,不需要再做数据清洗。这才是真正的“为告警准备数据”。