作為一個(gè)日志中心娃属,它會(huì)收集各種各樣的日志六荒,可以用于問(wèn)題排查,數(shù)據(jù)監(jiān)控矾端,統(tǒng)計(jì)分析等等掏击。那么對(duì)于繁多的日志,它們都有各自的存儲(chǔ)格式秩铆,我們?nèi)绾蝸?lái)區(qū)分它們砚亭,對(duì)于不同的日志格式,我們又是如何去解析的呢?
一長(zhǎng)串沒(méi)有結(jié)構(gòu)化的日志钠惩,給人的感覺(jué)很凌亂柒凉。我們需要的是提取日志中的有效字段,并以我們期望的形式進(jìn)行展現(xiàn)篓跛。下面我將和大家一起來(lái)探究日志解析的奧秘膝捞。
原理
依照前文,使用filebeat來(lái)上傳日志數(shù)據(jù)愧沟,logstash進(jìn)行日志收集與處理蔬咬,elasticsearch作為日志存儲(chǔ)與搜索引擎,最后使用kibana展現(xiàn)日志的可視化輸出沐寺。所以不難發(fā)現(xiàn)林艘,日志解析主要還是logstash做的事情。
說(shuō)到logstash混坞,它到底有哪些東西呢狐援?我們來(lái)簡(jiǎn)單看下:
從上圖中可以看到,logstash主要包含三大模塊:
- INPUTS: 收集所有數(shù)據(jù)源的日志數(shù)據(jù)([源有file究孕、redis啥酱、beats等,filebeat就是使用了beats源*)厨诸;
- FILTERS: 解析镶殷、整理日志數(shù)據(jù)(本文重點(diǎn));
- OUTPUTS: 將解析的日志數(shù)據(jù)輸出至存儲(chǔ)器([elasticseach微酬、file绘趋、syslog等);
看來(lái)FILTERS是我們探究的重點(diǎn)颗管,先來(lái)來(lái)看看它常用到的幾個(gè)插件(后面日志解析會(huì)用到):
- grok:采用正則的方式陷遮,解析原始日志格式,使其結(jié)構(gòu)化忙上;
- geoip:根據(jù)IP字段拷呆,解析出對(duì)應(yīng)的地理位置、經(jīng)緯度等疫粥;
- date:解析選定時(shí)間字段茬斧,將其時(shí)間作為logstash每條記錄產(chǎn)生的時(shí)間(若沒(méi)有指定該字段,默認(rèn)使用read line的時(shí)間作為該條記錄時(shí)間)梗逮;
*注意:codec也是經(jīng)常會(huì)使用到的项秉,它主要作用在INPUTS和OUTPUTS中,[提供有json的格式轉(zhuǎn)換慷彤、multiline的多行日志合并等
場(chǎng)景
說(shuō)了這么多娄蔼,到底怎么用呢怖喻?我們還是通過(guò)幾個(gè)例子,具體來(lái)看看是怎么實(shí)現(xiàn)的吧岁诉。
秉承先易后難的原則锚沸,希望大家全部看完后,對(duì)以后遇到更復(fù)雜的日志涕癣,也能處理的游刃有余哗蜈。
1. NodeJS 日志
- 日志格式
$time - $remote_addr $log_level $path - $msg
- 日志內(nèi)容
2017-03-15 18:34:14.535 - 112.65.171.98 INFO /root/ws/socketIo.js - xxxxxx與ws server斷開(kāi)連接
- filebeat配置(建議filebeat使用rpm安裝,以systemctl start filebeat方式啟動(dòng))
filebeat:
prospectors:
- document_type: nodejs #申明type字段為nodejs坠韩,默認(rèn)為log
paths:
- /var/log/nodejs/log #日志文件地址
input_type: log #從文件中讀取
tail_files: true #以文件末尾開(kāi)始讀取數(shù)據(jù)
output:
logstash:
hosts: ["${LOGSTASH_IP}:5044"]
#General Setting
name: "server1" #設(shè)置beat的名稱距潘,默認(rèn)為主機(jī)hostname
- logstash中FILTERS配置
filter {
if [type] == "nodejs" { #根據(jù)filebeat中設(shè)置的type字段,來(lái)過(guò)濾不同的解析規(guī)則
grok{
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} - %{IPORHOST:clientip} %{LOGLEVEL:level} %{PATH:path} - %{GREEDYDATA:msg}" }
}
geoip {
source => "clientip" #填寫IP字段
}
}
}
- 結(jié)果(為方便演示只搁,數(shù)據(jù)有刪減)
-
Filter配置講解
- grok中的match內(nèi)容:
- key:表示所需解析的內(nèi)容音比;
- value:表示解析的匹配規(guī)則,提取出對(duì)應(yīng)的字段氢惋;
- 解析語(yǔ)法:%{正則模板:自定義字段}洞翩,其中TIMESTAMP_ISO8601、IPORHOST等都是grok提供的正則模板焰望;
- geoip:通過(guò)分析IP值菱农,產(chǎn)生IP對(duì)應(yīng)的地理位置信息;
這里是否發(fā)現(xiàn)@timestamp與timestamp不一致柿估,@timestamp表示該日志的讀取時(shí)間,在elasticsearch中作為時(shí)間檢索索引陷猫。下面講解Nginx日志時(shí)秫舌,會(huì)去修正這一問(wèn)題。
- grok中的match內(nèi)容:
2. Nginx 訪問(wèn)日志
- 日志格式
$remote_addr - $remote_user [$time_local]
"$request" $status $body_bytes_sent "$http_referer"
"$http_user_agent" "$http_x_forwarded_for"
- 日志內(nèi)容
112.65.171.98 - - [15/Mar/2017:18:18:06 +0800] "GET /index.html HTTP/1.1" 200 1150 "http://www.yourdomain.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36" "-"
- filebeat中prospectors的配置
- document_type: nginx
paths:
- /var/log/nginx/access.log #日志文件地址
input_type: log #從文件中讀取
tail_files: true #以文件末尾開(kāi)始讀取數(shù)據(jù)
- logstash中FILTERS配置
filter {
if [type] == "nginx" {
grok{
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
date {
match => [ "timestamp" , "dd/MMM/yyyy:HH:mm:ss Z", "ISO8601" ]
target => "@timestamp" #可省略
}
}
}
-
結(jié)果
-
Filter配置講解
- grok:
- 是不是很不可思議绣檬,上一示例中我們匹配規(guī)則寫了一長(zhǎng)串足陨,這個(gè)僅僅一個(gè)COMBINEDAPACHELOG就搞定了!
- grok除了提供上面那種基礎(chǔ)的正則規(guī)則娇未,還對(duì)常用的日志(java,http,syslog等)提供的相應(yīng)解析模板墨缘,本質(zhì)還是那么一長(zhǎng)串正則,[詳情見(jiàn)grok的120中正則模板零抬;
- date:
- match:數(shù)組中第一個(gè)值為要匹配的時(shí)間字段镊讼,后面的n個(gè)是匹配規(guī)則,它們的關(guān)系是or的關(guān)系平夜,滿足一個(gè)即可蝶棋;
- target:將match中匹配的時(shí)間替換該字段,默認(rèn)替換@timestamp忽妒;
目前為止我們解析的都是單行的日志玩裙,向JAVA這樣的兼贸,若果是多行的日志我們又該怎么做呢?
- grok:
3. JAVA Log4j 日志
- 日志內(nèi)容
'2017-03-16 15:52:39,580 ERROR TestController:26 - test:
java.lang.NullPointerException
at com.test.TestController.tests(TestController.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)'
- filebeat中prospectors的配置
- document_type: tomcat
paths:
- /var/log/java/log #日志文件地址
input_type: log #從文件中讀取
tail_files: true #以文件末尾開(kāi)始讀取數(shù)據(jù)
multiline:
pattern: ^\d{4}
match: after
negate: true
- logstash中FILTERS配置
filter {
if [type] == "tomcat" {
grok{
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{JAVALOGMESSAGE:msg}" }
}
date {
match => [ "timestamp" , "yyyy-MM-dd HH:mm:ss,S", "ISO8601" ]
}
}
}I
-
結(jié)果
-
Filebeat配置講解
-
multiline 合并多行日志:
- pattern:匹配規(guī)則吃溅,這里指匹配每條日志開(kāi)始的年份溶诞;
- match:有before與after,這里指從該行開(kāi)始向后匹配决侈;
- negate:是否開(kāi)始一個(gè)新記錄螺垢,這里指當(dāng)pattern匹配后,結(jié)束之前的記錄颜及,創(chuàng)建一條新日志記錄甩苛;
當(dāng)然在logstash input中使用codec multiline設(shè)置是一樣的
-
小技巧:關(guān)于grok的正則匹配,官方有給出Grok Constructor方法俏站,在這上面提供了debugger讯蒲、自動(dòng)匹配等工具,方便大家編寫匹配規(guī)則
獲取更多免費(fèi)資料加群:554355695
如果你想學(xué)習(xí)Java工程化肄扎、高性能及分布式墨林、高性能、深入淺出犯祠。性能調(diào)優(yōu)旭等、Spring,MyBatis衡载,Netty源
碼分析和大數(shù)據(jù)等知識(shí)點(diǎn)可以來(lái)找我搔耕。
而現(xiàn)在我就有一個(gè)平臺(tái)可以提供給你們學(xué)習(xí),讓你在實(shí)踐中積累經(jīng)驗(yàn)掌握原理痰娱。主要方向是JAVA架構(gòu)
師弃榨。如果你想拿高薪,想突破瓶頸梨睁,想跟別人競(jìng)爭(zhēng)能取得優(yōu)勢(shì)的鲸睛,想進(jìn)BAT但是有擔(dān)心面試不過(guò)的,可以
加我的Java架構(gòu)進(jìn)階群:554355695
總結(jié)
本文開(kāi)始簡(jiǎn)單介紹了logstash的三大模塊:INPUTS坡贺、FILTERS官辈、OUTPUTS。之后通過(guò)Demo了3個(gè)小示例遍坟,給大家講解了FILTERS中g(shù)rok拳亿、geoip、date三個(gè)常用插件的使用政鼠,以及在處理多行日志上的做法风瘦。
在描述的過(guò)程中可能不能面面俱到,但我還是始終堅(jiān)持“知其然知其所以然”的理念公般。寫的每一行代碼万搔,你都得心中有數(shù)胡桨。功能的實(shí)現(xiàn)不意味著結(jié)束,我們何不多折磨自己一下瞬雹,走好最后的一公里昧谊。
最后,有興趣可以去看一下它的官方手冊(cè)酗捌,對(duì)這三大模塊呢诬,各自都提供了非常多的插件支持。我這里只是一個(gè)簡(jiǎn)單的使用胖缤,希望對(duì)大家有所幫助尚镰。