ELK日志分析系統
作者:Danbo 2016-*-*
本文是學習筆記,參考ELK Stack中文指南,鏈接:https://www.gitbook.com/book/chenryn/kibana-guide-cn/details
ELK Stack 是 Elasticsearch、Logstash、Kibana 三個開源軟件的組合。在實時數據檢索和分析場合,三者通常是配合共用,而且又都先后歸於 Elastic.co 公司名下,故有此簡稱。
ELK Stack 在最近兩年迅速崛起,成為機器數據分析,或者說實時日志處理領域,開源界的第一選擇。和傳統的日志處理方案相比,ELK Stack 具有如下幾個優點:
- 處理方式靈活。Elasticsearch 是實時全文索引,不需要像 storm 那樣預先編程才能使用;
- 配置簡易上手。Elasticsearch 全部采用 JSON 接口,Logstash 是 Ruby DSL 設計,都是目前業界最通用的配置語法設計;
- 檢索性能高效。雖然每次查詢都是實時計算,但是優秀的設計和實現基本可以達到全天數據查詢的秒級響應;
- 集群線性擴展。不管是 Elasticsearch 集群還是 Logstash 集群都是可以線性擴展的;
- 前端操作炫麗。Kibana 界面上,只需要點擊鼠標,就可以完成搜索、聚合功能,生成炫麗的儀表板。
Logstack
推薦安裝方式:采用Elasticsearch官方倉庫來直接安裝Logstash
rpm --import http://packages.elasticsearch.org/GPG-KEY-elasticsearch cat > /etc/yum.repos.d/logstash.repo <<EOF [logstash-1.5] name=logstash repository for 1.5.x packages baseurl=http://packages.elasticsearch.org/logstash/1.5/centos gpgcheck=1 gpgkey=http://packages.elasticsearch.org/GPG-KEY-elasticsearch enabled=1 EOF yum clean all yum install logstash
不過我是直接官網下載logstash-1.5.4.tar.gz安裝包,然后直接tar -zxvf logstash-1.5.4.tar.gz; mv logstash-1.5.4 /usr/local; ln -s logstash-1.5.4 logstash。支持安裝完畢。
測試運行結果如下:
[root@centos-linux logstash]# bin/logstash -e 'input {stdin{}}output{stdout{codec=>rubydebug}}'
Hello World
Logstash startup completed
{
"message" => "Hello World",
"@version" => "1",
"@timestamp" => "2016-03-03T03:17:37.694Z",
"host" => "centos-linux.shared"
}
Logstash就像管道一樣,輸入類似cat,處理類似過濾awk、uniq,最后輸出類似並保存類似tee。
top--》H查看進程時發現,logstash給每個線程都取了一個名字,輸入的叫xx,輸出的叫|xx。數據在線程之間以事件的形式流傳。logstash會給事件添加一些額外的信息。最重要的是@timestamp,用來標記時間的發生時間。
語法
logstash設計了自己的DSL(Domain Specific Language,區域特定語言)
包括:區域,注釋,數據類型(布爾值,字符串,數值,數組,哈希),條件判斷,字段引用等。
區段(section)
logstash用{}來定義區域。區域內可以包括插件區域定義,可以在一個區域內定義多個插件。插件區域內則可以定義鍵值對(類似字典)設置
數據類型
Logstash支持少量的數據值類型
bool
debug => true
string
host => "hostname"
number
port => 514
array
match => ["datetime", "UNIX", "ISO8601"]
hash
options => {
key1 => "value1"
key2 => "value2"
}
如果是logstash版本低於1.2.0,哈希的語法跟數組是一樣的,就像下面這樣:
match => ["field1", "pattern1", "field2", "pattern2"]
字段引用(field reference)
字段是Logstash::Event 對象的屬性。對象就像一個哈希一樣,所以你可以想象字段就像一個鍵值對。
在Logstash配置中使用字段的值,只需要把字段的名字寫在[]里就行了,這就叫字段引用。對於嵌套字段(多維哈希表),每層的字段名都寫在[]里就可以了。比如可以從geoip里獲取longitude值:[geoip][location][0]。
logstash 還支持變量內插,在字符串里使用字段引用的方法是這樣:
"the longitude is %{[geoip][location][-1]}"
條件判斷(condition)
命令行參數
Logstash提供了一個shell腳本叫logstash 方便快速運行,
-e 執行。
--config或者-f 表示文件。
真實運用中,我們會寫很長的配置,甚至超過shell所能支持的1024個字符長度。所以我們必把配置固定化到文件里,然后通過bin/logstash -f agent.conf這樣的形式來運行。
此外,logstash還提供一個方便我們規划和書寫配置的小功能。你可以直接用bin/logstash -f /etc/logstash.d/來運行。logstash會自動讀取/etc/logstash.d/目錄下所有*.conf的文本文件,然后在自己內存里拼接成一個完整的大配置文件,再去執行。
--configtest 或-t表示測試。
用來測試logstash讀取到的配置文件語法是否能正常解析。
--log 或-l表示日志
logstash默認輸出日志到標准錯誤。生產環境可以通過bin/logstash -l logs/logstash.log 來統一存儲日志。
--filterworks 或 -w 表示工作線程
logstash會運行多個線程。你可以用bin/logstash -w 5這樣的方式強制logstash為過濾插件運行5個線程。
--pluginpath 或 -P
可以寫自己的插件,然后利用bin/logstash --pluginpath /path/to/own/plugins加載他們。不過高版本的logstash已經取消該功能了。
--verbose
輸出一定的調試日志
--debug
輸出更多的調試日志
Plugin的安裝
從logstash 1.5.0版本開始,logstash將所有的插件都獨立拆分為gem包,這樣,每個插件都可以獨立更新,不用等待logstash自身做整體更新的時候才能使用。
plugin用法說明

