營(yíng)山網(wǎng)站建設(shè)seo扣費(fèi)系統(tǒng)源碼
有時(shí) Logstash Grok 沒(méi)有我們需要的模式。 幸運(yùn)的是我們有正則表達(dá)式庫(kù):Oniguruma。在很多時(shí)候,如果 Logstash 所提供的正則表達(dá)不能滿足我們的需求,我們選用定制自己的表達(dá)式。
定義
- Logstash 是一種服務(wù)器端數(shù)據(jù)處理管道,可同時(shí)從多個(gè)來(lái)源獲取數(shù)據(jù),對(duì)其進(jìn)行轉(zhuǎn)換,然后將其發(fā)送到 “存儲(chǔ)”(如 Elasticsearch)。
- Grok 是 Logstash 中的過(guò)濾器,用于將非結(jié)構(gòu)化數(shù)據(jù)解析為結(jié)構(gòu)化和可查詢的內(nèi)容。
- Regular expression 是定義搜索模式的字符序列。
如果你已經(jīng)在運(yùn)行 Logstash,則無(wú)需安裝額外的正則表達(dá)式庫(kù),因?yàn)?Grok 位于正則表達(dá)式之上,因此任何正則表達(dá)式在 grok 中也有效 —— Elastic 文檔。
語(yǔ)法
Grok
Grok 語(yǔ)法如下:
%{SYNTAX:SEMANTIC}
- SYNTAX 是默認(rèn)的 grok 模式
- SEMANTIC 是 key
Oniguruma
oniguruma 語(yǔ)法如下:
(?<field_name>the pattern here)
Grok + Oniguruma
你可以像下面這樣組合 Grok 和 Oniguruma:
%{SYNTAX:SEMANTIC} (?<field_name>the pattern here)
讓我們開始吧
樣本數(shù)據(jù)
為了演示我們?nèi)绾螌?Oniguruma 與 Grok 結(jié)合使用,我們將在示例中使用下面的日志數(shù)據(jù)。
production GET /v2/blacklist/ 200 24ms 5ba9e948801d34906b96e0c20 Panya/1.6.3 (com.sn.panya.host; build:1; iOS 10.3.3) Alamofire/4.66.0 {\"user_id\":\"5bd4c2f4569f470016bd8d55\",\"reason\":\"SPAMMER\"}
日志數(shù)據(jù)結(jié)構(gòu):
production == environment
GET == method
/v2/blacklist == url
200 == response_status
24ms == response_time
5bc6e716b5d6cb35fc9687c0 == user_id
Panya/1.6.3 (com.sn.panya.host; build:1; iOS 10.3.3) Alamofire/4.66.0 == user_agent
{\"user_id\":\"5bd4c2f4569f470016bd8d55\",\"reason\":\"SPAMMER\"} == req.body
目的:
目標(biāo)是找到一種模式來(lái)構(gòu)造非結(jié)構(gòu)化日志數(shù)據(jù)。為此,我們將使用 Kibana 里的 Grok Debugger 來(lái)進(jìn)行測(cè)試:
其中,我們的 Grok pattern 定義如下:
%{WORD:environment} %{WORD:method} %{URIPATH:url} %{NUMBER:response_status} %{WORD:response_time} %{USERNAME:user_id}
如上所示,上面的 Grok pattern 產(chǎn)生如下的結(jié)果:
{"environment": "production","method": "GET","response_status": "200","user_id": "5ba9e948801d34906b96e0c20","response_time": "24ms","url": "/v2/blacklist/"
}
這是一個(gè)不錯(cuò)的開始,但還不完整。 沒(méi)有 user_agent 和 req.body 的映射。要提取 user_agent 和 req.body,我們需要仔細(xì)檢查其結(jié)構(gòu)。
空格分隔符
值 production GET /v2/blacklist/ 200 24ms 5ba9e948801d34906b96e0c20 由空格分隔,這很容易使用。
但是,對(duì)于 user_agent,可以有動(dòng)態(tài)數(shù)量的空格,具體取決于發(fā)送請(qǐng)求的硬件類型。
Panya/1.6.3 (com.sn.panya.host; build:1; iOS 10.3.3) Alamofire/4.66.0
我們?nèi)绾谓忉屵@種持續(xù)變化?
提示:看一下 req.body 的結(jié)構(gòu)。
{\”user_id\”:\”5bd4c2f4569f470016bd8d55\”,\”reason\”:\”SPAMMER\”}
我們可以看到 req.body 是由花括號(hào) {} 組成的。
利用這些知識(shí),我們可以構(gòu)建一個(gè)自定義正則表達(dá)式模式來(lái)查找第一個(gè)左括號(hào)之前的所有內(nèi)容,然后獲取之后的所有內(nèi)容。
?在上面,我們使用 Grok pattern:
(?<user_agent>[^{]*) %{GREEDYDATA:body}
你可在這個(gè)鏈接中找到 “regex match everything until character”。
把所有的都放在一起
將其應(yīng)用于 grok 調(diào)試器中的自定義正則表達(dá)式模式,我們得到了我們想要的結(jié)果:
我們的 Grok pattern 為:
%{WORD:environment} %{WORD:method} %{URIPATH:url} %{NUMBER:response_status} %{WORD:response_time} %{USERNAME:user_id} (?<user_agent>[^{]*) %{GREEDYDATA:body}
?
創(chuàng)建 logstash.conf
為了能夠測(cè)試我們的 Grok pattern 是否正確,我們創(chuàng)建如下的一個(gè) logstash.conf 文件。我們可以參考之前的文章 “Logstash:在實(shí)施之前測(cè)試 Logstash 管道/過(guò)濾器”。
logstash.conf
input {generator {message => 'production GET /v2/blacklist/ 200 24ms 5ba9e948801d34906b96e0c20 Panya/1.6.3 (com.sn.panya.host; build:1; iOS 10.3.3) Alamofire/4.66.0 {"user_id":"5bd4c2f4569f470016bd8d55","reason":"SPAMMER"}'count => 1}
}filter {grok {match => { "message" => "%{WORD:environment} %{WORD:method} %{URIPATH:url} %{NUMBER:response_status} %{WORD:response_time} %{USERNAME:user_id1} (?<user_agent>[^{]*) %{GREEDYDATA:body}"}}mutate {remove_field => ["message", "event", "host", "@version"]}
} output {stdout {codec => rubydebug}
}
我們使用如下的命令來(lái)啟動(dòng) Logstash pipeline:
./bin/logstash -f logstash.conf
從上面的輸出中,我們可以看出來(lái)原始的數(shù)據(jù)已經(jīng)變?yōu)榻Y(jié)構(gòu)化的數(shù)據(jù)了。我們可以看到美中不足的是 body 這個(gè)數(shù)據(jù)是一個(gè) JSON 格式的數(shù)據(jù),還沒(méi)有被結(jié)構(gòu)化。我們進(jìn)一步修改我們的 logstash.conf 配置文件:
logstash.conf
input {generator {message => 'production GET /v2/blacklist/ 200 24ms 5ba9e948801d34906b96e0c20 Panya/1.6.3 (com.sn.panya.host; build:1; iOS 10.3.3) Alamofire/4.66.0 {"user_id":"5bd4c2f4569f470016bd8d55","reason":"SPAMMER"}'count => 1}
}filter {grok {match => { "message" => "%{WORD:environment} %{WORD:method} %{URIPATH:url} %{NUMBER:response_status} %{WORD:response_time} %{USERNAME:user_id1} (?<user_agent>[^{]*) %{GREEDYDATA:body}"}}json {source => "body"}mutate {remove_field => ["message", "event", "host", "@version", "body"]}} output {stdout {codec => rubydebug}
}
在上面,我們添加了 json 過(guò)濾器來(lái)處理 body,從而更進(jìn)一步結(jié)構(gòu)化數(shù)據(jù)。我們?cè)俅芜\(yùn)行 Logstash。我們可以看到如下的結(jié)果:
?
從上面,我們可以看到 body 也被結(jié)果化了。我們可以看到 user_id 及 reason 兩個(gè)字段。