跟我学:分布式链路跟踪之ELK日志实战

1,781 阅读3分钟

「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」。

跟我学:分布式链路跟踪之ELK初搭建

1.前言

上一篇文章我们进行了ELK环境的搭建,初步做到了在指定的文件夹下,新增日志时,可以存储在ES中,但有不少问题存在,本篇文章我们来好好捋捋。

有些代码放在中间影响体验,故用了@x标记,之后可在最下方搜索。

2.问题

2.1 多行代码问题

问题原因

众所周知,Java的异常是以多行代码的形式,按照之前的配置,呈现在kibana中便是一句话一行,完全无法使用。 image.png

问题解决

在filebeat.yml的log节点下增加配置,如果不能匹配正则表达式,会将下面的语句After到上面,从而成为一条Message。@1

  multiline:
      pattern: '^\s*(\d{4}|\d{2})\-(\d{2}|[a-zA-Z]{3})\-(\d{2}|\d{4})'  
      negate: true                                                       
      match: after

2.2 数据格式问题

问题原因

日志产生后,需要将数据进行清洗,保证数据质量问题。

问题解决

  1. 在logstash根目录下创建patterns文件夹。
  2. 创建 pattern 文件。
  3. 进行 pattern 文件编辑,添加如下正则表达式,用于数据格式化。
DATETIME \d{4}-\d{1,2}-\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2}(\.\d{1,3})
STACK_TRACE ((.+Exception:.*)|(.+Error:.*)|(\s+at\s.*))?(.*\s*)*
LINE \|{2}
VLINE \s*\|{2}\s*
VLIN1 \|
NOTVLINE [^\s\|]*
NOTSQUAR [\]]*

JAVA_LINE_LOG_SIMPLATE01 %{DATETIME:timestamp}%{LINE}%{DATA:level}%{LINE}%{DATA:logger}%{LINE}%{GREEDYDATA:more}
JAVA_LINE_LOG_MULTILINE01 %{DATETIME:timestamp}%{LINE}%{DATA:level}%{LINE}%{DATA:logger}%{LINE}%{DATA:more}[\n]+%{STACK_TRACE:stacktrace}
  1. 在logstash的sync.conf下进行配置@2(ps:该文件是手动创建的,见上文)

2.3 数据过滤问题

问题原因

大量日志产生后,有些日志是我们需要的,有些是我们不需要的。这边为了保证数据的完整性,不进行过滤。只是将其标注为Parse_Error,和逻辑删一个概念。

问题解决

在Logstash配置文件中添加配置@3

2.4 数据时间问题

问题原因

相信大多数开发同学都碰到过时区的问题,不管是MySQL的,还是Docker上的,经常差8个小时。

这套环境中有两个时间,一个是日志产生的时间,另外一个是写入ES的时间。

问题解决

在Logstash配置文件中添加配置 @4

2.5 字段多余问题

问题原因

数据清洗后,有些字段是不需要的,我们需要将一些字段给删掉。

问题解决

在Logstash配置文件中添加配置@5

3 结尾

3.1 效果

经过上方的各种配置后,在Es中呈现的效果如下:

image.png

3.2 搜索

image.png

4 完整的配置文件

4.1 filebeat

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /Users/zyq/project/study-project/logs/*.log
  fields_under_root: true
  fields:
   app_type: java

  ### Multiline options 多行配置  @1
  multiline:
      pattern: '^\s*(\d{4}|\d{2})\-(\d{2}|[a-zA-Z]{3})\-(\d{2}|\d{4})'  
      negate: true                                                       
      match: after

filebeat.config.modules:
  path: ${path.config}/modules.d/*.yml
  reload.enabled: false
setup.template.settings:
  index.number_of_shards: 1
  index.number_of_replica: 0
setup.kibana:
output.logstash:
  # The Logstash hosts
  hosts: ["localhost:5044"]
  # pretty: true
  # enable: true

processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~
  - add_docker_metadata: ~
  - add_kubernetes_metadata: ~

4.2 logstash

# 输入
input {
  beats {
    port => 5044
  }
}

filter{    #@2
  if [agent][type] == "filebeat" { #判断是否是fillebeat来源
    if [app_type] == "java" {  #判断apptype类型
        if "multiline" in [log][flags] {   #判断是多行还是单行
            grok { 
                patterns_dir => ["../config/patterns"]    #多行走的正则表达式
                match => [ "message" , "%{JAVA_LINE_LOG_MULTILINE01}" ]
            }
            mutate {
                add_field => {"mutiline" => "true"}   #多行添加es字段为true
            }
        } else {
            grok { 
                    patterns_dir => ["../config/patterns"]
                    match => [ "message" , "%{JAVA_LINE_LOG_SIMPLATE01}" ]  #单行走的正则表达式
                }
        }

        
        date {   #时区配置 @4
            target => "@timestamp"
            timezone => "Asia/Shanghai"
            match => ["@timestamp","MMMM dd yyyy HH:mm:ss.SSS"]
        }
        if "_grokparsefailure" in [tags] {   #解析失败后添加的过滤标志 parse_error@3
            mutate {
              add_field => {"parse_error" => "true"}
            }
        } else {
            mutate  {
                replace => {"message" => "%{[more]}"}
            }
        }
        mutate {  #@5
            remove_field => [   #去除的字段
              "@version","agent","host","ecs","input","log","more","tags"
            ]
            add_field => {
              "logfile" => "%{[log][file][path]}"
            }
        }
          
    }
  }

}

output {
  elasticsearch {
    hosts => ["http://localhost:9200"]
    index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
    #user => "elastic"
    #password => "changeme"
  }
}