docker快速搭建elk-2-解析Java、go、nginx日志,让你的日志从一潭死水变成生机勃勃的海洋

1,077 阅读6分钟

之前写的

用docker快速搭建elk日志平台

mp.weixin.qq.com/s?__biz=MzU…

总结了docker快速搭建elk的过程,今天再简单总结下elk的使用。

1.拉取最新镜像

docker pull registry.cn-beijing.aliyuncs.com/siyueren/elk:1.3.1


我将镜像升级到了 1.3.1 版本,主要给elastic search 加装了 head 插件,方便查看es服务状态和索引数据。

2.运行容器

docker run  \
-p 5000:5000 \
-p 5044:5044 \
-p 5601:5601 \
-p 9100:9100 \
-p 9200:9200 \
-p 9300:9300 \
-e ES_MIN_MEM=512m \
-e ES_MAX_MEM=2048m \
-v /Users/qiaojianyong/docker/elk/elasticsearch:/var/lib/elasticsearch \
-v /Users/qiaojianyong/docker/elk/logstash:/etc/logstash/conf.d \
-d -i -t --restart always --name=elk e86cbb543763

注意,其中挂载的宿主机目录要改成自己的

/Users/qiaojianyong/docker/elk/elasticsearches 索引数据目录
/Users/qiaojianyong/docker/elk/logstashlogstash配置目录

启动所需时间较长,访问 http://localhost:9100/ 如果看到如下界面,则说明启动成功。


当然你启动成功之后是没有 java-test-log-* 这个索引的。


3.收集java、NGINX、go日志

3.1下载filebeat

我这里只是简单用filebeat 来收集日志,更高阶的做法可以借助kafka 来收集。

首先下载 filebeat, 下载地址 www.elastic.co/downloads/b…,下载较慢。

下载完成后解压

tar -xvf filebeat-7.7.1-darwin-x86_64.tar.gz 

编写启动脚本start.sh,如下(可能有更高效的方法)

vim start.sh
​
# shutdown
# ps -ef|grep filebeat
# kill -9 pid# start 使用 nohup 守护进程方式启动
cd /Users/qiaojianyong/Downloads/logs/filebeat-7.7.1-darwin-x86_64
nohup ./filebeat -c filebeat.yml -e>filebeat.log 2>&1 &


3.2配置 filebeat

编辑filebeat.yml

vim filebeat.yml

filebeat.inputs:
# NGINX 日志输入源
- type: log
  enabled: true # 是否启用
  paths:
    - /var/log/nginx/access.log # 本机日志目录
  fields: # 自定义的字段,最终会和日志数据一起写入es索引文档,方便条件检索
    app: nginx-access # 指定日志输入源
    log_type: nginx-access # 指定日志类型# Java应用日志输入源
- type: log
  enabled: true
  paths:
    - /root/tomcat/data/log/mall/scheduler/mall-scheduler.log
  fields:
    app: mall-scheduler
    env: test # 环境
    log_type: java
  multiline.pattern: '^\s*(\d{4}|\d{2})\-(\d{2}|[a-zA-Z]{3})\-(\d{2}|\d{4})'
  multiline.negate: true
  multiline.match: after
​
# Go应用日志
- type: log
  enabled: true
  paths:
    - /home/ubuntu/applogs/wallet/wallet.log
  fields:
    app: wallet-go
    env: test
    log_type: go
