Elastic Stack梳理:Logstash Input插件详解与Codec插件应用指南之文件监控、多行日志处理与Kafka集成

Input插件核心机制与文件监控


Input插件基础功能

Input插件指定数据输入源,单个Pipeline可配置多个插件
Logstash支持丰富的数据源接入(如文件、Kafka、标准输入等)

核心插件包括:

  • stdin:标准输入(无专用配置)
  • file:文件读取(支持日志收集)
  • kafka:消息队列集成

1 ) stdin插件详解

作用:从命令行终端实时读取数据流。
通用配置参数(所有Input插件共享):

  • type:自定义事件类型(字符串),用于后续条件过滤(如 web/mysql)。
  • tags:事件标签(数组),辅助Filter阶段的条件判断。
  • add_field:添加自定义字段(哈希类型)。

配置示例:

input {  
  stdin {  
    codec => "plain"  # 原始文本解码  
    type  => "STD"    # 自定义类型  
    tags  => ["test"]  
    add_field => { "key" => "value" }  
  }  
}  
output { stdout { codec => rubydebug } }  # 调试输出  

执行效果(输入 Hello World):

{  
  "message" => "Hello World",  
  "type"    => "STD",  
  "tags"    => ["test"],  
  "key"     => "value"  
}  
  • 关键作用:typetags用于后续Filter条件过滤,add_field扩展元数据

2 ) 文件监控(file插件)的核心问题与解决方案

核心问题解决方案:

  • 断点续传:通过 sincedb 文件记录读取位置(路径由 sincedb_path 指定)
  • 实时监控:定时检查文件更新(间隔由 stat_interval 控制,默认1秒)
  • 新增文件发现:定时扫描匹配文件(间隔由 discover_interval 控制,默认15秒)
  • 文件归档处理:基于inode追踪文件,即使重命名仍可完整读取(依赖 logwatch 库)

关键配置参数:

参数类型作用
path数组监听文件路径(支持Glob语法)
exclude数组排除文件规则
start_position枚举beginning(从头读)/end(只读新内容)
ignore_older数值忽略超过设定时长(秒)未更新的文件
close_older数值关闭超过设定时长(秒)无新内容的文件句柄

Glob匹配语法规则:

  • *:匹配任意非隐藏文件
  • ``:递归匹配子目录
  • ?:匹配单个字符
  • [a-z]:匹配字符范围
  • {a,b,c}:匹配多选项
问题Logstash解决方案配置参数
断点续读sincedb位置记录文件sincedb_path
实时读取新增内容定时文件检查机制stat_interval
动态发现新文件目录扫描匹配discover_interval
文件旋转(如logrotate)基于inode追踪(非文件名)ignore_older
文件句柄资源释放自动关闭空闲文件close_older

关键配置详解:

input {
  file {
    path => ["/var/log/*.log", "/var/log//*.log"]  # Glob匹配规则
    exclude => "*.gz"              # 排除压缩文件
    start_position => "beginning"  # 首次读取从文件开头 
    sincedb_path => "/dev/null"    # 调试时禁用sincedb
    ignore_older => 86400          # 忽略24小时未更新文件
    close_older => 3600            # 1小时无新内容关闭句柄
  }
}

注意:start_position 仅在首次读取生效,后续依赖 sincedb 记录。需删除 sincedb 文件才能重新从头读取

3 ) Glob匹配语法规则

path => "/var/log//*.log"  # 递归匹配所有子目录
path => "/var/log/{app1,app2}/*.log"  # 匹配app1/app2目录 
path => "/var/log/??_error.log"       # 匹配两个字符前缀

特殊案例:

  • * 不匹配隐藏文件(需显式指定 .*
  • `` 跨多级目录递归

4 ) Kafka集成配置

input {
  kafka {
    bootstrap_servers => "kafka1:9092,kafka2:9092"
    group_id => "logstash_consumers"
    topics => ["nginx_logs", "app_logs"]
    consumer_threads => 4  # 并发线程数
  }
}

