Posts Fluentd 与 elk 日志收集与解析
Post
Cancel

Fluentd 与 elk 日志收集与解析

1 背景与说明

日志收集我们主要采用 ELK/EFK 方案,具体为什么采用这种方案本篇不进行更多阐述;本篇主要针对把业务日志进行解析并相关处理后推送到 Elasticsearch 中更方便进行检索与数据统计查看,本篇日志推送源来自于 DockerFluentd Log Driver,非 Docker 环境操作的仅作为参考。

2 效果图

image

3 主要三样插件

3.1 内置 Parser 插件

这个插件在最新的 Fluentd 中已经内置了,直接使用即可。参考地址

3.2 Elasticsearch 插件

Fluentd 收集到的日志信息推到 ES 进行存储,参考地址

3.3 地理位置插件

根据客户端 IP 地址获取到更多地理相关的信息,这样可以在 kibana 上使用地图与位置的统计图方式更直观查看信息,参考地址

4 开始

4.1 解析日志数据到对应属性

4.1.1 日志原始数据

以下是 Docker 的输出标准日志数据格式内容。

1
2017-03-03T10:46:21+08:00	1806d6c91569	{"log":"2017-03-03 10:46:21 HKT  INFO AccessInterceptor:80 - {time=1488509181152, method=POST, action=/nakedhub/adminx/auth/welcome, locale=zh_CN, cost=4, userId=185713, user-agent=null, header-security-token=null, clientIp=139.196.12.22, clientType=null, params={password=111111, username=maomao}, status=200, paramsOfJson=null}","container_id":"1806d6c91569612cdd746651eeb808591e0176befe565820a339294fc2a9ea0d","container_name":"/nhbackend-st.1.d7r1qsa35zwfxtsmyh5np61ft","source":"stdout"}

4.1.2 核心解析格式配置

1
2
3
4
5
6
7
8
9
<filter **>
    @type parser
    time_format %Y-%m-%d %H:%M:%S %Z
    key_name log
    suppress_parse_error_log true
    reserve_data true
    format /.*(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} \w+?).+AccessInterceptor(.+time=(?<requesttime>.+?),)(.+method=(?<method>.+?),)(.+action=(?<action>.+?),)(.*locale=(?<locale>.+?),)(.+cost=(?<cost>.+?),)(.*userId=(?<userId>.*?),)(.*agent=(?<user-agent>.*?),)(.+token=(?<token>.*?),)(.+clientIp=(?<clientIp>.+?),)(.+clientType=(?<clientType>.+?),)(.*params={(?<params>.*?)})(.+status=(?<status>.*?),)(.*Json=(?<paramsOfJson>.*?)})/
    types cost:integer,status:integer
  </filter>

这里我采用 Fluentd 中的 filter 对数据进行过滤处理,主要的格式化配置都在 format 这段配置中,主要采用正则表达式拆分数据到自定义的以 <> 包围起来的属性中,测试表达式格式可以点开在线格式解析表达式,测试完毕后再把表达式配置就好了;另外值得注意的是 time 这个属性值,这个值解析器会自动识别为时间类型,会按照 time_format 配置定义的格式转换至时间类型;key_name 配置在官方文档中并没有提及(但这个配置是必须的),我得出来的结论是这个配置会把外层 JSONlog 内容拿出来后再去做解析;types 则是把自定义的属性进行类型指定,推送到 Elasticsearch 中也是相应类型(否则通过 kibana 做统计计算的时候由于不是 Number 类型会有问题);reserve_data 配置则表示原始 log 的内容是否保留到输出项中。

4.1.3 最后日志输出项

1
2017-03-03T10:46:21+08:00	1806d6c91569	{"log":"2017-03-03 10:46:21 HKT  INFO AccessInterceptor:80 - {time=1488509181152, method=POST, action=/nakedhub/adminx/auth/welcome, locale=zh_CN, cost=4, userId=185713, user-agent=null, header-security-token=null, clientIp=139.196.12.22, clientType=null, params={password=111111, username=maomao}, status=200, paramsOfJson=null}","container_id":"1806d6c91569612cdd746651eeb808591e0176befe565820a339294fc2a9ea0d","container_name":"/nhbackend-st.1.d7r1qsa35zwfxtsmyh5np61ft","source":"stdout","requesttime":"1488509181152","method":"POST","action":"/nakedhub/adminx/auth/welcome","locale":"zh_CN","cost":4,"userId":"185713","user-agent":"null","token":"null","clientIp":"139.196.12.22","clientType":"null","params":"password=111111, username=maomao","status":200,"paramsOfJson":"null"}

4.2 推送到 ElasticSearch 核心配置

