構(gòu)建基于Docker的ELK日志分析服務(wù)
通過(guò)構(gòu)建基于Docker的ELK日志分析服務(wù),進(jìn)一步增強(qiáng)對(duì)日志文件的分析、檢索能力

容器化部署
所謂ELK指的是ElasticSearch、Logstash、Kibana,其中ElasticSearch用于數(shù)據(jù)的存儲(chǔ)、檢索,Logstash用于數(shù)據(jù)的結(jié)構(gòu)化處理,Kibana則進(jìn)行可視化展示。這里直接通過(guò)Docker Compose搭建ELK服務(wù),值得一提的是需保證ElasticSearch、Logstash、Kibana各組件的版本完全一致
#?Compose?版本
version:?'3.8'
#?定義Docker服務(wù)
services:
??#?ElasticSearch?服務(wù)
??ElasticSearch-Service:
????build:
??????#?指定dockerfile的路徑
??????context:?./ESDockerFile
??????#?指定dockerfile的文件名
??????dockerfile:?Dockerfile
????#?設(shè)置dockerfile所構(gòu)建鏡像的名稱、tag
????image:?es-ik:7.12.0
????container_name:?ElasticSearch-Service
????ports:
??????-?9200:9200
??????-?9300:9300
????environment:
??????-?"ES_JAVA_OPTS=-Xms2g?-Xmx2g"
??????-?"discovery.type=single-node"
??????-?"TZ=Asia/Shanghai"
????volumes:
??????#?ES數(shù)據(jù)目錄
??????-?/Users/zgh/Docker/ELK/ES/data:/usr/share/elasticsearch/data
??????#?ES日志目錄
??????-?/Users/zgh/Docker/ELK/ES/logs:/usr/share/elasticsearch/logs
??#?Logstash?服務(wù)
??Logstash-Service:
????image:?logstash:7.12.0
????container_name:?Logstash-Service
????ports:
??????-?5044:5044
????environment:
??????-?"xpack.monitoring.enabled=false"
??????-?"TZ=Asia/Shanghai"
????volumes:
??????#?Logstash配置文件
??????-?/Users/zgh/Docker/ELK/Logstash/conf/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
??????#?自定義的索引模板文件
??????-?/Users/zgh/Docker/ELK/Logstash/conf/customTemplate.json:/usr/share/logstash/config/customTemplate.json
??????#?日志文件所在目錄
??????-?/Users/zgh/Docker/ELK/Logstash/LocalLog:/home/Aaron/LocalLog
????depends_on:
??????-?ElasticSearch-Service
??#?Kibana?服務(wù)
??Kibana-Service:
????image:?kibana:7.12.0
????container_name:?Kibana-Service
????ports:
??????-?5601:5601
????environment:
??????-?"ELASTICSEARCH_HOSTS=http://ElasticSearch-Service:9200"
??????-?"TZ=Asia/Shanghai"
????depends_on:
??????-?ElasticSearch-Service
同時(shí)為對(duì)中文分詞提供更好的支持,這里以ElasticSearch官方鏡像為基礎(chǔ)重新構(gòu)建安裝了ik分詞器的ES鏡像,Dockerfile如下所示
#?基礎(chǔ)鏡像環(huán)境:?ES?7.12.0
FROM?elasticsearch:7.12.0
#?切換目錄
WORKDIR?/usr/share/elasticsearch/plugins
#?安裝與ES版本相同的IK分詞器
RUN?elasticsearch-plugin?install?-b?\
??https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.0/elasticsearch-analysis-ik-7.12.0.zip
上述兩文件的相對(duì)路徑關(guān)系如下圖所示