Codec插件:数据编解码与多行日志处理


1 ) 常用Codec插件对比

插件作用使用场景
plain原始文本输出基础日志
json解析JSON字段API日志
multiline合并多行事件Java异常堆栈
rubydebug友好格式化输出调试模式
dots点状进度指示压力测试

JSON解析示例:

input { stdin { codec => json } }  
output { stdout { codec => rubydebug } }  

输入 {"name":"Alice","age":30} 输出:

{ "name": "Alice", "age": 30 }  # 原始JSON被解析为字段  

2 ) 多行日志处理(multiline codec)

场景1:Java异常堆栈、代码换行字符串

核心参数:

  • pattern:正则表达式匹配行特征(如 ^\s+ 匹配空格开头行)
  • whatprevious(归属上一事件)/next(归属下一事件)
  • negatetrue(反向匹配,即不符合pattern的行触发合并)
input {
  stdin {
    codec => multiline {
      pattern => "^\[%{TIMESTAMP_ISO8601}\]"    # 匹配时间戳行首
      # pattern => "\\$"                        # 以反斜杠结尾的行
      negate => true                            # 对pattern取反 
      what => "previous"                        # 归属到前一行事件
      # what    => "next"                       # 与下一行合并
    }
  }
}

多行匹配模式:

案例1Java堆栈日志(空格缩进归并)
pattern => "^\s+"  
what => "previous"
 
案例2:代码换行(反斜杠结尾续行)
pattern => "\\$"  
what => "next"

调试技巧:通过negate反转匹配逻辑,what定义行归属方向

场景2:跨行代码字符串合并

codec => multiline {  
  pattern => "\\$"               # 以反斜杠结尾的行  
  what    => "next"              # 与下一行合并  
}  

输入内容:

Hello \  
World!  

输出效果(单事件):

{ "message" => "Hello World!" }  

工程示例:1


1 ) 基础日志采集管道

// nestjs-logger.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { Client } from '@elastic/elasticsearch';
 
@Injectable()
export class LoggerService {
  private readonly esClient: Client;
 
  constructor() {
    this.esClient = new Client({ node: 'http://localhost:9200' });
  }
 
  async logToES(message: string, context: string) {
    await this.esClient.index({
      index: 'app_logs',
      body: { 
        timestamp: new Date().toISOString(),
        message,
        context 
      }
    });
  }
}

Logstash配置同步ES:

logstash.conf
input {
  file {
    path => "/var/log/nest-app/*.log"
    sincedb_path => "/opt/logstash/sincedb"
  }
}
filter {
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:msg}" }
  }
}
output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "nest-logs-%{+YYYY.MM.dd}"
  }
}

2 ) Kafka缓冲日志中台

// kafka-producer.service.ts
import { Kafka } from 'kafkajs';
 
const kafka = new Kafka({ brokers: ['kafka:9092'] });
const producer = kafka.producer();
 
async function sendLog(topic: string, log: object) {
  await producer.send({
    topic,
    messages: [{ value: JSON.stringify(log) }]
  });
}

Logstash消费Kafka写入ES:

input {
  kafka {
    topics => ["nest_logs"]
    bootstrap_servers => "kafka:9092"
    codec => json  # 自动解析JSON
  }
}
output {
  elasticsearch {
    hosts => ["es01:9200"]
    index => "kafka-logs-%{+yyyy.MM}"
  }
}

3 ) 错误告警联动

Elasticsearch Watcher配置:

PUT _watcher/watch/error_alert
{
  "trigger": { "schedule": { "interval": "1m" } },
  "input": {
    "search": {
      "request": {
        "indices": ["app_logs-*"],
        "body": {
          "query": { "match": { "level": "ERROR" } }
        }
      }
    }
  },
  "actions": {
    "send_email": {
      "email": {
        "to": "admin@example.com",
        "subject": "紧急:发现系统错误日志",
        "body": "检测到{{ctx.payload.hits.total}}条错误日志"
      }
    }
  }
}

