场景&环境

环境:内网UAT环境ELK(elasticsearch、logstash、kibana)
日志类型:Java ERROR Log
格式:[级别] [时间] [class类] | message
grok:\[%{LOGLEVEL}\] \[%{TIMESTAMP_ISO8601}\] \[%{JAVAFILE:class}\] \| (?<info>([\s\S]*))

问题:

在使用ELK 检索日志时发现本应属于一条内容的日志分到了多条日志显示,查看原日志文件发现在应用打日志时就换行了。
日志行开头为“[” 检查logstash 客户端配置在file{}段已经有

codec => multiline {
            pattern => "^\["
            negate => true
            what => "previous"

但并没有解决换行的问题,查资料发现需要在filter{}段写multiline相关配置。

方案实施:

编写logstash 配置文件,在filter{}字段增加multiline 相关配置

        multiline {
            pattern => "^\["
            negate => true
            what => "previous"
        }

重启logstash……结果logstash 报错了……
看了下错误日志,显示的大概内容为没有multiline 插件……

安装logstash-filter-multiline

因为是离线环境,又到rubygems网站下载了对应的filter-multiline-gem文件做离线安装,将下载回来的文件放到logstash/vendor/cache目录下
执行如下命令执行安装

bin/logstash-plugin install --local vendor/logstash/vendor/cache/logstash-filter-multiline-3.0.4.gem

看到如下输出即表示安装成功

Validating /root/logstash-filter-multiline-3.0.4.gem
Installing logstash-filter-multiline

有类似上面信息输出,即可忽略连接错误,如下

Error Bundler::HTTPError, retrying 1/10
Could not fetch specs from https://rubygems.org/

可以查看Gemfile 文件最后一行,有类似如下信息即安装成功
gem "logstash-filter-multiline", "3.0.4", :path => "vendor/local_gems/ffa5f9f7/logstash-filter-multiline-3.0.4"

验证

启动logstash,这次没有报错信息了,再看kibana 上的日志已经合并为一行

后续

某一条错误日志打印了有1.3k行,日志又分为了多条显示,比对后发现前两条正好都是501行,怀疑是有默认行数限制,查阅资料验证了这点怀疑,修改默认行数值解决

默认行数限制

默认行数是在codec 字段,修改如下

        codec => multiline {
            max_bytes => "20MiB"  #修改最大值
            max_lines => 2000 #修改合并行数
            pattern => "^\["
            negate => true
            what => "previous"
        }

完整配置

input{
    file {
        path => ["/logs/error-*.log"]
        type => "error"
        codec => multiline {
            max_bytes => "20MiB"
            max_lines => 2000
            pattern => "^\["
            negate => true
            what => "previous"
        }
        start_position => "beginning"
    }
}

filter {
    if [type] == "error" {
        multiline {
            pattern => "^\["
            negate => true
            what => "previous"
        }
        grok {
            match => {
                "message" => "\[%{LOGLEVEL:loglevel}\] \[%{TIMESTAMP_ISO8601:time}\] \[%{JAVAFILE:class}\] \| (?([\s\S]*))"
            }
           overwrite => ["message"]
        }
    }
}

output {
    if [type] == "error" {
        elasticsearch {
            hosts => ["localhost:9200"]
            index => "error-%{+YYYY-MM}"
        }
    }
}

参考资料

Grok 表达式语法:https://github.com/logstash-plugins/logstash-patterns-core/tree/master/patterns
正则:http://manual.macromates.com/en/regular_expressions
行数限制:https://blog.csdn.net/jiao_fuyou/article/details/50350497
Grok Debugger :http://grokdebug.herokuapp.com 需×××
:http://grok.qiexun.net/ 无需×××