Logstash
配置
Logstash作為一款主流的日志處理框架,通過(guò)提供形式多樣的插件極大地豐富了表現(xiàn)力。具體地,我們通過(guò)logstash.conf配置文件進(jìn)行配置。如下所示
input?{
??file?{
????#?容器下的日志路徑,?支持遞歸匹配路徑
????path?=>?"/home/Aaron/LocalLog/**/*.*"
????#?排除壓縮文件類型
????exclude?=>?["*.zip",?"*.7z",?"*.rar"]
????#?使用read模式,一方面每次都會(huì)從文件開(kāi)始處讀取,另一方面讀取完后會(huì)自動(dòng)刪除日志文件
????mode?=>?"read"
????
????#?文件塊大小, Unit:?字節(jié)。4194304字節(jié)?= 4MB
????file_chunk_size?=>?4194304
????
????#?檢查文件的頻率
????stat_interval?=>?"200?ms"
????#?發(fā)現(xiàn)新文件的頻率:?stat_interval?*?discover_interval
????discover_interval?=>?1
????#?合并多行數(shù)據(jù)
????codec?=>?multiline?{
??????#?正則表達(dá)式:?以時(shí)間信息開(kāi)頭
??????pattern?=>?"^%{TIMESTAMP_ISO8601}"
??????#?true:?否定正則表達(dá)式,?即如果不匹配的話
??????negate?=>?true
??????#?當(dāng)negate為true,?即正則表達(dá)式不匹配時(shí),?當(dāng)前日志歸屬于上一條日志
??????what?=>?"previous"
??????#?檢測(cè)多行的等待時(shí)間閾值,Unit:?s
??????auto_flush_interval?=>?1
????}
??}
}
filter?{
??#?解析日志進(jìn)行結(jié)構(gòu)化
??grok?{
????match?=>?{
??????"message"?=>?"%{TIMESTAMP_ISO8601:logtime}?%{LOGLEVEL:level}?%{WORD:componentId}\.%{WORD:segmentId}?\[%{DATA:threaad}\]?\[%{DATA:method}\]?%{GREEDYDATA:message}"
????}
????#?重寫(xiě)message字段
????overwrite?=>?["message"]
??}
??#?通過(guò)指定字段計(jì)算Hash值
??fingerprint?{
????method?=>?"MURMUR3"
????source?=>?["logtime",?"threaad",?"message"]
????concatenate_sources?=>?"true"
????target?=>?"[@metadata][fingerprint]"
??}
??#?給SQL日志打標(biāo)簽
??if?[message]?=~?"==>?.*"?or?[message]?=~?"<==?.*"?{
????mutate?{
??????#?對(duì)tags字段添加值
??????add_tag?=>?["SQL"]
????}
??}
??#?解析時(shí)間并轉(zhuǎn)存到?@timestamp?字段
??date?{
????#?logtime字段按ISO8601格式進(jìn)行解析
????match?=>?["logtime",?"ISO8601"]
????#?將解析后的時(shí)間存儲(chǔ)到給定的目標(biāo)字段
????target?=>?"@timestamp"
????#?刪除logtime字段
????remove_field?=>?["logtime"]
??}
??#?解析日志名稱并轉(zhuǎn)存到logFile字段
??mutate?{
????#?日志文件路徑按/切分
????split?=>?{?"path"?=>?"/"?}
????#?添加logFile日志文件名字段
????add_field?=>?{?"logFile"?=>?"%{[path][-1]}"?}
????#?刪除無(wú)用字段
????remove_field?=>?["host",?"@version",?"path"]
??}
}
output?{
??elasticsearch?{
????#?ES地址
????hosts?=>?["http://ElasticSearch-Service:9200"]
????#?索引名稱
????index?=>?"logstash-%{componentId}"
????#?將計(jì)算出的Hash值作為文檔ID
????document_id?=>?"%{[@metadata][fingerprint]}"
????#?使能模板管理模板
????manage_template?=>?true
????#?模板名稱
????template_name?=>?"custom_template"
????#?容器下的模板文件路徑
????template?=>?"/usr/share/logstash/config/customTemplate.json"
??}
??#?Only?For?Debug
??#?stdout?{
??#???codec??=>?rubydebug?{
??#?????#?是否輸出元數(shù)據(jù)字段
??#?????metadata?=>?true
??#???}
??#?}
}
Plugin
這里對(duì)上述配置文件所使用的各種插件進(jìn)行介紹
File
File作為Input Plugin輸入插件的一種,用于實(shí)現(xiàn)通過(guò)日志文件讀取日志信息。具體地
path:指定日志文件所在路徑,支持遞歸 mode:在read模式下,一方面每次都會(huì)從文件開(kāi)始處讀取,另一方面讀取完后會(huì)自動(dòng)刪除日志文件。這里由于我們處理的是靜態(tài)的日志文件,故非常適合使用read模式 exclude:根據(jù)文件名(非路徑)排除文件,這里選擇排除壓縮類型的文件 stat_interval:檢查文件更新的頻率 discover_interval:發(fā)現(xiàn)新文件的頻率,該值是stat_interval配置項(xiàng)的倍數(shù)
Multiline
通常日志都是單行的,但由于異常錯(cuò)誤的堆棧信息的存在,如下所示。日志中存在多行類型日志的可能性,故這里通過(guò)Codec Plugin編解碼插件中的Multiline進(jìn)行處理,將多行合并為一行
2021-08-12T17:42:31.850+08:00 ERROR hapddg.hapddgweb [http-nio-8080-exec-124] [c.a.t.common.e.GlobalExceptionHandler:49] unexpected exception
org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.append(OutputBuffer.java:746)
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:360)
... 109 common frames omitted
對(duì)于Multiline而言,其常見(jiàn)選項(xiàng)如下所示
pattern:正則表達(dá)式。上文配置中我們使用的模式為以時(shí)間信息開(kāi)頭 negate:是否對(duì)正則表達(dá)式的結(jié)果進(jìn)行否定。上文配置為true,即不匹配pattern配置項(xiàng)指定的正則表達(dá)式視為多行并進(jìn)行處理 what:其可選值有:previous、next。用于多行日志合并時(shí),當(dāng)前行視為歸屬于上一行還是下一行 auto_flush_interval:在處理當(dāng)前行時(shí)檢測(cè)多行的等待時(shí)間閾值(Unit: s)。該配置項(xiàng)無(wú)默認(rèn)值,故如果不顯式設(shè)置,則會(huì)發(fā)現(xiàn)處理日志文件時(shí),輸出結(jié)果會(huì)丟失最后一行日志
Grok
Filter Plugin過(guò)濾器插件中最重要的就屬Grok了,我們就是通過(guò)它進(jìn)行正則捕獲實(shí)現(xiàn)對(duì)日志數(shù)據(jù)的結(jié)構(gòu)化處理。Grok內(nèi)置定義了多種常見(jiàn)的正則匹配模式,以大大方便我們?nèi)粘5氖褂?。?duì)于內(nèi)置模式的使用語(yǔ)法如下,其中PATTERN_NAME為Grok內(nèi)置的匹配模式的名稱,并通過(guò)capture_name對(duì)捕獲的文本進(jìn)行命名。由于默認(rèn)情況下,捕獲結(jié)果都是保存為字符串類型,所以可以通過(guò)可選地data_type進(jìn)行類型轉(zhuǎn)換。但僅支持int、float兩種類型
#?語(yǔ)法格式
%{PATTERN_NAME:capture_name:data_type}
#?使用.*正則進(jìn)行捕獲,并以message命名
%{GREEDYDATA:message}
#?使用.*正則進(jìn)行捕獲,并以age命名,最后將數(shù)據(jù)類型轉(zhuǎn)換為int
%{GREEDYDATA:age:int}
對(duì)于內(nèi)置模式無(wú)法滿足的場(chǎng)景,Grok也支持用戶自定義正則進(jìn)行匹配。語(yǔ)法格式及示例如下。其中reg_exp為正則表達(dá)式
#?語(yǔ)法格式
(?reg_exp)
#?使用.*正則進(jìn)行捕獲,并以message命名
(?.*)
這里就Grok中內(nèi)置的常見(jiàn)模式進(jìn)行介紹
TIMESTAMP_ISO8601:匹配ISO8601格式的時(shí)間。例如:2021-08-12T17:33:47.498+08:00 LOGLEVEL:匹配日志級(jí)別 WORD: 匹配字符串,包括數(shù)字、大小寫(xiě)字母、下劃線 DATA、GREEDYDATA:從這兩個(gè)模式的正則表達(dá)式.*?和.*就可以看出,后者是前者的貪婪模式版本
現(xiàn)在我們就可以利用Grok處理日志了,假設(shè)一條日志的格式如下所示
2021-08-12T17:33:47.498+08:00?INFO?hapddg.hapddgweb?[ActiveMQ?Session?Task-483]?[c.a.s.h.EventHandler:187]?add?event?message?to?queue
直接利用Grok內(nèi)置的模式對(duì)上述日志格式進(jìn)行結(jié)構(gòu)化處理,如下所示。其中match配置項(xiàng)用于定義待匹配的字段、匹配方式。與此同時(shí),由于已經(jīng)將message中所有信息均捕獲到各個(gè)字段了。為避免重復(fù)存儲(chǔ),我們可以通過(guò)overwrite重寫(xiě)默認(rèn)的message字段
#?解析日志進(jìn)行結(jié)構(gòu)化
grok?{
??match?=>?{
????"message"?=>?"%{TIMESTAMP_ISO8601:logtime}?%{LOGLEVEL:level}?%{WORD:componentId}\.%{WORD:segmentId}?\[%{DATA:threaad}\]?\[%{DATA:method}\]?%{GREEDYDATA:message}"
??}
??#?重寫(xiě)message字段
??overwrite?=>?["message"]
}
Fingerprint
Fingerprint同樣是一種Filter Plugin,其通過(guò)指定字段計(jì)算出一個(gè)指紋值。后續(xù)我們會(huì)將計(jì)算出的指紋值作為文檔ID,來(lái)實(shí)現(xiàn)重復(fù)文檔的去重
method:指定計(jì)算指紋信息的算法,支持SHA1、SHA256、SHA384、SHA512、MD5、MURMUR3等。這里我們選用MURMUR3,其作為一種非加密型哈希算法,由于計(jì)算快、碰撞低等特點(diǎn)被廣泛應(yīng)用于哈希檢索等場(chǎng)景 source:利用哪些字段計(jì)算指紋信息 concatenate_sources:計(jì)算指紋前是否將source配置項(xiàng)指定的所有字段的名稱、值拼接為一個(gè)字符串,默認(rèn)值為false。如果為false,則將只會(huì)使用source配置項(xiàng)中指定的最后一個(gè)字段進(jìn)行指紋信息計(jì)算。故這里需要顯式設(shè)為true target:設(shè)置存儲(chǔ)指紋值的字段名。這里使用了元數(shù)據(jù)字段
Logstash從1.5版本開(kāi)始提供了一種特殊字段——@metadata元數(shù)據(jù)字段。@metadata中的內(nèi)容不會(huì)對(duì)外進(jìn)行輸出(特殊條件下可以通過(guò)某種方式進(jìn)行輸出以便于調(diào)試)。故非常適合在Logstash DSL中作為臨時(shí)字段使用。否則如果使用普通字段存儲(chǔ)中間結(jié)果,還需要通過(guò)remove_field進(jìn)行刪除以避免對(duì)外輸出。使用元數(shù)據(jù)字段也很簡(jiǎn)單,如果期望使用一個(gè)名為tempData1的元數(shù)據(jù)字段。則字段名即為[@metadata][tempData1]。當(dāng)然其同樣支持字段引用,通過(guò)[@metadata][tempData1]直接即可訪問(wèn),而在字符串中的則可以通過(guò)%{[@metadata][tempData1]}方式進(jìn)行字段引用。關(guān)于元字段的使用示例如下所示
filter{
??mutate?{
????#?將message字段的值?存儲(chǔ)到?[@metadata][tempData1]?字段中
????add_field?=>?{?"[@metadata][tempData1]"?=>?"%{[message]}"?}
????#?將?[@metadata][tempData1]?字段的值?存儲(chǔ)到?outdata2?字段中
????add_field?=>?{?"outdata2"?=>?"%{[@metadata][tempData1]}"?}
??}
}
Mutate
Filter Plugin中的Mutate則可以對(duì)字段進(jìn)行修改,包括但不限于split、join、rename、lowercase等操作。但需要注意的是在一個(gè)Mutate塊內(nèi)各操作不是按書(shū)寫(xiě)的順序執(zhí)行的,而是根據(jù)Mutate Plugin內(nèi)部某種固定的預(yù)設(shè)順序依次執(zhí)行的。故如果期望控制各操作的執(zhí)行順序,可以定義多個(gè)Mutate塊。因?yàn)楦鱉utate塊的執(zhí)行順序是按書(shū)寫(xiě)順序依次進(jìn)行的。這里我們利用split對(duì)日志文件的path字段按路徑分隔符進(jìn)行切分,并通過(guò)下標(biāo)-1訪問(wèn)數(shù)組中的最后一個(gè)元素取得日志文件名稱,最后對(duì)原path字段進(jìn)行刪除
而對(duì)于各種不同類型的日志,我們期望能夠進(jìn)行分類、打標(biāo)簽。這樣便于后續(xù)在檢索日志時(shí)更加高效。具體地,對(duì)于SQL類型的日志而言,其結(jié)構(gòu)特征為"==>"、"<=="開(kāi)頭。如下所示
2021-08-17T16:33:11.958+08:00 DEBUG hapddg.hapddgweb [http-nio-8080-exec-1] [c.a.t.m.a.A.deleteData:143] ==> Preparing: delete from tb_person where id in ( ? , ? , ? )
2021-08-17T16:44:11.958+08:00 DEBUG hapddg.hapddgweb [http-nio-8080-exec-1] [c.a.t.m.a.A.deleteData:143] ==> Parameters: 22(Integer), 47(Integer), 60(Integer)
2021-08-17T16:55:11.959+08:00 DEBUG hapddg.hapddgweb [http-nio-8080-exec-1] [c.a.t.m.a.A.deleteData:143] <== Updates: 3
這樣即可結(jié)合Logstash條件判斷語(yǔ)句、Mutate的add_tag操作實(shí)現(xiàn)對(duì)SQL日志打標(biāo)簽,其中值為"SQL"。此外Logstash還提供了 =~、!~ 運(yùn)算符分別用于匹配正則、不匹配正則
#?給SQL日志打標(biāo)簽
if?[message]?=~?"==>?.*"?or?[message]?=~?"<==?.*"?{
??mutate?{
????#?對(duì)tags字段添加值
????add_tag?=>?["SQL"]
??}
}
Date
由于Logstash輸出的@timestamp字段值默認(rèn)為其處理日志文件過(guò)程的當(dāng)前時(shí)間,故這里我們需要將日志中記錄的時(shí)間信息寫(xiě)入@timestamp字段,以便后續(xù)的搜索。這里選擇Filter Plugin中的Date實(shí)現(xiàn)對(duì)于時(shí)間字符串的解析處理
match:指定時(shí)間字段及其對(duì)應(yīng)的時(shí)間格式。其中,支持的時(shí)間格式有:ISO8601(例如:2021-08-17T16:55:11.959+08:00)、UNIX(Unix紀(jì)元以來(lái)的秒數(shù))、UNIX_MS(Unix紀(jì)元以來(lái)的毫秒數(shù))等 target:存儲(chǔ)解析后時(shí)間信息的字段
Elasticsearch
當(dāng)Logstash完成日志的結(jié)構(gòu)化處理后,即可輸出到ElasticSearch。這里直接選擇Elasticsearch Plugin即可。如下所示,這里我們指定了ES的地址、索引、文檔ID等信息。同時(shí)還在其中定義了一個(gè)名為custom_template的ES索引模板
elasticsearch?{
??#?ES地址
??hosts?=>?["http://ElasticSearch-Service:9200"]
??#?索引名稱
??index?=>?"logstash-%{componentId}"
??#?將計(jì)算出的Hash值作為文檔ID
??document_id?=>?"%{[@metadata][fingerprint]}"
??#?使能模板管理模板
??manage_template?=>?true
??#?模板名稱
??template_name?=>?"custom_template"
??#?容器下的模板文件路徑
??template?=>?"/usr/share/logstash/config/customTemplate.json"
}
Rubydebug
前面提到默認(rèn)情況下,元數(shù)據(jù)字段不會(huì)進(jìn)行輸出。但實(shí)際上在調(diào)試過(guò)程中可以通過(guò)Codec Plugin編解碼插件中的Rubydebug使能輸出元數(shù)據(jù)字段。下面即是在一個(gè)標(biāo)準(zhǔn)輸出Stdout中包含元數(shù)據(jù)字段輸出的示例
stdout?{
??codec??=>?rubydebug?{
????#?是否輸出元數(shù)據(jù)字段?
????metadata?=>?true
??}
}
Index Template索引模板
在Logstash的DSL配置文件中我們通過(guò)Elasticsearch Plugin定義了一個(gè)ES索引模板,并且通過(guò)template字段指定在Logstash容器下的索引模板文件路徑。具體地,索引模板文件customTemplate.json的內(nèi)容如下所示
{
??"index_patterns"?:?"logstash-*",
??"order":?20,
??"settings":{
????"index.refresh_interval":?"1s",
????"index.number_of_replicas":?0,
????"index.lifecycle.name":?"autoRemoveOldData"
??},
??"mappings":{
????"properties"?:?{
??????"@timestamp"?:?{
????????"type"?:?"date"
??????},
??????"level"?:?{
????????"type"?:?"keyword",
????????"norms"?:?false
??????},????????
??????"componentId"?:?{
????????"type"?:?"keyword",
????????"norms"?:?false
??????},
??????"segmentId"?:?{
????????"type"?:?"keyword",
????????"norms"?:?false
??????},
??????"threaad"?:?{
????????"type"?:?"text",
????????"fields"?:?{
??????????"keyword"?:?{
????????????"type"?:?"keyword",
????????????"ignore_above"?:?556
??????????}
????????},
????????"norms"?:?false
??????},
??????"method"?:?{
????????"type"?:?"text",
????????"fields"?:?{
??????????"keyword"?:?{
????????????"type"?:?"keyword",
????????????"ignore_above"?:?556
??????????}
????????},
????????"norms"?:?false
??????},
??????"message"?:?{
????????"type"?:?"text",
????????"analyzer":?"ik_max_word"
??????},
??????"logFile"?:?{
????????"type":?"text",
????????"index"?:?false
??????},
??????"tags"?:?{
????????"type"?:?"keyword",
????????"norms"?:?false
??????}
????}???
??}
}
部分配置項(xiàng)說(shuō)明如下:
index_patterns:該模板匹配索引名稱的通配符表達(dá)式 order:優(yōu)先級(jí),值越大優(yōu)先級(jí)越高 index.refresh_interval:索引的刷新時(shí)間間隔 index.number_of_replicas:每個(gè)主分片的副本數(shù) index.lifecycle.name:ILM索引生命周期中的策略名稱
至此,ELK服務(wù)中的兩個(gè)關(guān)鍵性配置文件均已介紹完畢,其在宿主機(jī)下的相關(guān)層次結(jié)構(gòu)如下所示