工程示例:2


1 )原生Elasticsearch客户端

安装依赖:

npm install @elastic/elasticsearch  

服务封装(es.service.ts):

import { Injectable } from '@nestjs/common';  
import { Client, ClientOptions } from '@elastic/elasticsearch';  
 
@Injectable()  
export class EsService {  
  private client: Client;  
 
  constructor() {  
    this.client = new Client({ node: 'http://localhost:9200' } as ClientOptions);  
  }  
 
  async indexDocument(index: string, body: any) {  
    return this.client.index({ index, body });  
  }  
 
  async search(index: string, query: any) {  
    return this.client.search({ index, body: { query } });  
  }  
}  

2 ) 方案2:NestJS官方Elastic模块

安装依赖:

npm install @nestjs/elasticsearch  

模块注册(app.module.ts):

import { Module } from '@nestjs/common';  
import { ElasticsearchModule } from '@nestjs/elasticsearch';  
 
@Module({  
  imports: [  
    ElasticsearchModule.register({ node: 'http://localhost:9200' }),  
  ],  
})  
export class AppModule {}  

服务调用(log.service.ts):

import { Injectable } from '@nestjs/common';  
import { ElasticsearchService } from '@nestjs/elasticsearch';  
 
@Injectable()  
export class LogService {  
  constructor(private readonly esService: ElasticsearchService) {}  
 
  async createLog(index: string, log: any) {  
    return this.esService.index({ index, body: log });  
  }  
}  

ELK全链路集成(Logstash+Kafka+ES)


架构说明:

  1. Logstash:通过 kafka Input插件消费日志,Filter阶段解析字段
  2. Kafka:作为缓冲队列,解耦日志生产与消费
  3. Elasticsearch:存储结构化日志,NestJS服务通过客户端查询

Logstash配置:

input {  
  kafka {  
    topics => ["nginx_logs"]  
    bootstrap_servers => "kafka:9092"  
  }  
}  
filter {  
  grok { match => { "message" => "%{COMBINEDAPACHELOG}" } } # 解析Nginx日志  
}  
output {  
  elasticsearch {  
    hosts => ["es:9200"]  
    index => "nginx-%{+YYYY.MM.dd}"  
  }  
}  

ES索引生命周期管理(ILM):

PUT _ilm/policy/logs_policy  
{  
  "policy": {  
    "phases": {  
      "hot": { "actions": { "rollover": { "max_size": "50GB" } } },  
      "delete": { "min_age": "30d", "actions": { "delete": {} } }  
    }  
  }  
}  
 
PUT _index_template/logs_template
{
  "index_patterns": ["*-logs*"],
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs_policy"
    }
  }
}

性能调优参数

# elasticsearch.yml
thread_pool.write.queue_size: 1000  # 增大写入队列
indices.memory.index_buffer_size: 30%  # 内存缓冲区
cluster.routing.allocation.disk.watermark.low: 85%  # 磁盘警戒线

最佳实践:结合_bulk API批量写入,单批次5-15MB数据量

常见问题解决方案


  1. Sincedb失效

    • 删除sincedb_path文件强制从头读取
    • 开发环境可用sincedb_path => "/dev/null"
  2. 多行日志截断

    codec => multiline {
      pattern => "^%{TIMESTAMP_ISO8601} "
      negate => true
      what => "previous"
      auto_flush_interval => 5  # 5秒无新行强制结束事件
    }
    
  3. 文件句柄泄漏

    file {
      close_older => 300   # 5分钟关闭空闲文件
      file_completed_action => "delete"  # 处理完删除归档文件
    }
    

技术总结:

  • Logstash的核心价值在于通过插件化架构实现数据流的灵活编排。Input插件解决数据源适配问题,Codec插件处理数据格式转换,尤其multiline对堆栈日志的归并至关重要
  • 生产环境中需结合Kafka缓冲、ES索引生命周期管理、批量写入策略构建稳健日志管道
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值