這是之前系列文章“Logstash:Logstash 入門教程 (一)”的續集。在之前的文章中,我們詳細地介紹了Logstash是什麼?在今天的文章中,我們將詳細介紹如果使用Logstash,並把Apache Web log導入到Elasticsearch中。在這篇文章中,我們將觸及到如下的過濾器:
安裝
Elasticsearch
如果你還沒有安裝好自己的Elasticsearch,請參閱我之前的文章“如何在Linux,MacOS及Windows上進行安裝Elasticsearch”來安裝好自己的Elasticsearch。
Kibana
如果你還沒有安裝好自己的Kibana,請參閱我之前的文章“如何在Linux,MacOS及Windows上安裝Elastic棧中的Kibana”安裝好自己的Kibana。
Logstash
如果你還沒有安裝好自己的Logstash,請參閱我之前的文章“如何安裝Elastic棧中的Logstash”來安裝好自己的Logstash。
如何運行Logstash
在Mac, Unix及Linux下,我們可以使用如下的方式來進行運行:
bin/logstash [options]
在Windows環境下,我們使用如下的方式來運行:
bin/logstash.bat [options]
在通常情況下,我們需要跟上一些選項纔可以啓動Logstash,否則它會退出。除非有一種情況,在我們啓動monitoring後,可以不添加選項來啓動Logstash。關於如何啓動集中管理,請參閱我之前的文章“Logstash: 啓動監控及集中管理”。
如何配置 Logstash pipeline
Logstash管道有兩個必需元素,輸入和輸出,以及一個可選元素filter。 輸入插件使用來自源的數據,過濾器插件在您指定時修改數據,輸出插件將數據寫入目標。
要測試Logstash安裝,請運行最基本的Logstash管道。 例如:
cd logstash-7.6.2
bin/logstash -e 'input { stdin { } } output { stdout {} }'
等Logstash完成啓動後,我們在stdin裏輸入一下文字,我們可以看到如下的輸出:
當我們打入一行字符然後回車,那麼我們馬上可以在stdout上看到輸出的信息。如果我們能看到這個輸出,說明我們的Logstash的安裝是成功的。
另外一種運行Logstash的方式,也是一種最爲常見的運行方式。我們首先需要創建一個配置文件,比如:
heartbeat.conf
input {
heartbeat {
interval => 10
type => "heartbeat"
}
}
output {
stdout {
codec => rubydebug
}
}
然後,我們通過如下的方式來運行logstash:
bin/logstash -f heartbeat.conf
那麼我們可以在console中看到如下的輸出:
動手實踐
在這一節中,我們將使用一個例子來一步一步地詳細介紹如何使用Logstash來實現我們的數據處理。
1)首先啓動我們的Elasticsearch及Kibana。請參照之前的步驟運行Elasticsearch及Kibana。
2)我們進入到Logstash安裝目錄,並修改config/logstash.yml文件。我們把 config.reload.automatic 設置爲true。
這樣設置的好處是,每當我修改完我的配置文件後,我不需要每次都退出我的logstash,然後再重新運行。
3)創建一個叫做weblog.conf的配置文件,並輸入一下的內容:
weblog.conf
input {
tcp {
port => 9900
}
}
output {
stdout { }
}
4)運行我們的Logstash
bin/logstash -f weblog.conf
這樣我們的Logstash就已經啓動了。
接下來,我們使用 nc 應用把數據發送到 TCP 端口號 9900,並查看console的輸出。我們在另外一個console中打入如下的命令:
echo 'hello logstash' | nc localhost 9900
我們在Logstash 運行的console裏可以看到輸出:
上面說明我們的TCP input 運行是正常的。
5)下載Weblog文件併發送給Logstash
我們可以在地址https://ela.st/weblog-sample下載一個叫做weblog-sample.log的文件。這個文件有64.5M的大下。我們把這個文件保存於Logstash的安裝目錄中。它裏面的其中的一個log的內容如下:
14.49.42.25 - - [12/May/2019:01:24:44 +0000] "GET /articles/ppp-over-ssh/ HTTP/1.1" 200 18586 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b1) Gecko/20091014 Firefox/3.6b1 GTB5"
我使用如下的命令來讀取第一行,並輸入到TCP 9900端口:
head -n 1 weblog-sample.log | nc localhost 9900
那麼在Logstash運行的console中,我們可以看到如下的輸出:
這顯示是我們第一行的那條Weblog信息。在這裏,我們沒有對數據進行任何的處理。它只是把第一行日誌讀出來,並把它都賦予給message這個字段。
運用過濾器來對數據進行處理
接下來,我們分別使用一些過濾器來對數據進行分別處理。
Grok
針對Grok,我還有有一個專門的文章“Logstash:Grok filter 入門”來描述。在這裏,我們針對weblog.conf進行如下的修改(你可以使用你喜歡的編輯器):
input {
tcp {
port => 9900
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
}
output {
stdout { }
}
還記得之前我們的設置config.reload.automatic爲true嗎?當我們保存weblog.conf文件後,我們可以在Logstash的輸出console裏看到:
也就是說,我們的pipleline被自動地裝載進來了。我們安裝上面同樣的方法取第一條的數據來輸入:
head -n 1 weblog-sample.log | nc localhost 9900
這個時候,我們再在Logstash運行的console裏,我們可以看到:
也就是說,我們通過Grok這個filter,它通過正則表達式進行匹配,並把我們的輸入的非結構化的數據變爲一個結構化的數據。從上面,我們可以看到各種被提取的字段,比如clientip, port, host等等。
Geoip
儘管上面的數據從非結構化變爲結構化數據,這是非常好的,但是還是有美中不足的地方。比如clientip,我們知道了這個請求的IP地址,但是我們還是不知道這個IP是從哪個地方來的,具體是哪個國家,哪個地理位置。在這個時候,我們需要使用geoip過濾器來對數據進行豐富。我們在filter的這個部分加入geoip。當我們保存好weblog.conf文件後,我們會發現Logstash會自動裝載我們最新的配置文件(如上步所示一樣):
weblog.conf
input {
tcp {
port => 9900
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
geoip {
source => "clientip"
}
}
output {
stdout { }
}
同樣地,我們使用如下的命令來發送日誌裏的第一條數據:
head -n 1 weblog-sample.log | nc localhost 9900
這個時候,我們可以看到除了在上面的clientip信息之外, 我們的數據多了一個新的叫做geoip的字段。它裏面含有location位置信息。這就爲我們在地圖上進行顯示這些數據提供了方便。我們可以利用Elastic所提供的地圖清楚地查看到請求是來自哪裏。
Useragent
上面的數據比以前更加豐富。我們還注意到agent這個字段。它非常長,我們沒法查看出來是來自什麼樣的瀏覽器,什麼語言等等信息。我們可以使用useragent這個過濾器來進一步豐富數據。我們在weblog.conf中添加這個過濾器:
weblog.conf
input {
tcp {
port => 9900
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
geoip {
source => "clientip"
}
useragent {
source => "agent"
target => "useragent"
}
}
output {
stdout { }
}
等更新完這個配置文件後,我們再次在另外一個console中發送第一個log:
head -n 1 weblog-sample.log | nc localhost 9900
我們可以在上面看到一個新增加的字段useragent。上面它表明了useragent的版本信息,瀏覽器的名稱以及操作系統。這對於我們以後的數據分析提供更進一步的幫助。
Mutate - convert
從上面的輸出中,我們了可以看出來bytes是一個字符串的類型。這個和我們實際的應用可能會有所不同。這應該是一個整型數。我們可以使用mutate: convert 過濾器來對它進行轉換。我們重新編輯weblog.conf文件。我們把它放於grok過濾器之後:
weblog.conf
input {
tcp {
port => 9900
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
mutate {
convert => {
"bytes" => "integer"
}
}
geoip {
source => "clientip"
}
useragent {
source => "agent"
target => "useragent"
}
}
output {
stdout { }
}
等更新完這個配置文件後,我們再次在另外一個console中發送第一個log:
head -n 1 weblog-sample.log | nc localhost 9900
從上面的輸出中,我們可以看到bytes這個字段已經變爲正式值了,而不是之前的字符串了。
Date
Logstash將事件時間存儲在@timestamp字段中。 但是實際的日誌創建時間在 timestamp 字段中(沒有@)。 該字段的格式不是ISO8601,因此存儲爲文本。 我們可以使用 date 過濾器將此字段轉換爲日期類型。我們編輯weblog.conf,並加入 date 過濾器:
weblog.conf
input {
tcp {
port => 9900
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
mutate {
convert => {
"bytes" => "integer"
}
}
geoip {
source => "clientip"
}
useragent {
source => "agent"
target => "useragent"
}
date {
match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
}
}
output {
stdout { }
}
等更新完這個配置文件後,我們再次在另外一個console中發送第一個log:
head -n 1 weblog-sample.log | nc localhost 9900
從上面,我們看出來新添加了一個叫做@timestamp的字段。
設置輸出 - Elasticsearch
所有的到目前爲止,所有的輸出都是stdout,也就是輸出到Logstash運行的console。我們想把處理後的數據輸出到Elasticsearch。我們在output的部分添加如下的Elasticsearch輸出:
weblog.conf
input {
tcp {
port => 9900
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
mutate {
convert => {
"bytes" => "integer"
}
}
geoip {
source => "clientip"
}
useragent {
source => "agent"
target => "useragent"
}
date {
match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
}
}
output {
stdout { }
elasticsearch {
hosts => ["localhost:9200"]
user => "elastic"
password => "changeme"
}
}
在上面,我們同時保留兩個輸出:stdout及elasticsearch。事實上,我們可以定義很多個的輸出。stdout輸出對於我們初期的調試是非常有幫助的。等我們完善了所有的調試,我們可以把上面的stdout輸出關掉。依賴於我們是否已經爲Elasticsearch提供安全設置,我們需要在上面配置好訪問的用戶名及密碼。
等更新完這個配置文件後,我們再次在另外一個console中發送第一個log:
head -n 1 weblog-sample.log | nc localhost 9900
這一次,我們打開Kibana:
我們在Dev Tools裏輸入如下的命令:
GET logstash/_count
從上面,我們可以看到有一條Logstash的數據。我們可以再接着打入如下的命令:
GET logstash/_search
從上面我們可以看到這條Logstash導入的數據。它和我們之前在Longstash console裏看到的是一摸一樣的。
啓用 keystore 來保護自己的密碼等
在上面所有的配置中,我們在配置文件中把自己的用戶名及密碼都寫在文本中間。這個是非常不好的,這是因爲任何可以接觸到這個配置文件的人都可以看到你這些敏感信息。爲此,logstash-keystore 提供了一種安全機制。它允許我們把這些信息保存於一個keystore裏,這樣別人都看不到真實的用戶名及密碼等信息。如果你還不知道如何爲Elasticsearch設置安全信息的話,請參閱我之前的文章“Elasticsearch:設置Elastic賬戶安全”。
我們在Logstash的console裏打入如下的命令:
bin/logstash-keystore create
$ bin/logstash-keystore create
Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
2020-05-08T10:38:35.483+08:00 [main] WARN FilenoUtil : Native subprocess control requires open access to sun.nio.ch
Pass '--add-opens java.base/sun.nio.ch=org.jruby.dist' or '=org.jruby.core' to enable.
WARNING: The keystore password is not set. Please set the environment variable `LOGSTASH_KEYSTORE_PASS`. Failure to do so will result in reduced security. Continue without password protection on the keystore? [y/N] y
Created Logstash keystore at /Users/liuxg/elastic3/logstash-7.6.2/config/logstash.keystore
我們接着打入如下的命令:
bin/logstash-keystore add ES_HOST
我們把配置文件中的Elasticsearch的地址 localhost:9200 拷貝並粘貼過來:
$ bin/logstash-keystore add ES_HOST
Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
2020-05-08T10:39:41.884+08:00 [main] WARN FilenoUtil : Native subprocess control requires open access to sun.nio.ch
Pass '--add-opens java.base/sun.nio.ch=org.jruby.dist' or '=org.jruby.core' to enable.
Enter value for ES_HOST:
Added 'es_host' to the Logstash keystore.
我們再接着打入如下的命令:
bin/logstash-keystore add LS_USER
$ bin/logstash-keystore add LS_USER
Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
2020-05-08T10:41:41.603+08:00 [main] WARN FilenoUtil : Native subprocess control requires open access to sun.nio.ch
Pass '--add-opens java.base/sun.nio.ch=org.jruby.dist' or '=org.jruby.core' to enable.
Enter value for LS_USER:
Added 'ls_user' to the Logstash keystore.
我們在上面輸入我們的Logstash的用戶名。這個用戶名可以是那個超級用戶elastic,也可以是我們自己創建的一個專爲數據採集的用戶。
最後,我們也可以打入如下的命令:
bin/logstash-keystore add LS_PWD
我們把上面用戶名的密碼進行輸入:
$ bin/logstash-keystore add LS_PWD
Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
2020-05-08T10:48:29.166+08:00 [main] WARN FilenoUtil : Native subprocess control requires open access to sun.nio.ch
Pass '--add-opens java.base/sun.nio.ch=org.jruby.dist' or '=org.jruby.core' to enable.
Enter value for LS_PWD:
Added 'ls_pwd' to the Logstash keystore.
在這裏我必須指出的是:上面我使用的 ES_HOST, LS_USER 及 LS_PWD 都是你自己任意可以選取的名字。只要它們和我們下邊所使用的配置裏的名字是配合的即可。
在上面,我們已經創建了一下鍵值,那麼我們該如何使用它們呢?我們重新打開weblog.conf文件:
weblog.conf
input {
tcp {
port => 9900
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
mutate {
convert => {
"bytes" => "integer"
}
}
geoip {
source => "clientip"
}
useragent {
source => "agent"
target => "useragent"
}
date {
match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
}
}
output {
stdout { }
elasticsearch {
hosts => ["${ES_HOST}"]
user => "${LS_USER}"
password => "${LS_PWD}"
}
}
在上面的elasticsearch輸出部分,我們分別使用了 ES_HOST, LS_USER 及 LS_PWD 來分別代替了之前使用的字符串。這樣做的好處是,我們再也不用硬編碼我們的這些字符串了。我們把這個文件給任何人看,他們都不會發現我們的這些敏感信息了。
經過這個修改後,我們重新運行Logstash:
bin/logstash -f weblog.conf
我們看到Logstash已經被成功啓動了。我們使用如下的命令再次發送第一條日誌信息:
head -n 1 weblog-sample.log | nc localhost 9900
我們再次查看Kibana:
顯然,這次比上一次多了一條數據。說明我們的配置是成功的!
更多閱讀
你可以發現更多的關於Logstash的文章。相關的文章: