logstash 统计告警

 在实际的项目中需要对线上日志做实时分析跟统计,这一套方案可以用现有的ELK(ElasticSearch, Logstash, Kibana)方案既可以满足,关于这个方案的具体的步骤可以参考网上的解决方案。但如果只想统计某个错误码(http状态码,业务错误码)在指定时间内出现多少次然后就触发一个告警或者某个指令动作(邮件或者是调用已经写好的http接口,例如例如微信平台来通知告警信息等),这种需求可以用logstash进行实现,并且这种方案比较轻量级,很容易实现。这里以在linux平台为主。

下载

首先下载 最新的logstash 压缩包,https://download.elastic.co/logstash/logstash/logstash-2.3.2.zip ,下载后用unzip命令进行解压只指定的目录,解压后会生成一个目录logstash-2.3.2 这个目录,里面包含下面这些文件:

基本配置

开始可以通过一个小的介绍了解logstash是怎么回事,链接里面有一些基本的demo,有兴趣可以参考里面的写一下。链接如下:

http://udn.yyuap.com/doc/logstash-best-practice-cn/get_start/hello_world.html

运行命令如下:

假设在与logstash 平级目录新建一个 配置文件,sample.conf ,这个配置文件就是定义 input filter output 这3块,其主要表示 input的来源是什么(文件或命令之类的),filter 代表对于输入的内容按照规则怎么来过滤,output 就是按照过滤的规则进行输出 。

最简单的写法如下:

# bin/logstash -e 'input{stdin{}}output{stdout{codec=>rubydebug}}'

如果是在sample.conf 中写入则如下:

input {
    stdin{}
}
filter {
    
}
output {
    stdout {}
}
# bin/logstash -f sample.conf

特殊配置

在实际的业务中可能往往要对日志做过滤,然后根据某些关键字段进行统计,通过统计结果来决定需要做什么。logstash 本身对于syslog,redis等日志在过滤的时候一般不需要自己写正则表达式去过滤,这些都是通用的,在filter中可以直接通过%{定义的常量}来获取日志内容,已经自动支持的过滤的日志包含下面这些:

这个列表不全,对于已经支持的这些可以直接到github 上进行搜索(https://github.com/logstash/logstash/tree/v1.4.2/patterns),上面都有这些日志过滤的正则表达式,这些是属于通用配置。 

往往在业务日志中,所打印的业务关键错误码以及格式并非与通用格式相匹配,那么此时就需要自己针对自己的业务日志格式,写出正则表达式来过滤自己想要的信息。

这里就以日志中的errno 来为例,所实现的目的就是 当这个错误码在30s内出现3次就把这个错误输出出来或告警。

在logstash中正则表达式叫做grok表达式,其规则跟perl与ruby的正则表达式一样。 也有在线的grok正则表达式校验工具:http://grokdebug.herokuapp.com/

这里就以下面的日志格式为例:log.txt

begin 10001 end
begin 10001 end
begin 10001 end

在sample.conf 中,grok 是写在filter 中的,这里既可以直接写正则表达式,也可以引用外部文件的正则表达。

方式1:

grok {
    match => {
        "message" => "\s+(?<code>\d+?)\s+"
    }
}

方式2就是预先在 patterns/ 目录下创建一个文件,这个文件里面含有正则表达式,例如创建文件的名称为 test ,内容如下:

ERRORCODE \s+(?<code>\d+?)\s+
grok {
    patterns_dir => "../../patterns/test"
    match => ["message", "%{ERRORCODE:code:int}"]
}:

很显然这里我们习惯采用方式2,因为正则匹配相关的可以单独在一个文件,在sample.conf 就直接引用正则匹配中字段值,例如上面就直接用"ERRORCODE", message 中%后面花括号中的写法规则如下:

%{PATTERN_NAME:capture_name:data_type}

以上面完子为例,完整的 sample.conf 内容如下:

 

input {
    # 以日志文件作为来源
file {
    # 文件路径
    path => "../../log.txt"
}
}
filter {
    # 正则解析
    grok {
    # 增加自定义的正则,这里我把自定义的正则文件,加在了这个目录下
    patterns_dir => "../../patterns/test"
    # 从message字段中解析出 code
    match => ["message", "%{ERRORCODE:code:int}"]
    # 删除原来的message字段
    remove_field => [ "message" ]
    # 增加WARN,作为标记
    add_tag => "warn"
    }

    # 计数
    metrics {
    # 计数器数据保存的字段名 code的值就是上面解析出来的
    meter => "events_%{code}"
    # 增加"metric",作为标记
    add_tag => "metric"
    # 3秒内的message数据才统计,避免延迟
    # ignore_older_than => 3
    # 每隔300秒统计一次
    flush_interval => "30"
    # 每301秒清空计数器
    clear_interval => "31"
    }
    # 如果event中标记为“metric”的
    if "metric" in [tags] {
    # 执行ruby代码
        ruby {
        # 如果count为10001的数量小于3条,就忽略此事件(即不发送任何消息)。
            code => "event.cancel if event['events_10001']['count'] < 3"
        }
    }
}
output {
# 输出到console
    stdout {
        codec => rubydebug
    }
}

上面配置结束后,由于开启 debug 模式,所以当每次往 log.txt 写入 "begin 10001 end" 在控制台下都会有输出,输入内容下:

{
         "@version" => "1",
         "@timestamp" => "2016-11-14T13:14:14.374Z",
          "path" => "../../log.txt",
          "host" => "xxxx",
          "code" => "10001",
          "tags" => [
          [0] "warn"
        ]
}

当在30s内输入的次数大于3次的时候,输出的内容如下:

{
      "@version" => "1",
      "@timestamp" => "2016-11-14T13:14:20.148Z",
       "message" => "xxx",
       "events_" => {
        "WARN" => {
               "count" => 3,
             "rate_1m" => 2.1864058457089883,
             "rate_5m" => 3.814999397602868,
            "rate_15m" => 4.1951645878441255
        }
     },
          "tags" => [
        [0] "metric"
    ]
}

 

通过上面的结构可以看出我们在输出的时候还可以写表达式,例如只有当30s内大于3次才输出信息的话可以在 output 中加一个判断,逻辑如下:

output {
    # 如果event中标记为“metric”,表示只发送计数的消息。
    if "metric" in [tags] {
    # 执行一个简单的命令
        exec {
            command => "echo \"hello: %{events_10001.count}\""
        }
    }
}

 

到这里已经结束,关于logstash中的 统计相关的规则可以参考:http://udn.yyuap.com/doc/logstash-best-practice-cn/filter/metrics.html

输出的形式也是多种的 可以对接ES,触发http接口,这里就以输出为例。

 

posted @ 2016-11-17 00:28  大胡子码农  阅读(7955)  评论(1编辑  收藏  举报