Fluentd 作為日誌收集和處理工具,能與 Slack 等服務整合,提升監控效率。本文將示範如何設定 Fluentd 將日誌事件輸出到 Slack,並著重於 API Token 的安全處理,避免敏感資訊洩露。同時,我們也將探討如何利用環境變數外部化組態屬性,以及如何使用 @copy 外掛將日誌事件複製到多個目的地,包含檔案和標準輸出,並示範如何利用 @include 指令重用和擴充套件 Fluentd 設定檔,簡化設定管理。最後,我們將探討如何處理日誌事件複製過程中的錯誤,確保日誌資料的完整性和可靠性。
將Fluentd日誌事件輸出到Slack的完整
在現代化的軟體開發和維運過程中,日誌管理扮演著至關重要的角色。Fluentd作為一個強大的日誌收集和處理工具,能夠與多種系統和服務進行整合,將日誌事件輸出到不同的目標平台,如Slack。本篇文章將詳細介紹如何使用Fluentd將日誌事件輸出到Slack,並重點探討如何安全地處理憑證和令牌。
設定Fluentd輸出到Slack
要將Fluentd的日誌事件輸出到Slack,首先需要編輯現有的設定檔(位於Chapter4/Fluentd/rotating-file-read-slack-out.conf),加入從Slack設定中取得的詳細資訊。以下是一個範例設定檔的內容:
<match *>
@type slack
token "#{ENV['slack-token']}"
username UnifiedFluent
icon_emoji :ghost:
channel general
message Tell me if you've heard this before - %s
message_keys msg
title %s
title_keys tag
flush_interval 1s
</match>
設定解說
@type slack:指定輸出外掛為Slack。token "#{ENV['slack-token']}":使用環境變數slack-token中的值作為Slack的API令牌。這樣做可以避免將敏感資訊直接寫入設定檔中。username UnifiedFluent:在Slack中顯示的使用者名稱。icon_emoji :ghost::為Slack訊息設定一個表情符號。channel general:指定將訊息傳送到哪個Slack頻道。message和message_keys:定義要傳送的訊息內容和對應的日誌事件中的欄位。title和title_keys:定義訊息的標題和對應的日誌事件中的欄位。flush_interval 1s:設定Fluentd將日誌事件推播到Slack的頻率。
在執行之前,需要安裝Slack外掛,使用命令fluent-gem install fluent-plugin-slack。接著,可以透過以下命令啟動日誌模擬器和Fluentd:
fluentd -c Chapter4/Fluentd/rotating-file-read-slack-out.conf
groovy LogSimulator.groovy Chapter4/SimulatorConfig/social-logs.properties ./TestData/small-source.txt
啟動後,開啟Slack的#general頻道,就可以看到來自Fluentd的日誌事件訊息。
安全處理憑證和令牌
將憑證和令牌硬編碼在設定檔或程式碼中是一種不安全的做法。GitHub等服務會自動檢測並復原在提交記錄中發現的有效令牌。為了避免這種問題,可以採取以下策略:
- 將敏感憑證設定為環境變數,並限制其作用範圍。
- 使用金鑰管理服務(如HashiCorp的Vault)來儲存和管理憑證。
在Fluentd中使用環境變數
Fluentd允許在設定檔中嵌入Ruby程式碼片段。透過使用#{ENV['variable-name']}語法,可以存取環境變數。例如,將Slack令牌儲存在名為slack-token的環境變數中,可以這樣使用它:
token "#{ENV['slack-token']}"
首先,需要在系統中設定環境變數。在Linux或macOS上,可以使用以下命令:
export slack-token=xoxb-9999999999999-999999999999-XXXXXXXXXXXXXXXXXXXXXXXX
在Windows上,則使用:
set slack-token=xoxb-9999999999999-999999999999-XXXXXXXXXXXXXXXXXXXXXXXX
外部化Slack組態屬性實作
為了驗證組態是否正確,可以按照以下步驟進行:
- 設定名為
slack-token的環境變數,並將其值設為之前從Slack取得的令牌。 - 修改
Chapter4/Fluentd/rotating-file-read-slack-out.conf檔案,使用環境變數中的令牌。 - 重新執行日誌模擬器和Fluentd,確認日誌事件是否正確地傳送到Slack。
為多個輸出複製日誌事件
在前面的章節中,我們已經瞭解如何捕捉和儲存日誌事件。然而,在所有的例子中,路由都是將所有事件傳送到同一個輸出。然而,這並不是理想的情況。正如第1章所描述的,我們可能希望根據日誌事件的型別將其傳送到不同的工具,或者將一個日誌事件傳送到多個位置或不傳送。在本章中,我們將探討可以路由事件的不同方式。此外,我們還將研究一些較小的功能,它們可以幫助解決路由的挑戰,例如在日誌事件中新增資訊,以確保日誌事件的來源不會在傳輸過程中丟失。
路由通常與工作在個人或團隊之間的分配方式相一致。正如我們將看到的,使用包含(inclusions)支援多個團隊各自在其部分的Fluentd組態上工作,而不會干擾其他團隊,並注入特定的組態值。
使用@copy外掛進行複製
為了將日誌事件傳送到所有正確的輸出,一種方法是確保所有輸出都接收到該事件,並且每個輸出都包含一個或多個過濾器,以停止不想要的內容被輸出。在本文中,我們將重點介紹複製,並在稍後討論過濾。
預設情況下,日誌事件被第一個適當的match指令中的輸出外掛所消費。要使日誌事件到達多個輸出外掛,我們需要在match指令中使用@copy外掛。
每個目的地都包含在一個使用XML樣式標籤<store>和</store>定義的store宣告中。雖然store作為外掛名稱並不總是直觀(許多輸出是針對我們不常與儲存相關聯的解決方案,如Grafana),但值得記住的是,更多的Fluentd外掛處理的是檢索和儲存日誌事件。
組態示例
<match *>
@type copy
<store>
@type file
path /path/to/log/file.log
<format>
@type json
</format>
<buffer>
@type file
path /path/to/buffer/file.buffer
</buffer>
</store>
<store>
@type MySQL
host localhost
database log_database
table log_table
username log_user
password log_password
</store>
</match>
詳細解析:
@type copy:指定使用copy外掛,將日誌事件複製到多個輸出。<store>:定義一個輸出目的地,可以重複出現多次。@type file和@type MySQL:分別指定了兩個不同的輸出型別,一個是檔案,一個是MySQL資料函式庫。<format>:定義了輸出的格式,這裡使用JSON格式。<buffer>:定義了緩衝區的組態,用於最佳化輸出效能。
路由日誌事件的其他方法
除了使用@copy外掛外,Fluentd還提供了其他路由日誌事件的方法,例如使用標籤(tags)和標籤(labels)進行路由。這些方法將在後續章節中詳細介紹。
路由日誌事件的進階技巧
使用標籤和標籤進行路由
Fluentd允許您使用標籤和標籤對日誌事件進行分類別和路由。這種方法非常靈活,可以根據不同的需求對日誌事件進行處理。
<match tag.**>
@type copy
<store>
@type file
path /path/to/log/${tag}.log
</store>
<store>
@type MySQL
host localhost
database log_database
table log_table_${tag}
</store>
</match>
詳細解析:
tag.**:匹配所有帶有標籤的日誌事件。${tag}:在路徑或表名中使用標籤變數,使檔名或表名動態化。
新增額外資訊
在某些情況下,您可能需要在日誌事件中新增額外的資訊,例如主機名或額外的後設資料。Fluentd提供了相關的功能來實作這一點。
<filter tag.**>
@type record_transformer
<record>
hostname ${hostname}
</record>
</filter>
詳細解析:
@type record_transformer:指定使用記錄轉換器外掛。<record>:定義要新增到日誌事件中的額外記錄。
將日誌事件複製到多個輸出端
在每個儲存組態區塊中,我們可以組態外掛的使用。通常,這將是一個輸出外掛,但也可能是過濾器外掛。儲存外掛的屬性可以像在匹配指令中直接使用一樣進行組態,就像我們之前所做的那樣。這包括使用輔助外掛,例如緩衝區。
為了說明這一點,我們將採用檔案輸入,並擴充套件組態以將輸出傳送到檔案和標準輸出(控制檯),而不是將日誌事件從一個檔案傳送到另一個檔案,就像我們在第3章中所做的那樣。我們可以在圖5.2中看到這一點的表示。
組態多輸出端
要實作這一點,我們需要編輯匹配指令。最簡單的方法是首先將現有的輸出外掛屬性包裝在store標籤內,然後新增下一個store起始和結束標籤。隨著store起始和結束標籤的到位,每個輸出外掛都可以被組態。最後,在匹配指令的開頭引入@copy。
修改後的組態如下所示,其中包含兩個store區塊,每個區塊都包含一個輸出外掛(檔案和標準輸出)。您還將看到第三個store區塊,其輸出外掛型別為null,然後是一個@include指令。我們將在稍後解釋這些。
<match *>
@type copy
<store>
@type null
</store>
<store>
@type stdout
</store>
<store>
@type file
@id bufferedFileOut
tag bufferedFileOut
path ./Chapter5/fluentd-file-output
<buffer>
delayed_commit_timeout 10
flush_at_shutdown true
chunk_limit_records 500
flush_interval 30
flush_mode interval
</buffer>
<format>
@type out_file
delimiter comma
output_tag true
</format>
</store>
@include additionalStore.conf
</match>
內容解密:
@type copy:指定使用copy外掛,將日誌事件複製到多個輸出端。<store>標籤:定義每個輸出端的操作,可以是輸出外掛或轉發到另一個Fluentd節點。@type stdout:將日誌事件輸出到控制檯。@type file:將日誌事件輸出到檔案,並組態緩衝區和輸出格式。@include additionalStore.conf:包含額外的儲存組態。
執行示例
要執行此示例,需要以下命令:
fluentd -c ./Chapter5/Fluentd/file-source-multi-out.confgroovy LogSimulator.groovy ./Chapter5/SimulatorConfig/log-source-1.properties
執行這些命令後,日誌事件將很快出現在控制檯上。當緩衝區達到寫入點時,將出現名稱為fluentd-file-output.<日期>_<編號>.log的檔案。
按參照或按值複製
在大多數程式語言中,都有淺複製和深複製的概念,也稱為按參照複製和按值複製。按參照複製意味著日誌事件的副本透過參照同一記憶體位置來實作。如果日誌事件被修改,則該更改會影響所有後續使用。按值複製意味著取得新的記憶體並進行整體內容複製。
組態複製模式
在copy組態中,可以使用copy_mode屬性控制此行為。複製模式有幾個設定,從按參照複製到按值複製:
no_copy:預設狀態,實質上是按參照複製。shallow:對第一層值進行深複製,但如果這些物件又參照其他物件,則仍參照相同的記憶體。deep:正確的按值複製,使用Ruby的msgpackgem。marshal:當Ruby的msgpack無法使用時,可以使用原生語言物件序列化。
內容解密:
copy_mode屬性:控制日誌事件的複製行為。no_copy、shallow、deep、marshal:不同的複製模式,適用於不同的需求。- 使用Ruby的
dup方法進行淺複製,使用msgpackgem進行深複製。
路由日誌事件的複製與錯誤處理
在日誌事件的處理過程中,複製日誌事件到多個儲存位置是一項常見需求。然而,這種做法也帶來了一些挑戰,例如如何處理日誌事件的複製、如何處理錯誤等。
複製日誌事件的注意事項
當我們需要將日誌事件複製到多個儲存位置時,需要考慮如何正確地複製日誌事件。預設情況下,Fluentd 會將日誌事件複製到所有指定的儲存位置,但這可能會導致一些問題。例如,如果某個儲存位置無法接收日誌事件,則 Fluentd 會放棄將日誌事件傳送到後續的儲存位置。
程式碼範例:複製日誌事件的設定
<source>
@type tail
path /var/log/app.log
tag app.log
</source>
<match app.log>
@type copy
<store>
@type file
path /var/log/store1
</store>
<store>
@type file
path /var/log/store2
</store>
</match>
內容解密:
- 上述設定使用
copy外掛將日誌事件複製到兩個檔案儲存位置。 - 如果某個儲存位置發生錯誤,Fluentd 預設會放棄將日誌事件傳送到後續的儲存位置。
- 可以使用
ignore_error引數來控制是否忽略錯誤,繼續將日誌事件傳送到後續的儲存位置。
處理複製日誌事件時的錯誤
當複製日誌事件到多個儲存位置時,可能會遇到一些錯誤,例如某個儲存位置無法接收日誌事件。Fluentd 提供了一些機制來處理這些錯誤。
使用 ignore_error 引數
可以使用 ignore_error 引數來控制是否忽略錯誤,繼續將日誌事件傳送到後續的儲存位置。
<match app.log>
@type copy
<store ignore_error>
@type file
path /var/log/store1
</store>
<store>
@type file
path /var/log/store2
</store>
</match>
內容解密:
- 在上述設定中,如果
store1發生錯誤,Fluentd 會繼續將日誌事件傳送到store2。 - 使用
ignore_error引數可以提高日誌事件的可靠性和可用性。
組態的重用和擴充套件
隨著 Fluentd 組態的增長和複雜度的增加,我們可能需要重用某些組態或擴充套件現有的組態。Fluentd 提供了 @include 指令來實作組態的重用和擴充套件。
使用 @include 指令
可以使用 @include 指令來引入其他組態檔案或組態片段。
@include additionalStore.conf
<match app.log>
@type copy
<store>
@type file
path /var/log/store1
</store>
@include store2.conf
</match>
內容解密:
- 上述設定使用
@include指令引入了additionalStore.conf和store2.conf組態檔案。 - 可以使用
@include指令來重用和擴充套件現有的組態,提高組態的可維護性和可讀性。
Fluentd 設定檔重用與擴充套件:包含指令的應用
Fluentd 的設定檔可以透過包含指令(inclusion directive)來重用和擴充套件現有的組態內容。這種機制允許不同的團隊貢獻功能到單一執行環境中,例如 J2EE 伺服器,而不需要維護單一龐大的設定檔。
設定檔包含指令的使用
在 Fluentd 的設定檔中,可以使用 @include 指令來包含其他設定檔或片段。例如:
<match *>
@type copy
<store>
@type null
</store>
<store>
@type stdout
</store>
<store>
@type file
@id bufferedFileOut
tag bufferedFileOut
path ./Chapter5/fluentd-file-output
<buffer>
delayed_commit_timeout 10
flush_at_shutdown true
chunk_limit_records 500
flush_interval 30
flush_mode interval
</buffer>
<format>
@type out_file
delimiter comma
output_tag true
</format>
</store>
@include additionalStore.conf
</match>
@include record-origin.conf
在這個例子中,@include 指令用於包含 additionalStore.conf 和 record-origin.conf 兩個檔案。
設定檔包含的注意事項
- 包含的內容會影響主設定檔,因此需要小心放置包含指令。
- 如果包含的檔案路徑是相對路徑,則參考點是包含指令所在的檔案位置。
- 可以使用逗號分隔的列表來包含多個檔案,例如
@include file.conf, file2.conf。 - 可以使用萬用字元(例如
@include *.conf)來包含多個檔案,插入順序為字母順序。
使用 Null 輸出外掛進行佔位
在團隊合作開發中,可以使用 Null 輸出外掛來佔位,待其他團隊完成相關組態後再進行替換。例如:
<store>
@type null
@id inclusion
</store>
這種做法類別似於在程式碼中新增 TODO 註解,標記待完成的任務。
將包含指令與 MongoDB 輸出結合使用
透過將包含指令與 MongoDB 輸出外掛結合,可以實作將錯誤事件導向資料函式庫,方便統計和分析錯誤發生頻率和影響。例如,將 Chapter5/Fluentd/file-source-multi-out.conf 複製並修改為 Chapter5/Fluentd/file-source-multi-out-exercise.conf,將 @type null 替換為 MongoDB 輸出組態。
操作步驟
- 使用 dry-run 功能檢查組態是否有效。
- 執行 Fluentd 和 LogSimulator,分別使用以下命令:
fluentd -c ./Chapter5/Fluentd/file-source-multi-out-exercise.confgroovy LogSimulator.groovy ./Chapter5/SimulatorConfig/log-source-1.properties
程式碼解析
<match *>
@type copy
<store>
@type null
</store>
...
</match>
程式碼解密:
此段設定定義了一個匹配所有標籤的規則,並使用 @type copy 將事件複製到多個儲存目標。第一個儲存目標使用 @type null,表示丟棄接收到的日誌事件。
@include additionalStore.conf
@include record-origin.conf
程式碼解密:
這兩行使用 @include 指令分別包含了 additionalStore.conf 和 record-origin.conf 兩個設定檔。這種做法允許將不同的組態片段分開維護,最終在執行時合併成一個完整的組態。
<store>
@type null
@id inclusion
</store>
程式碼解密:
此段組態定義了一個使用 Null 輸出外掛的儲存目標,將接收到的日誌事件丟棄。這種做法常用於佔位,待其他團隊或開發者完成相關組態後再進行替換。