Hello World 系列 - Logstash
示範環境: Ubuntu 16.04.4 LTS
首先, logstash 需要 java, 所以我們就先安裝java
apt-get install python-software-properties
apt-get install software-properties-common
add-apt-repository ppa:webupd8team/java
apt-get update
apt-get install oracle-java8-installer
echo "export JAVA_HOME=/usr/lib/jvm/java-8-oracle" >> ~/.bashrc
echo "export JRE_HOME=/usr/lib/jvm/java-8-oracle/jre" >> ~/.bashrc
然後, 下載安裝logstash
當然, 你也可以選擇自己想要的版本
這邊建議用6.0以上的 原因有二
- 6.0 才有pipeline功能
- 6.0 之前的 config reload 這個功能有點異常
wget https://artifacts.elastic.co/downloads/logstash/logstash-6.2.4.zip
unzip logstash-6.2.4.zip
pipeline, 就是讓logstash可以同時執行多個任務, 而彼此不受影響.
在這個功能推出以前, 如果你的設定有多個output; 其中一個output到達不了的時候, 會進而影響全部功能 .. 然而官方的回覆是說這是要對logstash質量的保證, 不允許只輸出一半之類的事..
Anyway, 後來太多人抱怨了, 就推出這個pipeline功能啦! 如果你們的架構, logstash要處理類型比較豐富, 就一定會需要用到這個功能哦~
config reload, 就是有更改設定檔的時候可以自動reload. 因為logstash啟動需要帶起jvm, 會需要一點時間, 所以有這個參數就很方便.
Logstash Hello World
cd logstash-6.2.4
bin/logstash -e 'input { stdin { } } output { stdout {} }'
這時候需要耐心等待下, 不久後就可以看到下圖
有些朋友到了這一步就說, 我跑了沒有反應! 不working!
別誤會~其實已經正常開始運作了哦!
你會看到他說 The stdin plugin is now waiting for input:
然後現在試著在畫面輸入點東西, 就會看到他有回應了.
稍微實際一點的應用
wei~ 是有反應了, 但是好像沒什麼卵用啊? 說好的收集日誌呢? 把結果打印在畫面上也沒什麼用阿?
莫急、莫慌、莫害怕~ 先做一點基本的說明吧. 先看一下官方對於logstash的示意圖.
然後我自己的示意圖, 這一不小心就展現了我的繪畫天分 (:з」∠)
你可以把他想像成是一個, 這個
然後再做這件事
咳咳.. 進入正題
所以說, logstash 就是由三個部分組成, 每個部分都有各自的plugin
- Input: 各式各樣的接收, 剛剛的示範是
stdin
, 畫面接收自terminal - Filter: 各式各樣的資料處理, 剛剛的示範沒有用這個, 不過這是他最厲害的地方之一
- Output: 各式各樣的輸出, 剛剛的示範是
stdout
, 畫面直接打印在terminal
那我們就示範把日誌丟到elasticsearch吧! 還沒有安裝elasticsearch 的朋友, 請參考這裡哦~
Hello World 系列 - Elasticsearch
首先, 我們要編寫一個設定檔; 剛剛的示範屬於one-linner
, 主要是官方想要表達: 嘿..把config直接寫在指令也是可以的唷~
不過正常情況下誰會把落落長的config塞在指令阿?!
總之, 編寫一個設定檔吧.
所以剛剛的示範, 寫成檔案會變成這樣
input {
stdin {}
}
filter {}
output {
stdout { }
}
主要這三個區塊就是他的骨架, 然後看到input
下面塞了一個stdin
; 這邊就是上面說的plugin
可以來這邊看 logstash input stdin, 或是google 直接搜尋 logstash <input/filter/output> <plugin name>
那他就會跟你說, 這個plugin可以放那些參數, 哪些必填哪些選填之類.
沒興趣的同學請直接回頭~ 前方高能!
這邊示範, 蒐集laravel log 並且丟到 elasticsearch
mkdir conf.d
vim conf.d/laravel_log_to_es.conf
input {
file {
path => [
"/var/log/laravel-*.log"
]
start_position => "beginning"
sincedb_path => "./logstash_sincedb"
codec => multiline {
pattern => "^\["
negate => true
what => "previous"
}
}
}
filter {
grok {
# Laravel log format
match => { "message" => "\[%{TIMESTAMP_ISO8601:logdate}\] %{DATA:env}\.%{DATA:severity}: %{GREEDYDATA:logmessage}" }
}
# Parse the date
date {
match => [ "logdate", "yyyy-MM-dd HH:mm:ss" ]
target => [ "logdate" ]
}
# Remove empty lines
if [message] =~ /^\s*$/ {
drop { }
}
# Remove origin message
mutate {
remove_field => [ "message" ]
}
}
output {
elasticsearch {
hosts => ["127.0.0.1:9200"]
index => "laravel-log-%{+YYYY.MM.dd}"
}
}
只是想蒐集點log, 至於嗎?
別這樣~ 這都是為了更有利後續資料分析做的處理哦~
假設你的log位置在/var/log/laravel-2018.log
內容如下
[2018-05-02 15:05:49] production.INFO: server is now running
[2018-05-02 15:05:50] production.INFO: worker init
[2018-05-02 15:05:50] production.ALERT: proccess not found
[2018-05-02 15:06:22] production.ALERT: tux not found
[2018-05-02 15:15:54] production.ERROR: ErrorException: Trying to get property of non-object in /home/ubuntu/UserRegisterLinkService.php
Stack trace:
#0 /home/ubuntu/UserRegisterLinkService.php(62): Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(8, 'Trying to get p...', '/home/ubuntu/...', 62, Array)
#1 /home/ubuntu/UserRegisterLinkController.php(69): App\Services\UserRegisterLinkService->create(Object(App\Models\User), Array)
#2 [internal function]: App\Http\Controllers\API\Front\UserRegisterLinkController->create(Object(Illuminate\Http\Request))
#3 /home/ubuntu/src/Illuminate/Routing/Controller.php(55):
[2018-05-02 15:20:49] production.INFO: server is now running
[2018-05-02 15:20:50] production.INFO: worker init
上面每個區塊的puglin可以幫我們做這些事, 如果沒有這樣的話, 資料進去elasticsearch裡面就是一坨文字而已, 是不能做分析的哦!
我挑幾個比較重要的說, 剩下的會在其他篇做解釋
codec => multiline
: 這是多行日誌的解析插件, 沒有這個的話, 每一行trace都會被判定是獨立事件
grok
: 就是把我們的日誌訊息, 用正則的方式, 變成field: value
date
: 日誌時間的插件, 如果沒有使用他的話, logstash丟出去的@timestamp欄位, 是日誌接收的時間哦. 如果今天要匯入舊日誌的話就麻煩了.
if [message] =~ /^\s*$/
: 如果今天日誌是一個空行的話, 通常不會發生啦~
mutate
: 就是變異, 可以任意改變我們的資料
運行結果
畫面上好像不會特別顯示什麼.. 不過這時候看一下自己的elasticsearch
root@ubuntu:~# curl 127.0.0.1:9200/_cat/indices
yellow open laravel-log-2018.05.06 46sxRKN8SU2si1yfH8sNkQ 5 1 6 0 44kb 44kb
然後來做個搜尋
root@ubuntu:~# curl -s 127.0.0.1:9200/laravel-log-2018.05.06/_search?q=severity:ALERT | jq .
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.9808292,
"hits": [
{
"_index": "laravel-log-2018.05.06",
"_type": "doc",
"_id": "ljh5NGMBkXU3O_9hlAIl",
"_score": 0.9808292,
"_source": {
"host": "ubuntu",
"logmessage": "tux not found",
"@version": "1",
"logdate": "2018-05-02T07:06:22.000Z",
"env": "production",
"severity": "ALERT",
"@timestamp": "2018-05-06T08:02:52.142Z",
"path": "/var/log/laravel-2018.log"
}
},
{
"_index": "laravel-log-2018.05.06",
"_type": "doc",
"_id": "mDh5NGMBkXU3O_9hlAIp",
"_score": 0.2876821,
"_source": {
"host": "ubuntu",
"logmessage": "proccess not found ",
"@version": "1",
"logdate": "2018-05-02T07:05:50.000Z",
"env": "production",
"severity": "ALERT",
"@timestamp": "2018-05-06T08:02:52.141Z",
"path": "/var/log/laravel-2018.log"
}
}
]
}
}
成功啦~ 可以看到ALERT的就是有兩筆資料; 資料的欄位是剛剛grok
的功勞哦
現在你的資料已經很漂亮, 可以讓kibana 或是其他軟體去做視覺化分析啦~
Err.. 一不小心講太多了, 咱下次見~