Kibana
本地化
通過(guò)Docker Compose創(chuàng)建、啟動(dòng)ELK服務(wù)所需的各容器。進(jìn)入Kibana容器,修改/usr/share/kibana/config路徑下的配置文件kibana.yml,增加 i18n.locale: "zh-CN" 配置項(xiàng)

修改完畢后,重啟Kibana容器。然后通過(guò) http://localhost:5601 訪問(wèn)Kibana的Web頁(yè)面??梢钥吹剑?yè)面語(yǔ)言已經(jīng)被修改為中文

個(gè)性化配置
點(diǎn)擊【Management】下的【Stack Management】,然后進(jìn)入【高級(jí)設(shè)置】進(jìn)行個(gè)性化修改、并保存。具體地:
將日期的顯示格式修改為YYYY-MM-DD HH:mm:ss.SSS,并且將Monday周一作為一周的開(kāi)始

去除不必要的元字段展示,僅保留 _source, _id, _index 字段

將各種通知信息的保留時(shí)間設(shè)為5秒

ILM索引生命周期管理
在上文的customTemplate.json索引模板文件中,我們通過(guò)index.lifecycle.name配置項(xiàng)定義、關(guān)聯(lián)了一個(gè)名為autoRemoveOldData的ILM策略??赏ㄟ^(guò)【Management】-【Stack Management】-【索引管理】-【索引模板】查看,如下所示

