使用ELK管理SpringBoot日志
當(dāng)我們開發(fā)一個新項目的時候,一個經(jīng)常遇到的問題是日志的管理。ELK棧(Elastic,Logstash,Kibana)是一個功能強大且免費的日志管理解決方案。在本文中,將為您展示如何安裝、如何設(shè)置ELK,如何使用它來管理SpringBoot應(yīng)用程序中的默認(rèn)格式的日志。
在本文中,我們設(shè)置了一個演示SpringBoot應(yīng)用程序,并且啟用了日志管理,同時使用Logstash配置把日志條目送到了Elasticsearch。
應(yīng)用程序會把日志存在一個文件中。Logstash將讀取并解析日志文件并將日志條目發(fā)送給Elasticsearch實例。最后,我們將使用Kibana4(ElasticsearchWeb前端)來搜索和分析日志。
步驟一安裝Elasticsearch
下載Elasticsearch,下載地址:https://www.elastic.co/downloads/elasticsearch 解壓縮到一個路徑(解壓縮)
運行Elasticsearch(bin/elasticsearch或bin/elasticsearch.bat在Windows上) 檢查它是在使用curl-XGEThttp://localhost:9200運行 下面是如何操作(下面步驟是為OSX編寫的,但其它操作系統(tǒng)大致相同)
wgethttps://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.7.1.zip unzipelasticsearch-1.7.1.zip cdelasticsearch-1.7.1 bin/elasticsearch
現(xiàn)在,Elasticsearch應(yīng)該已經(jīng)在運行中了。您可以使用curl命令來驗證。在單獨的終端窗口中執(zhí)行Elasticsearch狀態(tài)頁面的GET請求: curl-XGEThttp://localhost:9200 如果一切正常,你應(yīng)該得到以下結(jié)果:
{ "status":200, "name":"Tartarus", "cluster_name":"elasticsearch", "version":{ "number":"1.7.1", "build_hash":"b88f43fc40b0bcd7f173a1f9ee2e97816de80b19", "build_timestamp":"2015-07-29T09:54:16Z", "build_snapshot":false, "lucene_version":"4.10.4" }, "tagline":"YouKnow,forSearch" }
步驟二安裝InstallKibana04
下載Kibana,下載地址:https://www.elastic.co/downloads/kibana(請注意你的系統(tǒng)屬性,下載與你系統(tǒng)相匹配的版本,鏈接給出的是OSX系統(tǒng)的)
解壓縮文件 運行Kivana(bin/kibana)
通過把瀏覽器指向Kibana's來檢查它是否在運行
下面是具體的做法:
wgethttps://download.elastic.co/kibana/kibana/kibana-4.1.1-darwin-x64.tar.gz tarxvzfkibana-4.1.1-darwin-x64.tar.gz cdkibana-4.1.1-darwin-x64 bin/kibana
將你的瀏覽器指向http://localhost:5601(如果頁面顯示正常,說明我做的很好,我們將在稍后配置它)。
步驟三安裝Logstash
下載Logstash,下載地址:https://www.elastic.co/downloads/logstash
提取文件(解壓縮) wgethttps://download.elastic.co/logstash/logstash/logstash-1.5.3.zip unziplogstash-1.5.3.zip
步驟四配置SpringBoot的日志文件
為了讓Logstash傳遞文件到Elasticsearch,我們必須先配置SpringBoot來把日志條目存儲到一個文件中。我們將建立以下傳遞路徑:SpringBootApp——日志文件——Logstash——Elasticsearch。這里還有其它的方法可以完成同樣的事情,比如配置logback來使用TCP附加器把日志發(fā)送到一個遠(yuǎn)程的Logstash,以及其它的有些配置。但我更喜歡文件方法,因為這樣更簡單、很自然(你可以很容易的把它添加到已存在的系統(tǒng)中),并且當(dāng)Logstash停止工作或者Elasticearch宕機的時候,不會丟失或者破壞任何文件。
不管如何,讓我們來配置SpringBoot的日志文件。最簡單的方法是在application.properties中配置日志文件。添加下面一行就足夠了:
logging.file=application.log 現(xiàn)在,SpringBoot將會在application.log中記錄ERROR,WARN和INFO級別的信息,并且當(dāng)信息量達(dá)到10M的時候更迭。
步驟五配置Logstash
通過配置Logstash可以了解SpringBoot的日志文件格式。這部分比較棘手?! ∥覀冃枰獎?chuàng)建一個Logstash配置文件。典型的Logstash配置文件包含三個部分:input、filter、output。每個部分包含執(zhí)行相關(guān)部分處理的插件,例如:從文件中讀取日志時間的文件輸入插件,或者將日志時間發(fā)送到Elasticsearch的elasticseatch輸出插件。
input部分定義了Logstash從哪里讀取輸入數(shù)據(jù)——在我們的例子中它是一個文件,所以我們將使用一個file插件multilinecodec。這基本上意味著我們的輸入文件可能每個條目有多行。
Input部分 下面是輸入部分的配置:
input{ file{ type=>"java" path=>"/path/to/application.log" codec=>multiline{ pattern=>"^%{YEAR}-%{MONTHNUM}-%{MONTHDAY}%{TIME}.*" negate=>"true" what=>"previous" } } }
我們將會用到file插件?! ype被設(shè)置為java——這只是額外的元數(shù)據(jù),以備將來使用多種類型的日志文件?! ath是日志文件的絕對路徑。它必須是絕對的——Logstash對這點很嚴(yán)格。
我們使用multilinecodec意味著多個行可能對應(yīng)著一個日志事件?! 榱藱z測在邏輯上與前一行分組的行,我們使用檢測模式: pattern=>"^%{YEAR}-%{MONTHNUM}-%{MONTHDAY}%{TIME}.*"→每個新的日志事件都需要以日期開始?! egate=>"true"→如果它不以日期開始...... what=>"previous"→...然后,它應(yīng)該與前一行分組?! ∥募斎氩寮?,就像配置的一樣,將會跟蹤日志文件(例如:只讀取文件末尾的新條目)。所以,測試的時候,為了讓Logstash讀取某些內(nèi)容,您需要生成新的日志條目。
Filter部分 Filter部分包含對日志時間執(zhí)行中間處理的插件。在我們的例子中國,事件可以是根據(jù)上述規(guī)則分組的單個日志行貨多行日志事件。在Filter部分,我們會做幾件事情:
如果一個日志事件包含堆棧跟蹤,我們會標(biāo)記它。這將有助于我們在后面尋找我們所期望的信息。解析出時間戳,日志等級,pid,線程,類名稱(記錄器實際)和日志信息。指定時間戳的區(qū)域和格式——Kibana將會用到它來進(jìn)行實踐的基本搜索。
上面提及的SpringBoot日志格式的過濾器部分看起來是這樣的: filter{ #Ifloglinecontainstabcharacterfollowedby'at'thenwewilltagthatentryasstacktrace if[message]=~"\tat"{ grok{ match=>["message","^(\tat)"] add_tag=>["stacktrace"] } } #GrokkingSpringBoot'sdefaultlogformat grok{ match=>["message", "(?%{YEAR}-%{MONTHNUM}-%{MONTHDAY}%{TIME})%{LOGLEVEL:level}%{NUMBER:pid}---\[(?[A-Za-z0-9-]+)\][A-Za-z0-9.]*\.(?[A-Za-z0-9#_]+)\s*:\s+(?.*)", "message", "(?%{YEAR}-%{MONTHNUM}-%{MONTHDAY}%{TIME})%{LOGLEVEL:level}%{NUMBER:pid}---.+?:\s+(?.*)" ] } #Parsingouttimestampswhichareintimestampfieldthankstopreviousgroksection date{ match=>["timestamp","yyyy-MM-ddHH:mm:ss.SSS"] } }
說明 if[message]=~"\tat"→如果消息包含后面跟著at的tab字符(這是ruby語法),那么...... ...使用grok插件來標(biāo)記堆棧蹤跡: match=>["message","^(\tat)"]→當(dāng)message匹配行的開頭,后面跟著tab,之后跟著at,然后是... add_tag=>["stacktrace"]→...用stacktrace標(biāo)簽標(biāo)記事件?! ∈褂胓rok插件進(jìn)行常規(guī)的SpringBoot日志消息解析: 第一種模式提取時間戳,級別,pid,線程,類名(實際上是記錄器名稱)和日志消息?! 〔恍业氖?,某些日志消息沒有類似于類名的記錄器名稱(例如,Tomcat日志),因此第二個模式將跳過記錄器/類字段并解析出時間戳,級別,pid,線程和日志消息。 使用date插件解析并設(shè)置事件日期: match=>["timestamp","yyyy-MM-ddHH:mm:ss.SSS"]→timestamp字段(早先grokked)包含指定格式的時間戳
Output部分 Output部分包含將事件數(shù)據(jù)發(fā)送到特定目標(biāo)的輸出插件。產(chǎn)出是事件管道的最后階段。我們將把日志事件發(fā)送到stdout(控制臺輸出,用于調(diào)試)和Elasticsearch。 與Filter分相比,Output部分非常簡單:
filter{ #Ifloglinecontainstabcharacterfollowedby'at'thenwewilltagthatentryasstacktrace if[message]=~"\tat"{ grok{ match=>["message","^(\tat)"] add_tag=>["stacktrace"] } } #GrokkingSpringBoot'sdefaultlogformat grok{ match=>["message", "(?%{YEAR}-%{MONTHNUM}-%{MONTHDAY}%{TIME})%{LOGLEVEL:level}%{NUMBER:pid}---\[(?[A-Za-z0-9-]+)\][A-Za-z0-9.]*\.(?[A-Za-z0-9#_]+)\s*:\s+(?.*)", "message", "(?%{YEAR}-%{MONTHNUM}-%{MONTHDAY}%{TIME})%{LOGLEVEL:level}%{NUMBER:pid}---.+?:\s+(?.*)"
]
}
#Parsingouttimestampswhichareintimestampfieldthankstopreviousgroksection
date{
match=>["timestamp","yyyy-MM-ddHH:mm:ss.SSS"]
}
}
說明:
我們正在使用多個輸出:stdout和elasticsearch。
stdout{...}→stdout插件將日志事件打印到標(biāo)準(zhǔn)輸出(控制臺)。
codec=>rubydebug→使用類似JSON格式的漂亮打印事件。
elasticsearch{...}→elasticsearch插件將日志事件發(fā)送到Elasticsearch服務(wù)器。
host=>"127.0.0.1"→Elasticsearch所在的主機名在我們的例子中是localhost。
Update5/9/2016:在編寫此更新時,Logstash的elasticsearch輸出插件的最新版本使用hosts配置參數(shù),而不是host上面的示例中所示。新參數(shù)將一組主機(例如elasticsearchcluster)作為值。換句話說,如果您正在使用最新的Logstash版本,請按如下所示配置elasticsearch輸出插件:
elasticsearch{
hosts=>["127.0.0.1"]
}
把各個部分放在一起
最后,三個部分——input,filter和output需要復(fù)制粘貼到一起并保存在Logstash.conf配置文件中。一旦配置文件就位,并且Elasticsearch運行,我們可以運行Logstash:
elasticsearch{
hosts=>["127.0.0.1"]
}
如果一切順利,Logstash正在傳遞日志時間到Elasticsearch。
步驟六配置Kibana
現(xiàn)在是我們再次訪問KibanawebUI的時候了,我們已經(jīng)在第二部中啟動了,它應(yīng)該在http://localhost:5601上運行。
首先,您需要將Kibana指向您選擇的elasticsearch索引。Logstash創(chuàng)建索引的名稱模式是:logstash-YYYY.MM.DD。在Kibana設(shè)置——索引中配置索引。
索引包含基于時間的事件(選擇此項)
使用事件時間創(chuàng)建索引名稱(選擇此項)
索引模式間隔:日
索引名稱或模式:[logstash-]YYYY.MM.DD
點擊“創(chuàng)建索引”
現(xiàn)在,點擊“Discover”標(biāo)簽。在我看來,“Discover”選項卡在Kibana中的確命名不正確-它應(yīng)該被標(biāo)記為“Search”而不是“Discover”,因為它允許您執(zhí)行新的搜索并保存/管理它們。日志事件現(xiàn)在應(yīng)該顯示在主窗口中。如果不是,則再次檢查屏幕右上角的時間段過濾器。默認(rèn)表格默認(rèn)有2列:Time和_source。為了使列表更有用,我們可以配置顯示的列。從左側(cè)的選擇菜單中選擇級別,類別和日志消息。
好的!您現(xiàn)在已準(zhǔn)備好使用ELK堆棧來控制日志,并開始自定義和調(diào)整日志管理配置。
您可以從這里下載這篇文章時使用的示例應(yīng)用程序:https://github.com/knes1/todo。它已被配置為將日志寫入文件,并具有上述的Logstash配置(盡管需要調(diào)整絕對路徑logstash.conf)。