1
2
3
4
5
6
7
8
9
10
11
12
13
<match>
      @type elasticsearch
      host 10.47.121.12
      port 9200
      user elastic
      password 123456
      scheme http
      index_name fluentd
      type_name fluentd
      logstash_format true
      logstash_prefix docker
      reload_connections false
</match>

由于我的 ES 安装了 XPACK 所以我使用了账号与密码项配置内容,另外注意 password 这里不用使用特殊字符,否则会出现 Fluentd 连接 ElasticSearch 的时候字符编码不对导致认为账户与密码不对的错误问题。

4.3 客户端 IP 地理位置处理

4.3.1 注意

这个 filter 的配置项必须要在以上日志解析的配置项下面,要先解析到了 clientIp 属性,我们才能方便配置从而让插件获取客户端IP地址处理地理位置属性。

4.3.2 核心配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<filter **>
    type geoip
    geoip_lookup_key clientIp
    geoip_database /home/fluent/GeoLiteCity.dat
    <record>
      latitude        ${latitude["clientIp"]}
      longitude       ${longitude["clientIp"]}
      country_code3   ${country_code3["clientIp"]}
      country         ${country_code["clientIp"]}
      country_name    ${country_name["clientIp"]}
      dma             ${dma_code["clientIp"]}
      area            ${area_code["clientIp"]}
      region          ${region["clientIp"]}
      city            ${city["clientIp"]}
      location        '[${longitude["clientIp"]},${latitude["clientIp"]}]'
    </record>
    skip_adding_null_record  true
    log_level         info
    flush_interval    1s
</filter>

GeoLiteCity.dat 参考GITHUB项目地址去下载,location 会自动转换为 geo_point 类型。

4.3.3 Kibana 类型 geo_point 问题

1
No Compatible Fields: The "xxx" index pattern does not contain any of the following field types: geo_point

location 属性值已经存在ES中了就算配置后依然无法自动转成 geo_point 类型,我们需要手动进行处理了,先删除相关的所以索引,然后手动创建类型模板定义 location 的类型,然后创建测试索引查看。

4.3.3.1 创建模板类型

打开 Shell 控制台创建文件 json ,文件内容为以下。

1
2
3
4
5
6
7
8
9
10
{
  "template": "docker-*",
  "mappings": {
    "_default_": {
      "properties" : {
        "location": { "type": "geo_point"}
      }
    }
  }
}
1
curl -u elastic:123456 -XPUT 'http://10.47.121.12:9200/_template/docker' -d @json

4.3.3.2 创建测试索引

1
curl -u elastic:123456 -XPUT 'http://10.47.121.12:9200/docker-test/fluentd/2' -d '{"host":"8.8.8.8","location":[1.23,4.56]}'

4.3.3.3 查看索引属性类型

1
curl -u elastic:123456 -XGET http://10.47.121.12:9200/docker-test/fluentd/_mapping?pretty

4.3.3.4 原始问题参考地址

https://github.com/y-ken/fluent-plugin-geoip/issues/16

4.3.4 最后日志输出内容

1
2017-03-03T10:46:21+08:00	1806d6c91569	{"log":"2017-03-03 10:46:21 HKT  INFO AccessInterceptor:80 - {time=1488509181152, method=POST, action=/nakedhub/adminx/auth/welcome, locale=zh_CN, cost=4, userId=185713, user-agent=null, header-security-token=null, clientIp=139.196.12.22, clientType=null, params={password=111111, username=maomao}, status=200, paramsOfJson=null}","container_id":"1806d6c91569612cdd746651eeb808591e0176befe565820a339294fc2a9ea0d","container_name":"/nhbackend-st.1.d7r1qsa35zwfxtsmyh5np61ft","source":"stdout","requesttime":"1488509181152","method":"POST","action":"/nakedhub/adminx/auth/welcome","locale":"zh_CN","cost":4,"userId":"185713","user-agent":"null","token":"null","clientIp":"139.196.12.22","clientType":"null","params":"password=111111, username=maomao","status":200,"paramsOfJson":"null","latitude":30.29360008239746,"longitude":120.1613998413086,"country_code3":"CHN","country":"CN","country_name":"China","dma":null,"area":null,"region":"02","city":"Hangzhou","location":[120.1613998413086,30.29360008239746]}

5 最后

本篇相关的内容到这里就结束了,有什么问题的话给我留言,我会尽量回复,如果有不正确的地方还望不吝赐教,我会作出相应的改进,避免误导更多人,谢谢。

This post is licensed under CC BY 4.0

Docker平台下创建jenkins worker节点

Git 常用的命令汇总

Comments powered by Disqus.