現(xiàn)在我們來(lái)創(chuàng)建該策略,通過(guò)【Management】-【開(kāi)發(fā)工具】-【控制臺(tái)】發(fā)送如下的PUT請(qǐng)求即可
#?創(chuàng)建名為autoRemoveOldData的策略:自動(dòng)刪除超過(guò)20天的索引
PUT?_ilm/policy/autoRemoveOldData?pretty
{
??"policy":?{
????"phases":?{
??????"hot":?{
????????"min_age":?"0",
????????"actions":?{}
??????},
??????"delete":?{
????????"min_age":?"20d",
????????"actions":?{
??????????"delete":?{
????????????"delete_searchable_snapshot":?true
??????????}
????????}
??????}
????}
??}
}
效果如下所示

通過(guò)【Management】-【Stack Management】-【索引生命周期策略】查看,可以看到相應(yīng)的ILM策略已經(jīng)創(chuàng)建成功

建立索引模式
現(xiàn)在,將我們用于測(cè)試的日志文件aaron.log放入LocalLog目錄下,已便讓ELK分析日志

其中測(cè)試的日志文件aaron.log的內(nèi)容如下所示
2021-08-12T17:33:47.498+08:00 INFO hapddg.hapddgweb [ActiveMQ Session Task-483] [c.a.s.h.EventHandler:187] add event message to queue
2021-08-12T17:42:31.850+08:00 ERROR hapddg.hapddgweb [http-nio-8080-exec-124] [c.a.t.common.e.GlobalExceptionHandler:49] unexpected exception
org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.append(OutputBuffer.java:746)
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:360)
... 109 common frames omitted
2021-08-12T18:22:01.959+08:00 INFO hapddg.hapddgweb [http-nio-8080-exec-137] [c.a.t.s.CallBackServiceImpl:71] sublist is empty
2021-08-12T18:25:02.146+08:00 DEBUG hapddg.hapddgweb [http-nio-8080-exec-135] [c.a.t.s.CallBackServiceImpl:72] query down result is ok
2021-08-12T18:29:02.356+08:00 INFO hapddg.hapddgweb [http-nio-8080-exec-137] [c.a.t.s.CallBackServiceImpl:73] start task
2021-08-17T16:33:11.958+08:00 DEBUG hapddg.hapddgweb [http-nio-8080-exec-1] [c.a.t.m.a.A.deleteData:143] ==> Preparing: delete from tb_person where id in ( ? , ? , ? )
2021-08-17T16:44:11.958+08:00 DEBUG hapddg.hapddgweb [http-nio-8080-exec-1] [c.a.t.m.a.A.deleteData:143] ==> Parameters: 22(Integer), 47(Integer), 60(Integer)
2021-08-17T16:55:11.959+08:00 DEBUG hapddg.hapddgweb [http-nio-8080-exec-1] [c.a.t.m.a.A.deleteData:143] <== Updates: 3
當(dāng)ELK讀取完日志文件后會(huì)自動(dòng)將其進(jìn)行刪除,同時(shí)通過(guò)【Management】-【Stack Management】-【索引管理】-【索引】可以查看相應(yīng)的索引、文檔已經(jīng)建立完畢