​
​
filebeat.config.modules:
  path: ${path.config}/modules.d/*.yml
  reload.enabled: false
setup.template.settings:
  index.number_of_shards: 1
setup.kibana:
# 输出源
output.logstash:
  hosts: ["localhost:5044"]
processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~
  - add_docker_metadata: ~
  - add_kubernetes_metadata: ~


3.3 启动 filebeat

sh start.sh

启动成功如图

一共加载了三个启用的输入源,并成功连接到了5044端口

但是当日志文件中产生新日志的时候会报错,如下

这是因为logstash没有成功启动,因为之前启动elk时没有给logstash准备配置文件。

接下来就需要配置logstash接收、解析filebeat发来的日志。


4.配置logstash,解析日志


4.1 logstash配置文件目录结构

首先进入到elk容器本机挂载的logstash配置文件宿主目录,我这里是

/Users/qiaojianyong/docker/elk/logstash

这里的配置文件可以是多个,有的人按照logstash配置的三个主要部分分别来配置inputfilteroutput

比如下图这样

我这里简单只写一个配置文件 filebeat.conf 表示接收和处理来自filebeat的日志数据。

vim filebeat.conf

另外还要在logstash配置目录再建一个文件夹 patterns, 用来存放切割日志的grok正则对。

建好之后如下


4.2 logstash配置文件结构

如上所说,logstash配置文件有三个主要部分 input filter output


4.2.1 ‍input

用来配置输入源,比如我这里简单从filebeat来接收日志

这里也可以配置成从kafka,file,系统日志等输入源接收日志

更多知识详见官网 

www.elastic.co/guide/en/lo…

4.2.2 filter

配置过滤和解析规则,起到一个数据适配的作用。这里知识较多不细说了,这篇博文写的很详细,

www.cnblogs.com/xiaobaozi-9…

如图是我的配置,通过filebeat 自定义的field-log_type 来区分日志来源。



4.2.2.1 grok插件

grok作用简单来说就是通过正则匹配来切割日志,将日志切割成不同部分。grok插件内置了一些常用的patterns,比如说日期时间、ip等


grok内置patterns地址

github.com/logstash-pl…

grok更多知识可以看这几篇文章

www.jianshu.com/p/443f1ea7b…

doc.yonyoucloud.com/doc/logstas…

www.jianshu.com/p/86133dd66…


可以到下面这个网站验证自己写的pattern是否正确(墙内无法使用)

grokconstructor.appspot.com/do/match#re…

操作方法如图



我的go日志输出格式,在每个字段前后加了中括号,方便匹配切割

java日志就是springboot默认的格式

我的自定义patterns

# base
MY_STR [\s\S]*
MY_TIME 20%{YEAR}-%{MONTHNUM}-%{MONTHDAY} %{HOUR}:?%{MINUTE}(?::?%{SECOND})
​
# java
JAVA_LOG %{MY_TIME:log_time} \s*%{LOGLEVEL:level} %{NUMBER:pid} .*\[\s*%{MY_STR:thread}\] %{JAVACLASS:class} .*:\s%{MY_STR:message}
​
# go
GO_LOG \[%{MY_TIME:log_time}\] \[%{MY_STR:level}\] \[%{MY_STR:file}\:%{NUMBER:line}\:%{MY_STR:function}\] \[%{MY_STR:message}\]
​
# nginx 容器自带保持默认就行


4.2.3 output

配置输出源,这里只配置了es,并指定将日志数据按天存到不同索引,方便日后处理过期日志。


4.3 完整filebeat.conf 内容

input {
  beats {
    port => 5044
    type => "logs-from-beats"
  }
}
​
filter {
    if [fields][log_type]=="java" {
        grok {
            patterns_dir => "/etc/logstash/conf.d//patterns"
            match => {"message" => ["%{JAVA_LOG}", "%{MY_STR:message}"]}
            overwrite => ["message"]
        }
​
        date { # 将@timestamp 替换为日志时间,如果不替换查看时日志可能前后时间颠倒
            match => ["log_time","YYYY-MM-dd HH:mm:ss.SSS"]
            remove_field =>["log_time"]
            # target => "@timestamp" # 默认就是@timestamp
            timezone => "Asia/Shanghai"
        }
​
        # 解析嵌套json格式数据
        mutate {
            add_field => { "@fields" => "%{fields}" } # 新增json
            add_field => { "@log" => "%{log}" } # 新增json
            remove_field => ["host","agent","ecs","tags","fields","@version","input","_index","_score","_type","type","_id"]
        }
​
        json {
            source => "@fields" # 解析新增的json @fields
            remove_field => [ "beat","@fields","fields","index_name","source","time"] # 删除不必要字段
        }
        json {
            source => "@log" # 解析新增的json @log
            remove_field => [ "offset","@log","log"]
        }
    }
    if [fields][log_type]== "nginx-access" {
        grok {
            patterns_dir => "/opt/logstash/patterns"
            match => {"message" => "%{NGINXACCESS}"}
  }
        date {
            match => ["timestamp", "dd/MM/YYYY HH:mm:ss Z"]
        }
        # 解析嵌套json格式数据
        mutate {
            add_field => { "@fields" => "%{fields}" } # 新增json
            add_field => { "@log" => "%{log}" } # 新增json
            remove_field => ["host","agent","ecs","tags","fields","@version","input","_index","_score","_type","type","_id"]
        }
​
        json {
            source => "@fields" # 解析新增的json @fields
            remove_field => [ "beat","@fields","fields","index_name","source","time"] # 删除不必要字段
        }
        json {
            source => "@log" # 解析新增的json @log
            remove_field => [ "offset","@log","log"]
        }
    }
    if [fields][log_type]== "go" {
        grok {
            patterns_dir => "/etc/logstash/conf.d//patterns"
            match => {"message" => ["%{GO_LOG}", "%{MY_STR:message}"]}
            overwrite => ["message"]
        }
​
        date { # 将@timestamp 替换为日志时间,如果不替换查看时日志可能前后时间颠倒
            match => ["log_time","YYYY-MM-dd HH:mm:ss.SSS"]
            remove_field =>["log_time"]
            timezone => "Asia/Shanghai"
        }
​
        # 解析嵌套json格式数据
        mutate {
            add_field => { "@fields" => "%{fields}" } # 新增json
            add_field => { "@log" => "%{log}" } # 新增json
            remove_field => ["host","agent","ecs","tags","fields","@version","input","_index","_score","_type","type","_id"]
        }
​
        json {
            source => "@fields" # 解析新增的json @fields
            remove_field => [ "beat","@fields","fields","index_name","source","time"] # 删除不必要字段
        }
        json {
            source => "@log" # 解析新增的json @log
            remove_field => [ "offset","@log","log"]
        }
    }
}
​
output {
  elasticsearch {
    hosts => ["http://localhost:9200"]
    index => "java-test-log-%{+YYYY.MM.dd}"
    # index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
    #user => "elastic"
    #password => "changeme"
  }
   #stdout { codec => rubydebug } # logstash控制台输出
}

4.4 重启elk

docker restart elk


5.kibana,让你的日志活起来

5.1 查询日志

使用kibana简单的查询如下图,入口统一,简单方便快速简直不要太友好,与传统用tail、greo 等命令查看纯文本日志相比,就像是使用iphone与诺基亚的区别



5.2 使用kibana创建可视化图表,分析接口请求流量

选择左侧图表按钮创建一个可视化图表

选择好类型,kibana默认会生成y轴,默认指示数量 count

需要自己按照需要创建x轴,我这里选择Date Histogram,根据时间创建直方图

这里以下单接口为例,如图


另外,可以创建多个图表,然后组成一个仪表盘~

效果