示例,通過bin/plugin list 查看本機現在有多少插件可用。(其實就在vendor/bundle/ruby/1.9/gems 目錄下)
通過bin/plugin install logstash-ouput-webhdfs 就可以了;
同樣僅升級的話可以使用:bin/plugin update logstash-input-tcp
本地插件安裝
bin/plugin 不單可以通過rubygems平台安裝插件,還可以讀取本地路徑的gem文件。
例如:bin/plugin install /path/to/logstash-filter-crash.gem
長期運行
1.最基礎的nohup方式
nohup command 2>$1 &
2.screen方式
3.推薦daemontools方式
daemontools是一個軟件的,包括但不限於python實現的supervisord,perl實現的ubic,ruby實現的god等。
?????這個沒懂
輸入插件
注意:logstash配置一定要有一個input和一個output。如果沒有寫明input,默認就會使用input/stdin,同理,沒有寫明的output就是output/stdout。
collectd簡述
collectd是一個守護進程,用來收集系統性能和提供各種存儲方式來存儲不同值的機制。它會在系統運行和存儲信息時周期的統計系統的相關統計信息。利用這些信息有助於查找當前系統性能瓶頸和預測系統未來的部署能力。
詳細參見配置手冊。
讀取文件(File)
Logstash使用一個名叫FileWatch的Ruby Gem庫來監聽文件變化。會記錄一個叫.sincedb的數據庫文件來跟蹤被監聽的日志文件的當前讀取位置。
sincedb文件中記錄了每個被監聽的文件的inode, major number, minor number 和 pos
配置文件:
[root@centos-linux conf]# cat input.conf input { file { path => ["/var/log/*.log", "/var/message"] type => "system" start_position => "beginning" } }
解釋
有一些有用的配置項:
·discover_interval
logstash每隔多久去檢查一次被監聽的path下是否有新文件。默認值是15s。
·exclude
不想被監聽的文件可以排除出去。
·sincedb_path
如果你不想用默認的$HOME/.sincedb,可以通過這個配置定義sincedb文件到其他位置。
·sincedb_write_interval
logstash每隔多久寫一次sincedb文件,默認是15s。
·stat_interval
logstash每隔多久檢查一次被監聽文件狀態(是否更新),默認是1s。
·start_position
logstash從什么位置開始讀取文件數據,默認是結束位置,也就是說logstash進程會以類似tail -f的形式運行。如果你是要導入原有數據,可以把這個參數改成"beginning",logstash進程就從頭開始讀取,優點類似cat,然后讀到最后一行再以tail -f形式讀取。
此時我們運行input.conf文件: bin/logstash -f /conf/input.conf
[root@centos-linux logstash]# cat conf/input.conf input { file { path => ["/var/log/*.log", "/var/message"] type => "system" start_position => "beginning" sincedb_path => "/uestc/log/sincedb" } }
運行結果如下:
[root@centos-linux log]# cat sincedb 1566732 0 64768 20267 1571713 0 64768 2103 1571851 0 64768 89 1566741 0 64768 3329 1571723 0 64768 0 1571714 0 64768 76117
正如上面寫的,從左到右以此為:inode, major number, minor number, pos
注意:
1.FileWatch只支持文件的絕對路徑,而且會不自動遞歸目錄。所以有需要的話,用數字方式寫明具體哪些文件。
2.LogStash::Inputs::File 只是在進程運行的注冊階段初始化一個FileWatch對象。它不支持那樣動態的寫法,如:path => "/path/to/%{+yyyy/MM/dd/hh}.log"這樣的寫法,為了達到相同的目的你可以寫:path => "/path/to/**/*.log",用**來縮寫表示遞歸全部子目錄。
3. start_position 僅在該文件從從未被監聽的時候起作用。如果sincedb文件中已經由這個文件的inode記錄了,那么logstash依然會從記錄過的pos開始讀取數據。所以重復測試的時候需要刪除sincedb文件,不過有另一巧妙的解決辦法那就是在conf文件中將sincedb_path定義為/dev/null,則每次啟動自動從頭開會讀。
4.不過windows沒有inode的概念,因此在windows下很不靠譜。
讀取Syslog數據
當你想從設備上收集系統日志的時候,syslog應該會是你的第一選擇。
這個實驗沒有做成功。
讀取網絡數據(TCP)
未來你可能會用Redis服務器或者其他的消息隊列系統來作為logstash broker的角色。不過logstash其實也有自己的TCP/UDP插件,不過在生產環境下Logstash本身只能在sizedqueue中緩存20個事件。
目前來看,logstash::input::TCP 最常見的用法就是配合nc命令導入久數據。
******
編碼插件(Codec)
Codec來自Coder/Decoder兩個單詞的首字母縮寫。
其實logstash最初只支持純文本形式輸入,然后過濾處理它,現在可以處理不同的類型的數據,這全是因為有了codec設置。logstash不只只有一個input | filter | output 的數據流,而是一個input| decode| filter | encode | output 的數據流 codec就是用來decode、encode事件的。
采用JSON編碼
在早期的版本中,有一種降低logstash過濾器的CPU負載消耗的做法盛行於社區:直接輸入預定義好的JSON數據,這樣就可以省略嗲filter/grok配置。
JSON(JavaScript Object Notation)是一種輕量級的數據交換格式,其特點是易於人閱讀和編寫,同時也易於機器解析和生成(一般用於提高網絡傳輸速率)。
合並多行數據(Multiline)
有時候,應用程序調試日志會包含非常豐富的內容,為一個事件打印出很多行內容,這種日志通常都很難通過命令解析的方式做分析。
配置實例:
input { stdin { codec => multiline { pattern => "^\[" negate => true what => "previous" } } }
此時在logstash輸入以下幾行信息:

此時你會發現logstash輸出下面這樣的返回:

此時你會發現輸出的事件中都沒有最后的“the end”字符串。這是因為你最后輸入的回車符\n 並不匹匹配^\[開頭”[“,logstash還得等到下一個數據直到匹配成功后才會輸出這個事件。
NetFlow
******
過濾器插件(Filter)
1.時間處理(Date)
之前我們提到過,filters/date插件可以用來轉換你的日志記錄中的時間字符串,變成Logstash::Timestamp 對象,然后轉存到@timestamp字段里。
注意:因為在稍后的outputs/elasticsearch中常用的%{+YYYY.MM.dd} 這種寫法必須讀取@timestamp數據,所以一定不要直接刪掉這個字段保留自己的字段,而是應該用filters/date轉換后刪除自己的字段!
2.Grok正則捕獲
Grok是Logstash最重要的插件。你可以在Grok里預定義好命名正則表達式,在稍后(grok參數或者其他正則表達式里)引用它。
配置文件:
input {stdin{}} filter { grok { match => { "message" => "\s+(?<request_time>\d+(?:\.\d+)?)\s+" } } } output {stdout{}}
然后運行logstash進程,然后輸入"begin 123.456 end",你會看到類似下面的輸出:

不過數據類型好像不太對,request_time 應該是數值而不是字符串。
3.Grok正則捕獲
Grok支持把預定義的grok表達式寫入到文件中。
其用法我們看下面這個示例:
USERNAME [a-zA-Z0-9._-]+ USER %{USERNAME}
第一行,用普通的正則表達式來定義一個grok表達式;第二行,通過打印賦值格式,用前面定義好的grok表達式來定義另一個grok表達式。
grok表達式的打印復制格式的完整語法是下面這樣:
%{PATTERN_NAME:capture_name:data_type}
data_type 目前只支持兩個值:int 和 float。
我們將配置修改成下面這樣:
input { stdin {} } filter { grok { match => { "message" => "%{WORD} %{NUMBER:request_time:float} %{WORD}" } } } output { stdout {} }
重新運行進程然后可以得到如下結果:

此時request_time 變成數值類型了。
4.最佳實踐
實際運用中,我們需要處理各種各樣的日志文件,如果都是在配置文件里各自寫一行自己的表達式,太麻煩,我們建議是把所有的grok表達式統一寫入到一個地方。然后用filter/grok的patterns_dir 選項來指明。
如果你吧“message”里所有的信息都grok到不同的字段了,數據實質上就相當於是重復存儲了兩份。所以可以用remove_field參數來刪除掉message字段,或者用overwirte 參數來重寫默認的message字段,只保留最重要的部分。
重寫參數:
filter { grok { patterns_dir => "/path/to/your/own/patterns" match => { "message" => "%{SYSLOGBASE} %{DATA:message}" } overwirte => ["message"] } }
哎哎......有沒有講解的視頻啊~,求視頻!
**********