通過(guò)【Management】-【Stack Management】-【索引模式】來(lái)建立索引模式

定義索引模式的名稱為 logstash-*

同時(shí)將 @timestamp 字段作為全局時(shí)間篩選的時(shí)間字段

實(shí)踐
只需第一次在Kibana中建立好索引模式即可,后續(xù)無(wú)需再次重復(fù)建立?,F(xiàn)在通過(guò)【Analytics】-【Discover】即可進(jìn)行日志的檢索,效果如下所示

Note
Docker掛載Volume
掛載Volume前,一方面需要提前在宿主機(jī)下創(chuàng)建相應(yīng)的目錄、文件;另一方面需要將其加入Docker的File Sharing配置中,由于File Sharing對(duì)所配置目錄的子目錄同樣會(huì)生效,故一般只需將父目錄加入即可。設(shè)置方法如下所示

特別地,在Windows系統(tǒng)下掛載Volume時(shí),需要注意路徑的寫(xiě)法。例如,Windows系統(tǒng)的路徑 D:\Docker\ELK 應(yīng)該寫(xiě)為 /D/Docker/ELK
查看Logstash Plugin版本信息
進(jìn)入Logstash容器后,可通過(guò)執(zhí)行如下命令查看Logstash中各Plugin的版本信息
#?查看Logstash?Plugin版本信息
/usr/share/logstash/bin/logstash-plugin?list?--verbose
調(diào)試Logstash Filter
對(duì)于Logstash DSL中的Filter Plugin,可通過(guò)創(chuàng)建一個(gè)臨時(shí)的Logstash容器進(jìn)行調(diào)試。具體地,輸入、輸出分別使用標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出,過(guò)濾器則為待調(diào)試的Filter DSL。示例如下
docker?run?--rm?-it?logstash:7.12.0??\
??--path.settings=?-e?'
??#?使用標(biāo)準(zhǔn)輸入
??input?{?
????stdin?{}?
??}
??#?待調(diào)試的Filter?DSL
??filter?{????
????mutate?{
??????#?按/進(jìn)行切分
??????split?=>?{?"message"?=>?"/"?}
??????#?取message數(shù)組最后一個(gè)元素值賦給新增字段logFile
??????add_field?=>?{?"logFile"?=>?"%{[message][-1]}"?}
????}
??}
??#?使用標(biāo)準(zhǔn)輸出
??output?{?
?????stdout?{}
??}
'
其中,選項(xiàng)說(shuō)明如下:
rm:容器退出后自動(dòng)被刪除 it:為容器分配一個(gè)偽輸入終端,并保持容器的標(biāo)準(zhǔn)輸入打開(kāi)
調(diào)試效果如下所示

調(diào)試Grok
特別地,對(duì)于Filter Plugin中的Grok而言,Kibana還專門(mén)提供了一個(gè)在線調(diào)試工具——Grok Debugger。通過(guò)【Management】-【開(kāi)發(fā)工具】-【Grok Debugger】進(jìn)入即可使用,效果如下所示

參考文獻(xiàn)
Grok內(nèi)置模式的正則表達(dá)式:https://github.com/logstash-plugins/logstash-patterns-core/blob/main/patterns/legacy/grok-patterns ElasticSearch 7.12版官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/7.12/index.html Logstash 7.12版官方文檔:https://www.elastic.co/guide/en/logstash/7.12/index.html
