ELK的安装部署已是第N次了! 其实也很简单,这里记下来,以避免忘记。html
#elasticsearch安装部署 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.0.1.tar.gz tar -zxvf elasticsearch-6.0.1.tar.gz cd elasticsearch-6.0.1 #配置。 以下 集群名称;节点名称;供外网访问的ip(xxx.xxx.xxx.xxx或0.0.0.0);端口(注意空格) vi config/elasticsearch.yml cluster.name: my-application node.name: node-1 network.host: ip http.port: 9200
修改系统参数:
echo "* soft nofile 65536
* hard nofile 65536" >> /etc/security/limits.confjava
echo "vm.max_map_count=262144" >> /etc/sysctl.confnode
#启动 useradd es # 须要非root 用户 su es ./bin/elasticsearch -d # ./elasticsearch -q 关闭 exit
cd .. #访问 curl ip:9200 #kibana安装部署 wget https://artifacts.elastic.co/downloads/kibana/kibana-6.0.1-linux-x86_64.tar.gz tar -zxvf kibana-6.0.1-linux-x86_64.tar.gz cd kibana-6.0.1 vi config/kibana.yml #配置信息 服务端口;kibana服务ip;es的外网访问ip;index server.port: 5601 server.host: "0.0.0.0" elasticsearch.url: "http://xxx.xxx.xxx.xxx:9200" # 注意ip、url不能使用localhost、127.0.0.1, 必须使用实际的ip!!! kibana.index: ".kibana" #启动 nohup ./bin/kibana &
cd .. #访问 curl ip:5601 #Logstash安装部署 wget https://artifacts.elastic.co/downloads/logstash/logstash-6.0.1.tar.gz tar -zxvf logstash-6.0.1.tar.gz cd logstash-6.0.1 #配置 vi logstash-6.0.1/config/logs_to_es.conf input { file { type => "tomcat-catalina" path => "/opt/apps/apache-tomcat7/logs/catalina.log" codec => multiline { pattern => "^\s" what => "previous" } } } filter { #Only matched data are send to output. } output { elasticsearch { action => "index" #The operation on ES hosts => "xxx.xxx.xxx.xxx:9200" #ElasticSearch host, can be array. index => "tomcat_log" #The index to write data to. } } #启动 nohup ./bin/logstash -f config/logs_to_es.conf &
cd .. 测试: # Logstash管道测试代码 bin/logstash -e 'input{stdin {}} output{stdout{}}' # 参考 https://blog.csdn.net/zhaojiweiwin/article/details/80281525
上面的脚本,只要把vi 部分换成sed -i 或相似免交互的命令,那么实际上是能够一键 快速完成ELK的安装部署。 须要注意的是 ip 是不能使用localhost 或 127.0.0.1的, 而是须要实际的ip。须要注意的是,es启动以前须要设置一下linux系统的一些参数: /etc/security/limits.conf, /etc/sysctl.conf,不然会启动报错。至于为何,我以为多是es须要打开不少不少的文件句柄。 nofile实际上是最大可以打开的文件数,跟ulimit -n含义差很少,可是经过ulimit -n设置是临时的,经过/etc/security/limits.conf设置才是永久的;max_map_count 是虚拟内存映射,是容许一个进程在VMAs(虚拟内存区域)拥有最大数量,VMA是一个连续的虚拟地址空间,当进程建立一个内存映像文件时VMA的地址空间就会增长,当达到max_map_count了就是返回out of memory errors。它也能够经过sysctl -w进行设置,可是也是临时的,须要写入 /etc/sysctl.conf才是永久的。linux
固然,上面的logstash 的配置文件是很示例的,可能不够。 我实际上使用的是下面的配置:正则表达式
input { file { type => "erdp-rc" #path => "/app/java/logs/nohup-erdp_${WORD:app}-*.log" path => "/app/java/logs/nohup-erdp_*.log" #add_field => {"app2"=>"aa"} codec => multiline { pattern => "^%{TIMESTAMP_ISO8601}" negate => true what => "previous" } } } filter { #Only matched data are send to output. grok { # match => { "message" => "%{TIMESTAMP_ISO8601:timestamp}\s? %{LOGLEVEL:level} %{INT:pid} --- \[%{URIPATHPARAM:thread}\] %{NOTSPACE:clz}\s+: %{GREEDYDATA:msg}" } match => { "message" => "%{TIMESTAMP_ISO8601:timestamp}\s? %{LOGLEVEL:level} %{INT:pid} --- \[%{NOTSPACE:thread}\] %{NOTSPACE:clz}\s+: %{GREEDYDATA:msg}" } } grok {
# match => ["path","%{GREEDYDATA}/nohup-erdp_%{WORD:appName}_%{GREEDYDATA}\.log"] match => ["path","%{GREEDYDATA}/nohup-erdp_(?<appName>[a-zA-Z0-9.-]+)_%{DATA}\.log"] } # date { # match => [ "timestamp" , "YYYY-MM-dd HH:mm:ss.SSS" ] # } } output { elasticsearch { action => "index" #The operation on ES hosts => "192.168.11.183:9200" #ElasticSearch host, can be array. index => "erdp_log" #The index to write data to. } }
上面的两个grok 花了我很多时间。有些蛋疼。grok确实是个麻烦的玩意,每次都要折腾一番。 由于 Logstash不方便调试,须要修改conf,而后重启,而后操做,而后等待日志输出到elk,而后kibana上面观察。观察不到呢, 还要怀疑是不是本身的查询条件写错了,各类修改、折腾。这样的一次手动调试下来须要2-6分钟。 在线的grok debugger又用不了。 真是麻烦。apache
如上,能够看到 URIPATHPARAM 用来匹配线程 thread 就出问题了! 开始一直没怀疑。为何URIPATHPARAM 不行,而NOTSPACE 就能够呢?以下
tomcat
URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\-]*)+ #URIPARAM \?(?:[A-Za-z0-9]+(?:=(?:[^&]*))?(?:&(?:[A-Za-z0-9]+(?:=(?:[^&]*))?)?)*)? URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]]* URIPATHPARAM %{URIPATH}(?:%{URIPARAM})?
我感受是匹配到 URIPATHPARAM 后面的就出问题了,可是Logstash 没有报错。 因此,问题一直排查不出来。app
另外,须要经过文件名, 找到对应的应用,添加一个app_name 的字段,搞了很久啊。curl
最开始的时候想经过input-file-add_field 插件添加进来,发现input-file 的path 没法使用分组,没法将文件名读取到,其余通配符也无效。。elasticsearch
搜索“logstash path 添加字段” ,不行。 后面搜索“logstash get the file name as field”终于找到了
https://stackoverflow.com/questions/23780000/use-grok-to-add-the-log-filename-as-a-field-in-logstash
https://stackoverflow.com/questions/22916200/logstash-how-to-add-file-name-as-a-field
(其实以前找到了 http://www.voidcn.com/article/p-rueddyth-btd.html, 可是以为这样效率低,我就想经过add_field,而不想经过grok 的方式)
后面明白,只能经过grok 的方式了! 仔细想一想, 其实grok 的方式的效率应该是也是差很少的。
另外注意到 filter的 grok 是能够多个的, input 的file 其实也能够多个并行。
可是,我须要经过log文件名再截取一段,appName, 发现 %{WORD:appName}, 发现死活不行,或时好时坏, 后面改为 [a-zA-Z0-9.-]+), 就终于好了!浪费一两个小时时间啊!
仔细检查,原来啊, WORD 是必须有边界的!——> WORD \b\w+\b 。 我开始还在怀疑 自定义的 grok 语法是否是搞错了呢! --> (?<field>regex) , 后面又怀疑GREEDYDATA是否是应该改成DATA。 其实都不是的。
附常见的内置的gork 正则表达式:
USERNAME [a-zA-Z0-9._-]+ USER %{USERNAME} INT (?:[+-]?(?:[0-9]+)) BASE10NUM (?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))) NUMBER (?:%{BASE10NUM}) BASE16NUM (?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+)) BASE16FLOAT \b(?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]*)?)|(?:\.[0-9A-Fa-f]+)))\b POSINT \b(?:[1-9][0-9]*)\b NONNEGINT \b(?:[0-9]+)\b WORD \b\w+\b NOTSPACE \S+ SPACE \s* DATA .*? GREEDYDATA .* QUOTEDSTRING (?>(?<!\\)(?>”(?>\\.|[^\\"]+)+”|”"|(?>’(?>\\.|[^\\']+)+’)|”|(?>(?>\\.|[^\]+)+)|`)) UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12} MAC (?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC}) IPV4 (?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9]) IP (?:%{IPV6}|%{IPV4}) HOSTNAME \b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\.?|\b) HOST %{HOSTNAME} IPORHOST (?:%{HOSTNAME}|%{IP}) HOSTPORT (?:%{IPORHOST=~/\./}:%{POSINT}) # Years? YEAR (?>\d\d){1,2} HOUR (?:2[0123]|[01]?[0-9]) MINUTE (?:[0-5][0-9]) # ’60′ is a leap second in most time standards and thus is valid. SECOND (?:(?:[0-5][0-9]|60)(?:[:.,][0-9]+)?) TIME (?!<[0-9])%{HOUR}:%{MINUTE}(?::%{SECOND})(?![0-9]) # datestamp is YYYY/MM/DD-HH:MM:SS.UUUU (or something like it) DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR} DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR} ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE})) ISO8601_SECOND (?:%{SECOND}|60) TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}? DATE %{DATE_US}|%{DATE_EU} DATESTAMP %{DATE}[- ]%{TIME} TZ (?:[PMCE][SD]T|UTC) DATESTAMP_RFC822 %{DAY} %{MONTH} %{MONTHDAY} %{YEAR} %{TIME} %{TZ} DATESTAMP_OTHER %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{TZ} %{YEAR} # Log Levels LOGLEVEL ([A-a]lert|ALERT|[T|t]race|TRACE|[D|d]ebug|DEBUG|[N|n]otice|NOTICE|[I|i]nfo|INFO|[W|w]arn?(?:ing)?|WARN?(?:ING)?|[E|e]rr?(?:or)?|ERR?(?:OR)?|[C|c]rit?(?:ical)?|CRIT?(?:ICAL)?|[F|f]atal|FATAL|[S|s]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?)
参考