初探ELK-logstash使用小结
2016/9/22
注:由于在实践过程中,会不断学习到新的东西,文章会不定时保持更新,如果遇到问题,请重新刷新一下文章查看是否有更新。
【写在前言】
说起处理日志的手段,大家或多或少都听说过ELK(elasticsearch+logstash+kibana),怎么入门呢?咱们从一个小小的目标开始。
目标:收集nginx日志,集中展示。
不少人对 ELK 的第一印象,容易觉得它这个工具组合似乎挺难上手的,错!只需动手试试就知道啦!
目标分解:
1)熟悉 logstash 的安装和基本操作
2)熟悉 elasticsearch 的安装和基本操作,然后结合 logstash 使用
3)熟悉 kibana 的安装和基本操作,然后结合 elasticsearch 使用
本文主要是带你进入 logstash 的世界,其余内容请参考相关文章(elasticsearch使用小结,kibana使用小结,filebeat使用小结)。
一、安装 1、jdk 和 环境变量 支持jdk-1.7以上,推荐jdk-1.8 在环境变量配置:JAVA_HOME 2、安装 有2种方式下载,推荐缓存rpm包到本地yum源 1)直接使用rpm wget https://download.elastic.co/logstash/logstash/packages/centos/logstash-2.4.0.noarch.rpm 2)使用yum源 [root@vm49 ~]# rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch [root@vm49 ~]# vim /etc/yum.repos.d/logstash.repo [logstash-2.4] name=Logstash repository for 2.4.x packages baseurl=https://packages.elastic.co/logstash/2.4/centos gpgcheck=1 gpgkey=https://packages.elastic.co/GPG-KEY-elasticsearch enabled=1 [root@vm49 ~]# yum install logstash [root@vm49 ~]# whereis logstash logstash: /etc/logstash /opt/logstash/bin/logstash /opt/logstash/bin/logstash.bat 二、使用 1、命令行测试 1)输出到 stdout [root@vm49 ~]# /opt/logstash/bin/logstash -e 'input { stdin { } } output { stdout {} }' hi, let us go(输入) Settings: Default pipeline workers: 4 Pipeline main started 2016-09-12T02:42:59.110Z 0.0.0.0 hi, let us go(输出) why not TRY IT OUT(输入) 2016-09-12T02:43:11.904Z 0.0.0.0 why not TRY IT OUT(输出) (CTRL-D 退出) Pipeline main has been shutdown stopping pipeline {:id=>"main"} 2)改变输出到 stdout 的格式 [root@vm49 ~]# /opt/logstash/bin/logstash -e 'input { stdin { } } output { stdout { codec => rubydebug } }' aaaa Settings: Default pipeline workers: 4 Pipeline main started { "message" => "aaaa", "@version" => "1", "@timestamp" => "2016-09-18T02:11:07.109Z", "host" => "0.0.0.0" } bbbb { "message" => "bbbb", "@version" => "1", "@timestamp" => "2016-09-18T02:11:11.864Z", "host" => "0.0.0.0" } Pipeline main has been shutdown stopping pipeline {:id=>"main"} 3)上述输出发现一个小问题,得到的 host 为 0.0.0.0,而不是期望中的当前 hostname 检查一下 hostname [root@vm49 ~]# hostname vm49.localdomain [root@vm49 ~]# echo '10.50.200.49 vm49.localdomain' >>/etc/hosts 再次测试: [root@vm49 ~]# /opt/logstash/bin/logstash -e 'input { stdin { } } output { stdout { codec => rubydebug } }' aaaaa Settings: Default pipeline workers: 4 Pipeline main started { "message" => "aaaaa", "@version" => "1", "@timestamp" => "2016-09-18T02:22:12.180Z", "host" => "vm49.localdomain" } Pipeline main has been shutdown stopping pipeline {:id=>"main"} 符合预期。 注1:还有一种场景(hostname使用本地名称,而不是采取域名的命名方式)需要注意 /etc/hosts 中包括下述内容 ------------------------ 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 127.0.0.1 local-vm50 10.50.200.50 local-vm50 ------------------------ 期望的结果是: "host" => "local-vm50" 实际得到的结果是: "host" => "localhost" 此时,需要删除: 127.0.0.1 local-vm50 然后才能得到期望的结果。 注2:如果是在 logstash 服务启动后才去调整了 hostname 相关设置,则需要重启 logstash 服务,否则依然是旧的结果。 2、使用配置文件 目的:从日志文件中读取数据,输出到另一个文件中来查看。 前提:已经配置了一个nginx服务,生成了对应的日志文件。 首先,因为这里要读取nginx日志,请将 logstash 加入 nginx 的用户组。 示例: [root@vm49 ~]# ls -l /var/log/nginx/access_*.log -rw-r----- 1 nginx adm 608083 Sep 13 18:18 /var/log/nginx/access_www.test.com_80.log -rw-r----- 1 nginx adm 597070 Sep 13 18:18 /var/log/nginx/access_www.work.com_80.log nginx属于 adm 组,使用 logstash 读取日志,可能产生权限异常: failed to open /var/log/nginx/access.ecshop.test.d3dstore.com.log: Permission denied 因此,要加入对应的组: [root@vm49 ~]# usermod -G adm logstash 接着,我们尝试这样配置 logstash 来收集日志: [root@vm49 ~]# cat /etc/logstash/conf.d/nginx.conf input { file { path => "/var/log/nginx/access_*.log" start_position => beginning ignore_older => 0 } } filter { grok { match => { "message" => "%{COMBINEDAPACHELOG}"} } } output { file { path => "/tmp/test.log" } } 上面使用到以下插件: file:日志数据的输入和输出 grok:来匹配标准的apache日志格式 【细节延伸】 显然,在3个环节中,都有改进和调整的地方。 input:使用 filebeat filter:使用其他插件和规则 output:使用ES,redis等 具体请参考: https://www.elastic.co/guide/en/logstash/current/pipeline.html 3、测试配置文件: [root@vm49 ~]# service logstash configtest Configuration OK 4、启动服务: [root@vm49 ~]# service logstash start [root@vm49 ~]# chkconfig logstash on 5、测试请求nginx服务,然后观察输出的内容: [root@vm49 ~]# cat /tmp/test.log 符合预期。 6、比较 去掉 filter 这一节,我们来对比一下 /tmp/test.log 收集到的内容的差异 【使用了 filter 的结果a】 {"message":"10.50.200.219 - - [12/Sep/2016:13:00:03 +0800] \"GET / HTTP/1.1\" 200 13 \"-\" \"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2\" \"-\" 0.000 \"-\" \"-\"","@version":"1","@timestamp":"2016-09-12T05:00:04.140Z","path":"/var/log/nginx/access_www.test.com_80.log","host":"vm49.localdomain","clientip":"10.50.200.219","ident":"-","auth":"-","timestamp":"12/Sep/2016:13:00:03 +0800","verb":"GET","request":"/","httpversion":"1.1","response":"200","bytes":"13","referrer":"\"-\"","agent":"\"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2\""} 【未使用 filter 的结果b】 {"message":"10.50.200.219 - - [12/Sep/2016:13:07:49 +0800] \"GET / HTTP/1.1\" 200 13 \"-\" \"curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2\" \"-\" 0.000 \"-\" \"-\"","@version":"1","@timestamp":"2016-09-12T05:07:49.917Z","path":"/var/log/nginx/access_www.test.com_80.log","host":"vm49.localdomain"} a的内容中,多出来的地方,正是使用了 grok 分析和结构化数据 --------------------------------------------------- Information Field Name ----------- ---------- IP Address clientip User ID ident User Authentication auth timestamp timestamp HTTP Verb verb Request body request HTTP Version httpversion HTTP Status Code response Bytes served bytes Referrer URL referrer User agent agent --------------------------------------------------- 注:也可以将 filter 调整到服务端,让客户端仅仅是收集日志即可,这个取舍需要自行对比。 7、改进 Logstash 默认自带了 apache 标准日志的 grok 正则: 如何使用自定义的日志格式呢? 例如,默认的 nginx 日志是: log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; 改成自定义的日志格式: log_format online '$remote_addr [$time_local] "$request" ' '"$http_content_type" "$request_body" "$http_referer" ' '$status $request_time $body_bytes_sent'; 对应的数据: 【GET】# curl -H "Content-Type: text/html; charset=UTF-8" --referer 'www.abc.com/this_is_a_referer' http://www.test.com/a/b/c.html?key1=value1 【结果】10.50.200.219 [12/Sep/2016:15:11:04 +0800] "GET /a/b/c.html?key1=value1 HTTP/1.1" "text/html; charset=UTF-8" "-" "www.abc.com/this_is_a_referer" 404 0.000 168 【POST】# curl -H "Content-Type: application/xml" -d "{"name": "Mark Lee" }" "http://www.test.com/start" 【结果】10.50.200.218 [12/Sep/2016:15:02:07 +0800] "POST /start HTTP/1.1" "application/xml" "-" "-" 404 0.000 168 尝试一下: [root@vm49 ~]# mkdir -p /etc/logstash/patterns.d [root@vm49 ~]# vim /etc/logstash/patterns.d/extra_patterns NGINXACCESS %{IPORHOST:clientip} \[%{HTTPDATE:timestamp}\] "%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}" (?:%{QS:content_type}|-) (?:%{QS:request_body}|-) (?:"(?:%{URI:referrer}|-)"|%{QS:referrer}) %{NUMBER:response} %{BASE16FLOAT:request_time} (?:%{NUMBER:bytes}|-) 调整配置为: [root@vm49 ~]# cat /etc/logstash/conf.d/nginx.conf input { file { path => "/var/log/nginx/access_*.log" start_position => beginning ignore_older => 0 } } filter { grok { patterns_dir => ["/etc/logstash/patterns.d"] match => { "message" => "%{NGINXACCESS}" } } } output { file { path => "/tmp/test.log" } } [root@vm49 ~]# service logstash restart 结果: {"message":"10.50.200.218 [12/Sep/2016:15:28:23 +0800] \"POST /start HTTP/1.1\" \"application/xml\" \"-\" \"-\" 404 0.000 168","@version":"1","@timestamp":"2016-09-12T07:28:24.007Z","path":"/var/log/nginx/access_www.test.com_80.log","host":"vm49.localdomain","clientip":"10.50.200.218","timestamp":"12/Sep/2016:15:28:23 +0800","verb":"POST","request":"/start","httpversion":"1.1","content_type":"\"application/xml\"","request_body":"\"-\"","response":"404","request_time":"0.000","bytes":"168"} {"message":"10.50.200.219 [12/Sep/2016:15:28:24 +0800] \"GET /a/b/c.html?key1=value1 HTTP/1.1\" \"text/html; charset=UTF-8\" \"-\" \"www.abc.com/this_is_a_referer\" 404 0.000 168","@version":"1","@timestamp":"2016-09-12T07:28:25.019Z","path":"/var/log/nginx/access_www.test.com_80.log","host":"vm49.localdomain","clientip":"10.50.200.219","timestamp":"12/Sep/2016:15:28:24 +0800","verb":"GET","request":"/a/b/c.html?key1=value1","httpversion":"1.1","content_type":"\"text/html; charset=UTF-8\"","request_body":"\"-\"","referrer":"\"www.abc.com/this_is_a_referer\"","response":"404","request_time":"0.000","bytes":"168"} 符合预期。 三、输出到 redis+elasticsearch+kibana 1、测试环境(已经部署了服务) 【客户端】10.50.200.49: logstash, nginx(www.test.com, www.work.com) 【服务端】10.50.200.220: logstash, redis, elasticsearch, kibana 【测试端】10.50.200.218, 10.50.200.219: curl 请求 nginx 1)测试脚本 -------------------------------------------------------- [root@vm218 bin]# cat test_www_by_curl.sh #!/bin/bash # #2016/9/20 # crontab: # */2 * * * * /usr/local/bin/test_www_by_curl.sh >>/tmp/test_www_by_curl.log 2>&1 & echo "[S] at: `date`" tag="$(echo `hostname` |awk -F'-' '{print $NF}')" do_curl(){ www=$1 rnd=$2 #PUT curl -H "Content-Type: application/xml" -d "{"name": "Jack A"}" "http://${www}/from_${tag}" curl -H "Content-Type: application/json" -d "{"name": "Jack B"}" "http://${www}/from_${tag}" curl -H "Content-Type: application/png" -d "{"img_path": "p_w_picpaths/$(date +%F)/${rnd}.png"}" "http://${www}/from_${tag}" #GET curl -H "Content-Type: text/html; charset=UTF-8" --referer "www.${tag}.com/this_is_referer" "http://${www}/" curl -H "Content-Type: text/html; charset=UTF-8" --referer "www.${tag}.com/this_is_referer" "http://${www}/a/b/c.html?key=${tag}" curl -H "Content-Type: text/html; charset=GBK" --referer "www.${tag}.com/this_is_referer" "http://${www}/action.do?event=login&user=${tag}&sid=${rnd}" # } for i in `seq 1 2000`; do do_curl www.work.com "`od /dev/urandom -w12 -tx4 -An |sed -e 's/ //g' |head -n 1`" do_curl www.test.com "`od /dev/urandom -w12 -tx4 -An |sed -e 's/ //g' |head -n 1`" done >/dev/null 2>&1 echo "[D] at: `date`" -------------------------------------------------------- 2)hosts 写入域名 10.50.200.49 www.test.com 10.50.200.49 www.work.com 2、场景1:只有1个域名/模糊匹配N个域名 目的:将匹配的 access 日志收集起来集中展示。 【客户端】 输入:file 输出:redis [root@vm49 ~]# cat /etc/logstash/conf.d/nginx.conf input { file { type => "NginxAccess" path => "/var/log/nginx/access_*.log" start_position => beginning ignore_older => 0 } } filter { if[type] == "NginxAccess" { grok { patterns_dir => ["/etc/logstash/patterns.d"] match => { "message" => "%{NGINXACCESS}" } } date { match => [ "timestamp", "dd/MMM/YYYY:HH:mm:ss Z" ] remove_field => [ "timestamp" ] } } } output { if[type] == "NginxAccess" { redis { host => "10.50.200.220" data_type => "list" key => "logstash:nginxaccess" } } } [root@vm49 ~]# service logstash restart 【服务端】 输入:redis 输出:elasticsearch [root@vm220 ~]# vim /etc/logstash/conf.d/redis.conf input { redis { host => '127.0.0.1' data_type => 'list' port => "6379" key => 'logstash:nginxaccess' type => 'redis-input' } } output { if[type] == "NginxAccess" { elasticsearch { hosts => "127.0.0.1:9200" index => "logstash-nginxaccess-%{+YYYY.MM.dd}" } } } [root@vm220 ~]# service logstash restart 可以通过命令行去观察 redis 的状态: [root@vm220 ~]# redis-cli monitor 指定kibana的索引名称,例如: logstash-nginxaccess-* 结果:符合预期。 3、场景2:N个域名分开收集 目的:将 www.test.com 和 www.work.com 的 access 日志收集起来使用独立的索引名来分开展示 【客户端】 输入:file 输出:redis [root@vm49 ~]# cat /etc/logstash/conf.d/nginx.conf input { file { type => "NginxAccess-www.test.com" path => "/var/log/nginx/access_www.test.com*.log" start_position => beginning ignore_older => 0 } file { type => "NginxAccess-www.work.com" path => "/var/log/nginx/access_www.work.com*.log" start_position => beginning ignore_older => 0 } } filter { if[type] =~ "NginxAccess-" { grok { patterns_dir => ["/etc/logstash/patterns.d"] match => { "message" => "%{NGINXACCESS}" } } date { match => [ "timestamp", "dd/MMM/YYYY:HH:mm:ss Z" ] remove_field => [ "timestamp" ] } } } output { if[type] =~ "NginxAccess-" { redis { host => "10.50.200.220" data_type => "list" key => "logstash:nginxaccess" } } } [root@vm49 ~]# service logstash restart 【服务端】 输入:redis 输出:elasticsearch [root@vm220 ~]# cat /etc/logstash/conf.d/redis.conf input { redis { host => '127.0.0.1' data_type => 'list' port => "6379" key => 'logstash:nginxaccess' type => 'redis-input' } } output { if[type] == "NginxAccess-www.test.com" { elasticsearch { hosts => "127.0.0.1:9200" index => "logstash-nginxaccess-www.test.com-%{+YYYY.MM.dd}" } } if[type] == "NginxAccess-www.work.com" { elasticsearch { hosts => "127.0.0.1:9200" index => "logstash-nginxaccess-www.work.com-%{+YYYY.MM.dd}" } } } [root@vm220 ~]# service logstash restart 当然了,要调整kibana的索引名称,指定更具体的名称,例如: logstash-nginxaccess-www.test.com-* logstash-nginxaccess-www.work.com-* 结果:符合预期。 四、小结FAQ 1、数据流向 ------------------------------------------------------------------ log_files -> logstash -> redis -> elasticsearch -> kibana ------------------------------------------------------------------ 2、@timestamp 和 message 中记录的时间字段(timestamp)不一致 message 中记录的是原始时间,而 @timestamp 中记录的是事件采集到的时候记录的时间,两者可能差距有1s及以上。 可以通过 date 插件来调整记录到的时间,以日志中记录的原始时间为准,可以用于读取过去某段时间的日志文件,这样一来,收集日志时记录的时间不会错乱。 例如: filter { date { match => [ "timestamp", "dd/MMM/YYYY:HH:mm:ss Z" ] remove_field => [ "timestamp" ] } } 将匹配 field "timestamp" 格式为 "dd/MMM/YYYY:HH:mm:ss Z" 实际匹配到: 18/Sep/2016:16:43:15 +0800 默认更新 @timestamp 为: September 18th 2016, 16:43:15.000 特别说明: 1)timestamp 是我们在原始日志中收集的时间字段,不一定是这个名称(这意味是任意的自定义的字段名称),因为只是我们在前述操作中使用 grok 插件中在 patterns 中定义了 "%{NGINXACCESS}" 这个变量来解析原始字段,里边定义了这个 "timestamp" 字段。 a、grok插件的定义 grok { patterns_dir => ["/etc/logstash/patterns.d"] match => { "message" => "%{NGINXACCESS}" } } b、grok插件指明的 patterns 的定义 [root@vm49 ~]# cat /etc/logstash/patterns.d/extra_patterns NGINXACCESS %{IPORHOST:clientip} \[%{HTTPDATE:timestamp}\] "%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}" (?:%{QS:content_type}|-) (?:%{QS:request_body}|-) (?:"(?:%{URI:referrer}|-)"|%{QS:referrer}) %{NUMBER:response} %{BASE16FLOAT:request_time} (?:%{NUMBER:bytes}|-) 2)为何要使用 remove_field 功能? a、重复数据 我们已经有了一个时间字段 "@timestamp" 因此可以丢掉这个重复的 "timestamp" 字段。 注:由此联想一下,生产应用中,我们是不是应该好好利用下 "remove_field" 功能去筛选一下字段呢?主动的去丢弃一些字段,只保留特别重要的指标发送给 output 即可。 b、导入到 elasticsearch 时,模版 mapping type 时异常 以收集 nginx error log 为例: error log 的时间字段格式是这样的:2016/09/21 10:34:41 对应的 date 插件是这样写的: date { match => [ "timestamp", "YYYY/MM/dd HH:mm:ss" ] remove_field => [ "timestamp" ] } 如果不删除字段 "timestamp",当传递到 elasticsearch 时,模版将试图解析这字段的格式,这个时候会遇到解析异常,从而影响到 index 的建立。 在 elasticsearch 的日志中将产生如下错误: MapperParsingException[failed to parse [timestamp]]; nested: IllegalArgumentException[Invalid format: "2016/09/21 10:34:41" is malformed at "/09/21 10:34:41"]; 3、如何使用 grok 插件来匹配 nginx error log 1)示例日志 2016/09/21 10:34:41 [error] 11990#0: *6718852 no live upstreams while connecting to upstream, client: 10.50.200.219, server: c.test.com, request: "GET http://www.work.com/cgi-bin/common/attr?id=260714&r=0.1011513018987016 HTTP/1.1", upstream: "http://upstream_backend/cgi-bin/common/attr?id=260714&r=0.1011513018987016", host: "www.work.com" 2016/09/21 11:26:41 [error] 1614#0: *25584123 open() "/data/www/www.test.com/404.html" failed (2: No such file or directory), client: 10.50.200.218, server: www.test.com, request: "GET /action.do?event=login&user=vm218&sid=15120ae826ca2290514bcd5b HTTP/1.1", host: "www.test.com", referrer: "www.vm218.com/this_is_referer" 2)示例匹配规则 NGINXERROR_DATESTAMP %{YEAR}/%{MONTHNUM}/%{MONTHDAY} %{TIME} NGINXERROR_PID (?:[0-9]+#[0-9]+\:) NGINXERROR_TID (?:\*[0-9]+) NGINXERROR %{NGINXERROR_DATESTAMP:timestamp} \[%{LOGLEVEL:loglevel}\] %{NGINXERROR_PID:pid} %{NGINXERROR_TID:tid} %{GREEDYDATA:errormsg}, client: %{IPORHOST:clientip}, server: %{HOSTNAME:server}, request: %{QS:request}(?:, upstream: %{QS:upstream})?, host: \"%{HOSTNAME:hostname}\"(?:, referrer: (?:"(?:%{URI:referrer}|-)"|%{QS:referrer}))? 注:特别说明,“%{NGINXERROR_PID:pid} %{NGINXERROR_TID:tid}” 这一段只是为了匹配“11990#0: *6718852”并打算丢弃掉,并非实际需要这2个字段。 3)使用工具测试 http://grokconstructor.appspot.com/do/match 4)结果 ------------------------------------------------------------------ 2016/09/21 10:34:41 [error] 11990#0: *6718852 no live upstreams while connecting to upstream, client: 10.50.200.219, server: c.test.com, request: "GET http://www.work.com/cgi-bin/common/attr?id=260714&r=0.1011513018987016 HTTP/1.1", upstream: "http://upstream_backend/cgi-bin/common/attr?id=260714&r=0.1011513018987016", host: "www.work.com" 【MATCHED】 request "GET·http://www.work.com/cgi-bin/common/attr?id=260714&r=0.1011513018987016·HTTP/1.1" server c.test.com hostname www.work.com timestamp 2016/09/21·10:34:41 clientip 10.50.200.219 port pid 11990#0: upstream "http://upstream_backend/cgi-bin/common/attr?id=260714&r=0.1011513018987016" referrer tid *6718852 errormsg no·live·upstreams·while·connecting·to·upstream loglevel error ================================================================== 2016/09/21 11:26:41 [error] 1614#0: *25584123 open() "/data/www/www.test.com/404.html" failed (2: No such file or directory), client: 10.50.200.218, server: www.test.com, request: "GET /action.do?event=login&user=vm218&sid=15120ae826ca2290514bcd5b HTTP/1.1", host: "www.test.com", referrer: "www.vm218.com/this_is_referer" 【MATCHED】 request "GET·/action.do?event=login&user=vm218&sid=15120ae826ca2290514bcd5b·HTTP/1.1" server www.test.com hostname www.test.com timestamp 2016/09/21·11:26:41 clientip 10.50.200.218 port pid 1614#0: upstream referrer "www.vm218.com/this_is_referer" tid *25584123 errormsg open()·"/data/www/www.test.com/404.html"·failed·(2:·No·such·file·or·directory) loglevel error ------------------------------------------------------------------ 5)应用 【服务端】 a、增加上述匹配规则到配置文件 [root@vm220 ~]# cat /etc/logstash/patterns.d/extra_patterns NGINXERROR_DATESTAMP %{YEAR}/%{MONTHNUM}/%{MONTHDAY} %{TIME} NGINXERROR_PID (?:[0-9]+#[0-9]+\:) NGINXERROR_TID (?:\*[0-9]+) NGINXERROR %{NGINXERROR_DATESTAMP:timestamp} \[%{LOGLEVEL:loglevel}\] %{NGINXERROR_PID:pid} %{NGINXERROR_TID:tid} %{GREEDYDATA:errormsg}, client: %{IPORHOST:clientip}, server: %{HOSTNAME:server}, request: %{QS:request}(?:, upstream: %{QS:upstream})?, host: \"%{HOSTNAME:hostname}\"(?:, referrer: (?:"(?:%{URI:referrer}|-)"|%{QS:referrer}))? b、调整对应的 logstash 配置 [root@vm220 ~]# vim /etc/logstash/conf.d/filebeat.conf 在 filter 这一段增加: if[type] =~ "NginxError-" { grok { patterns_dir => ["/etc/logstash/patterns.d"] match => { "message" => "%{NGINXERROR}" } } date { match => [ "timestamp", "YYYY/MM/dd HH:mm:ss" ] remove_field => [ "timestamp" ] } } 在 output 这一段增加: if[type] == "NginxError-www.test.com" { elasticsearch { hosts => ["10.50.200.218:9200", "10.50.200.219:9200", "10.50.200.220:9200"] manage_template => false index => "%{[@metadata][beat]}-nginxerror-www.test.com-%{+YYYY.MM.dd}" document_type => "%{[@metadata][type]}" } } if[type] == "NginxError-www.work.com" { elasticsearch { hosts => ["10.50.200.218:9200", "10.50.200.219:9200", "10.50.200.220:9200"] manage_template => false index => "%{[@metadata][beat]}-nginxerror-www.work.com-%{+YYYY.MM.dd}" document_type => "%{[@metadata][type]}" } } c、重启 logstash 服务 [root@vm220 ~]# service logstash restart 【客户端】 d、调整对应的 filebeat 配置 [root@vm49 ~]# vim /etc/filebeat/filebeat.yml (增加对应的 prospectors 来收集日志,打上 type 标记,其他配置略) prospectors: - paths: - /var/log/nginx/error_www.test.com*.log input_type: log document_type: NginxError-www.test.com - paths: - /var/log/nginx/error_www.work.com*.log input_type: log document_type: NginxError-www.work.com e、重启 filebeat 服务 [root@vm49 ~]# service filebeat restart 4、怎么调试问题 直接改变 output 到 stdout 即可查看输出是否符合需求。 output { if[type] =~ "NginxAccess-" { stdout { codec => rubydebug } } if[type] =~ "NginxError-" { stdout { codec => rubydebug } } } ZYXW、参考 1、官网 https://www.elastic.co/guide/en/logstash/current/introduction.html https://www.elastic.co/guide/en/logstash/current/getting-started-with-logstash.html https://www.elastic.co/guide/en/logstash/current/installing-logstash.html https://www.elastic.co/guide/en/logstash/current/first-event.html https://www.elastic.co/guide/en/logstash/current/advanced-pipeline.html https://www.elastic.co/guide/en/logstash/current/pipeline.html https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html https://www.elastic.co/guide/en/logstash/current/plugins-filters-date.html 2、ELK中文 http://kibana.logstash.es/content/ http://kibana.logstash.es/content/logstash/plugins/filter/grok.html http://kibana.logstash.es/content/beats/file.html 3、用ELK搭建简单的日志收集分析系统 http://blog.csdn.net/lzw_2006/article/details/51280058 4、logstash host field is 0.0.0.0 http://www.v1en.com/2016/03/31/logstash-host-field-is-0-0-0-0/ 5、grok https://github.com/logstash-plugins/logstash-patterns-core/blob/master/patterns/grok-patterns http://grokconstructor.appspot.com/do/match