Fluentd 作為一款開源的日誌收集器,在日誌管理領域扮演著重要角色。其靈活的組態和豐富的外掛生態,使得它能夠有效地處理各種日誌資料。本文將重點介紹如何利用 Fluentd 捕捉、解析和輸出日誌事件,並探討正規表示式(Regex)解析、輸出外掛應用、緩衝機制以及相關最佳實踐。在實際應用中,我們經常需要從非結構化的日誌資料中提取有用的資訊。Fluentd 的 Regex 解析器提供了一個強大的工具,可以根據自定義的模式匹配和提取日誌中的特定內容。同時,Fluentd 支援多種輸出外掛,可以將處理後的日誌資料輸出到不同的目標系統,例如檔案、資料函式庫和訊息佇列等。為了提高系統的吞吐量和穩定性,Fluentd 引入了緩衝機制,可以暫時儲存日誌事件,並在適當的時機批次輸出。
使用 Fluentd 捕捉日誌事件
SYSLOG
Syslog 是由作業系統和基礎設施程式產生的,但應用程式也可以使用這種格式。Syslog 條目的原始非官方結構已被 IETF 正式化為 RFC 3164(https://tools.ietf.org/html/rfc3164)。後來在 2009 年被 RFC 5424(https://tools.ietf.org/html/rfc5424)取代。由於一些硬體可能需要多年時間才會被替換,因此 Fluentd 可以處理兩種標準。預設情況下,Fluentd 將採用原始標準,但您可以透過設定 message_format 屬性(rfc3164、rfc5424、auto)來告訴 Fluentd 使用後來的標準或使用負載來處理。如果您知道將處理哪種格式,最好在組態中明確定義。這樣可以消除在解析之前評估每個事件的開銷。如果單個端點正在消耗兩種型別的事件,您可能不得不接受這個開銷。
該外掛有兩種不同的演算法用於處理事件——字串處理邏輯和正規表示式(regexp)。目前,預設是 regexp,但未來將更改為預設使用 string 選項,這比 regexp 演算法更快。如果您希望強制使用演算法,則需要使用 regexp 或 string 設定 parser_type 屬性。
第三方解析器
除了核心解析器之外,還有一些第三方解析器。以下是可能的選項的子集。然而,這些要麼是經過認證的,要麼是被大量下載的,因此它們很可能受益於廣泛的使用,並且由於程式碼是開源的,受益於 Linus 法則(給定足夠的關注,所有錯誤都是淺顯的——Eric Raymond)。
多格式解析器外掛用於 Fluentd
這嘗試使用定義順序中的不同格式模式來獲得匹配。它可以從 http://mng.bz/wnoO 獲得。
Grok 解析器用於 Fluentd
這使用根據 Grok 的方法從日誌條目中提取詳細資訊。它包括多行支援。它可以從 https://github.com/fluent/fluent-plugin-grok-parser 獲得。使用 Grok 解析器的好處是,Grok 被 Logstash 用作過濾和解析機制;因此,利用 Grok 預定義模式並在 Logstash 和 Fluentd 之間切換是一個相對較小的步驟。
將 Regex 解析器應用於複雜日誌
如前所述,Regex 或正規表示式解析器可能是最強大但最難使用的。在大多數 Regex 應用中,結果通常是單個結果、子字串或字串出現次數的計數。然而,當涉及到 Fluentd 時,我們需要 regex 生成多個值,例如設定日誌事件時間,將負載分解為 JSON 事件主體中的第一級元素。讓我們分解一個 Regex 表示式來突出基礎知識。但在這之前,我們需要使用一個真實的日誌條目。讓我們執行日誌模擬器組態,使用命令:
groovy LogSimulator.groovy Chapter3/SimulatorConfig/jul-log-file2.properties ./TestData/medium-source.txt
注意這與上一個示例的組態略有不同,因此我們可以在 Fluentd 中看到幾種可能性。檢視生成的輸出檔案(仍然是 structuredrolling-log.0.log),現在傳送的有效負載顯示為:
2020-04-30--20:10:52 INFO com.demo (6-1) {"log":"A clean house is the sign of a broken computer"}
在此輸出行中,我們可以看到應用的時間戳記,準確到秒,然後是一個空格,後面跟著日誌級別,再後面是包名,後面跟著編號方案,如前所述。最後,核心日誌條目被包裝為 JSON 結構。當我們解析訊息時,我們需要去掉那個 JSON 表示法,因為它不應該在我們想要的 JSON 結構中。
目標是在 Fluentd 中結束以下結構,以便我們可以使用這些值進行未來的操作:
{
"level": "INFO",
"class": "com.demo",
"line": 33,
"iteration": 1,
"msg": "What is an astronauts favorite place on a computer? The Space bar!"
}
以下是正規表示式,在其下方增加了字元位置,以便精確參照每個部分:
(?<time>\S+)\s(?<level>[A-Z]*)\s*(?<class>\S+)[^\d]*(?<line>[\d]*)\-(?<iteration>[\d]*)\)[\s]+\{"log":"(?<msg>.*(?="\}))
1234567890123456789012345678901234567890123456789012345678901234567
0 1 2 3 4 5 6
89012345678901234567890123456789012345678901234567890123
7 8 9 10 11 12
作為表示式的一部分,我們需要使用 Regex 的能力來定義文字組。組的範圍由開閉括號定義(例如,字元 1 和 12)。要將一些源文字分配給 JSON 元素,我們需要使用 ?<name>,其中名稱是要出現在 JSON 中的元素名稱。在我們的例子中,它應該是 level、class、line、iteration 和 msg 的值。除此之外,我們還需要捕捉日誌事件時間與預設時間值。這可以在字元 2 和 8 之間看到,例如,在字元 16 和 23 之間。緊接著這之後,我們可以使用 Regex 表示法來描述要捕捉的文字。為此,我們使用 \S(字元 9 和 10),它表示非空白字元;透過新增 +(字元 11),我們宣告這應該發生一次或多次。
內容解密:
- 正規表示式的組成:表示式
(?<time>\S+)\s(?<level>[A-Z]*)\s*(?<class>\S+)[^\d]*(?<line>[\d]*)\-(?<iteration>[\d]*)\)[\s]+\{"log":"(?<msg>.*(?="\}))用於捕捉日誌事件的不同部分,包括時間、日誌級別、類別名、行號、迭代次數和訊息。 - 命名捕捉組:表示式中使用了命名捕捉組(如
(?<time>\S+)),以便將匹配的文字直接對映到 JSON 結構中的相應欄位。 - 字元匹配:
\S+用於匹配一個或多個非空白字元,而[A-Z]*用於匹配零個或多個大寫字母。同樣,\d*用於匹配零個或多個數字。 - 日誌結構解析:透過這個正規表示式,可以將具有特定結構的日誌條目解析為 JSON 結構,從而方便進一步處理和分析。
- 適用場景:這種技術特別適用於處理具有複雜或非標準格式的日誌檔案,能夠有效地抽取有價值的資訊。
使用 Fluentd 捕捉日誌事件的正規表示式解析
在處理日誌事件時,Fluentd 提供了多種解析器(parser)來幫助我們從日誌中提取有用的資訊。其中,正規表示式(Regular Expression)解析器是一種非常強大且靈活的工具,可以用來匹配和提取日誌中的特定模式。
正規表示式的應用
假設我們有以下格式的日誌事件:
2023-04-01--12:00:00 INFO com.example.ClassName 123-456 {"log":"This is a log message"}
我們可以使用正規表示式來解析這個日誌事件,提取出時間、日誌級別、類別名稱、行號、迭代次數和日誌訊息等資訊。
正規表示式的組成
我們的正規表示式如下:
/(?<time>\S+)\s(?<level>[A-Z]*)\s*(?<class>\S+)[^\d]*(?<line>[\d]*)\-(?<iteration>[\d]*)\)[\s]+\{"log":"(?<msg>.*(?="\}))/
讓我們逐步解析這個正規表示式:
(?<time>\S+):匹配時間戳,使用\S+匹配一個或多個非空白字元。\s:匹配一個空白字元。(?<level>[A-Z]*):匹配日誌級別,使用[A-Z]*匹配零個或多個大寫字母。\s*:匹配零個或多個空白字元。(?<class>\S+):匹配類別名稱,使用\S+匹配一個或多個非空白字元。[^\d]*:匹配零個或多個非數字字元。(?<line>[\d]*):匹配行號,使用[\d]*匹配零個或多個數字。-:匹配一個連字號。(?<iteration>[\d]*):匹配迭代次數,使用[\d]*匹配零個或多個數字。\):匹配一個右括號。[\s]+:匹配一個或多個空白字元。\{"log":":匹配字串"log":"。(?<msg>.*(?="\})):匹配日誌訊息,使用.*匹配任意字元,直到遇到"}為止。
組態 Fluentd
要在 Fluentd 中使用這個正規表示式,我們需要在組態檔案中定義一個 regexp 型別的解析器:
<parse>
@type regexp
Expression /(?<time>\S+)\s(?<level>[A-Z]*)\s*(?<class>\S+)[^\d]*(?<line>[\d]*)\-(?<iteration>[\d]*)\)[\s]+\{"log":"(?<msg>.*(?="\}))/
time_format %Y-%m-%d--%T
time_key time
</parse>
這個組態告訴 Fluentd 使用正規表示式解析器,並定義了時間戳的格式和鍵名。
結果
當 Fluentd 處理日誌事件時,它將使用正規表示式解析器提取出相關資訊,並輸出到控制檯。輸出的結果將是一個 JSON 物件,包含提取出的資訊:
2023-04-01 12:00:00.000000000 +0800 tag: {"level":"INFO","class":"com.example.ClassName","line":"123","iteration":"456","msg":"This is a log message"}
程式碼解密:
(?<time>\S+):此部分用於捕捉時間戳,透過\S+確保至少捕捉一個非空白字元,從而正確提取時間資訊。(?<level>[A-Z]*):此部分負責捕捉日誌級別,利用[A-Z]*可以匹配到由大寫字母組成的級別名稱,如 “INFO” 或 “ERROR”。(?<class>\S+):此段正規表示式用於捕捉類別名稱,透過\S+可以完整提取出類別名稱,無論其包含多少字元。(?<line>[\d]*)和(?<iteration>[\d]*):這兩部分分別用於捕捉行號和迭代次數,利用[\d]*可以提取數字資訊,即使是空值也能妥善處理。(?<msg>.*(?="\})):此部分負責捕捉日誌訊息主體,透過.*可以匹配任意字元,直到遇到指定終止符"},確保訊息內容被完整提取。
使用 Fluentd 捕捉日誌事件的進階技巧
正規表示式(Regex)在日誌解析中的應用與挑戰
在處理多樣化的日誌格式時,Fluentd 的正規表示式解析功能顯得尤為重要。正確地定義 Regex 模式能夠有效地從非結構化的日誌中提取有價值的資訊。然而,編寫有效的 Regex 模式可能相當具有挑戰性。
Regex 模式驗證工具
為瞭解決這一問題,Fluentd 提供了 UI 組態介面來驗證 Regex 表示式。此外,還有許多第三方工具可供使用,例如:
- Fluentular(https://fluentular.herokuapp.com/):專門為 Fluentd 設計的 Regex 開發和測試工具。
- Regexp Explain(http://mng.bz/q2YA):Visual Studio Code 中的 Regex 視覺化工具,有助於理解 Regex 模式的結構。
- regexper.com(https://regexper.com/):提供 Regex 模式的視覺化表示。
這些工具可以幫助開發者更直觀地理解和除錯 Regex 模式,從而提高日誌解析的效率和準確性。
在 Fluentd 中應用自定義的 Regex 解析器
以下是一個具體的例子,展示瞭如何在 Fluentd 中使用自定義的 Regex 解析器來結構化日誌事件:
<parse>
@type regexp
Expression /(?<time>\S+)\s(?<level>[A-Z]*)\s*(?<class>\S+)[^\d]*(?<iteration>[\d]*)\-(?<line>[\d]*)\][\s]+\{"event":"(?<msg>.*(?="\,))/
time_format %Y-%m-%d--%T
time_key time
keep_time_key true
types line:integer,iteration:integer
</parse>
程式碼解析
@type regexp:指定使用 Regex 解析器。Expression:定義用於匹配日誌事件的 Regex 模式。在這個例子中,它提取了時間戳(time)、日誌級別(level)、類別(class)、迭代次數(iteration)、行號(line)以及事件訊息(msg)等資訊。time_format %Y-%m-%d--%T:指定時間戳的格式。time_key time:指定包含時間戳的鍵名。keep_time_key true:將原始時間戳保留在 JSON 載荷中。types line:integer,iteration:integer:明確指定某些欄位的資料型別,這裡將line和iteration定義為整數型別。
透過這種方式,Fluentd 能夠更準確地解析和結構化原本非結構化的日誌資料,為後續的分析和處理提供了便利。
練習與實踐
為了更好地掌握 Fluentd 的日誌解析功能,建議進行以下練習:
- 複製提供的 Fluentd 組態檔案,並修改其中的 Regex 表示式,以正確解析目標日誌格式。
- 使用提供的日誌模擬器組態檔案執行模擬日誌生成,並觀察 Fluentd 的解析結果。
- 利用上述的 Regex 驗證工具最佳化你的 Regex 表示式。
透過實踐,你將能夠更深入地理解 Fluentd 的日誌解析機制,並掌握如何根據具體需求調整和最佳化組態。
使用 Fluentd 輸出日誌事件
在第三章中,我們已經展示瞭如何捕捉日誌事件以及如何使用解析器等輔助外掛。但是,捕捉資料只有在我們能夠對其進行有意義的操作時才具有價值,例如將資料傳遞到端點並格式化,以便日誌事件可以被使用——例如,將事件儲存在日誌分析引擎中或向維運(Ops)團隊傳送訊息以進行調查。本章將展示 Fluentd 如何實作這一點。我們將探討如何使用 Fluentd 輸出外掛將日誌事件寫入檔案,以及 Fluentd 如何與 MongoDB 和 Slack 等協作/社交工具配合使用,以實作快速通知。
本章涵蓋以下內容:
- 使用輸出外掛將日誌事件寫入檔案、MongoDB 和 Slack
- 應用不同的緩衝選項與 Fluentd
- 評估緩衝的好處
- 處理緩衝區過載和其他緩衝風險
- 新增格式化程式來結構化日誌事件
檔案輸出外掛
與 tail(檔案輸入)外掛相比,我們較少使用檔案輸出外掛,因為通常我們希望將輸出傳遞到允許查詢、分析和視覺化事件的工具。當然,在生產環境中,檔案輸出有其合理的使用場景。然而,它是逐步過渡到更先進工具的最佳選擇之一,因為它易於檢視結果和各種外掛(如解析器和過濾器)的影響。將重要事件記錄到檔案中也便於將來需要時存檔日誌事件(例如,稽核日誌事件以支援法律要求)。因此,我們將首先介紹檔案輸出,然後再轉向更複雜的輸出。
在使用檔案輸出(以及任何直接或間接寫入物理儲存的輸出)時,我們需要考慮幾個因素:
- 檔案系統中的寫入位置受儲存容量和許可權的限制
- 該位置是否具有足夠的容量(既包括分配的容量,也包括物理容量)
- 物理硬體能夠提供的 I/O 吞吐量是多少
- 資料存取是否存在延遲(NAS 和 SAN 裝置透過網路存取)
雖然基礎設施效能不太可能影響開發工作,但在預生產(例如,效能測試環境)和生產環境中卻極為重要。值得注意的是,裝置效能對於檔案外掛至關重要。其他輸出外掛可能會使用包含最佳化 I/O 邏輯的服務(例如,資料函式庫快取、分配的檔案空間最佳化)。
使用輸出外掛時,我們可能已經整合了多個日誌事件源。因此,我們最終可能會得到一個組態,讓 Fluentd 將所有輸入寫入一個檔案或位置。物理效能問題可以透過使用緩衝(我們很快就會看到)和快取來緩解。
基本檔案輸出
讓我們從一個相對基本的檔案輸出組態開始。在之前的所有章節示例中,我們只是將內容寫入控制檯。現在,我們不再寫入控制檯,而是將所有內容寫入檔案。要做到這一點,我們需要在組態中新增一個新的匹配指令,但我們將繼續使用檔案源來生成日誌事件。
為了說明輸出外掛可以處理組態中的多個輸入,除了日誌檔案源之外,我們還包含了上一章中所示的自我監控源組態。要控制 Fluentd 自我監控生成的日誌事件的頻率,我們可以定義另一個屬性 emit_interval,它接受一個持續時間值——例如,10 秒。emit_interval 提供的值是 Fluentd 生成日誌事件之間的時間間隔。自我監控可以包括諸如已處理的事件數量、管理的 worker 程式數量等詳細資訊。
檔案輸出外掛至少需要定義 type 屬性和指向輸出位置的 path 屬性。在下面的列表中,我們可以看到 Chapter4/Fluentd/rotating-file-read-file-out.conf 檔案的相關部分。這個組態的結果可能會讓你感到驚訝,但讓我們看看會發生什麼。
<source>
@type monitor_agent
bind 0.0.0.0
port 24220
@id in_monitor_agent
include_config true
tag self
emit_interval 10s
</source>
<match *>
@type file
path ./Chapter4/fluentd-file-output
</match>
如果使用以下命令執行 LogSimulator 和 Fluentd,則可以看到使用這個新的匹配指令的結果:
fluentd -c ./Chapter4/Fluentd/rotating-file-read-file-out.confgroovy LogSimulator.groovy ./Chapter4/SimulatorConfig/jul-log-output2.properties ./TestData/medium-source.txt
簡單的預測是所有內容都被寫入名為 fluentd-file-output 的檔案中。然而,實際發生的情況是建立了一個資料夾,使用路徑的最後一部分作為其名稱(即 fluentd-file-output),並且在該資料夾中可以看到兩個檔案。該檔案將以半隨機名稱出現(以區分不同的緩衝檔案),並且具有相同基本名稱的後設資料檔案。Fluentd 所做的是隱式地使用了緩衝機制。採用預設選項的緩衝在輸出外掛中並不罕見;一些外掛放棄使用緩衝——例如,stdout 外掛。
緩衝基礎
正如您可能從第一章中回憶的那樣,緩衝是 Fluentd 的輔助外掛。輸出外掛需要了解它們可能對 I/O 效能產生的影響。因此,大多數輸出外掛使用可以同步或非同步執行的緩衝外掛。
緩衝內容解密:
- 緩衝的作用:緩衝是用於臨時儲存資料的區域,用於平衡生產者和消費者之間的資料處理速度差異。
- 同步與非同步緩衝:同步緩衝是指資料寫入緩衝區後立即被處理,而非同步緩衝則允許資料在緩衝區中累積後再被處理。
- Fluentd 中的緩衝:Fluentd 使用緩衝外掛來最佳化 I/O 操作,大多數輸出外掛都支援緩衝,以提高效能和可靠性。
透過這種方式,Fluentd 能夠有效地管理和輸出日誌事件,從而滿足不同的應用需求和場景。