Fluentd 的 Label 機制提供更彈性的日誌路由和處理方式,相較於傳統的 tag,Label 更適合複雜的日誌流程管理。透過 @label 指令,可以將日誌事件導向特定 Label 管道,管道中可包含多個 filter 和 match 指令,實作 filter、enrich、re-route 等操作。複雜場景下可串接多個 Label 管道,順序不影響處理流程,提升架構彈性。Fluentd 也提供多種過濾器,例如 record_transformer 可修改及新增欄位,grep 則可根據特定規則篩選日誌。這些過濾器搭配 Elasticsearch 等輸出外掛,可有效簡化日誌分析流程,提升系統監控效率。此外,Fluentd 也能妥善處理敏感資訊,例如信用卡號或個資,透過遮蔽或刪除等方式確保資料安全,符合 GDPR 等規範。

深入理解Fluentd中的Label機制

在Fluentd的組態中,Label是一種強大的工具,用於管理和路由日誌事件。與傳統的tag機制相比,Label提供了更靈活和可擴充套件的方式來處理複雜的日誌處理流程。

Label的基本概念

Label在Fluentd中是一個獨立的處理管道,可以包含多個過濾器(filter)和輸出(match)指令。透過使用@label指令,可以將日誌事件定向到特定的Label進行處理。

組態Label管道

以下是一個基本的Label組態範例:

<label labelPipeline>
  <filter *>
    @type stdout
  </filter>
  <match *>
    @type copy
    <store>
      @type file
      path ./Chapter5/label-pipeline-file-output
      <buffer>...</buffer>
      <format>...</format>
    </store>
    <store>
      @type relabel
      @label common
    </store>
  </match>
</label>

內容解密:

  1. <label labelPipeline>定義了一個名為labelPipeline的Label管道。
  2. <filter *>對所有進入該Label的日誌事件進行過濾處理,這裡使用的是stdout型別,表示將日誌事件輸出到控制檯。
  3. <match *>匹配所有日誌事件,並使用copy外掛將事件複製到多個輸出目的地。
  4. 第一個<store>將日誌事件輸出到檔案。
  5. 第二個<store>使用relabel外掛將日誌事件的Label更改為common,並繼續處理。

連線多個Label管道

在複雜的組態中,可能需要連線多個Label管道來實作更靈活的日誌處理流程。這可以透過relabel外掛來實作。

graph LR
    A[basic-file.txt] -->|labelPipeline|> B[label-pipeline-file-output]
    B -->|relabel|> C[common]
    D[basic-file2.txt] -->|common|> C
    C -->|file|> E[alt-file-output]

此圖示展示了兩個日誌源透過不同的Label管道進行處理,最終都輸出到alt-file-output檔案。

內容解密:

  1. 日誌源basic-file.txtbasic-file2.txt分別被定向到不同的Label管道。
  2. labelPipeline管道對日誌事件進行處理後,透過relabel外掛將事件定向到common管道。
  3. common管道最終將日誌事件輸出到檔案。

Label的排序無關性

與tag機制不同,Label的相對位置不會影響日誌事件的處理順序。這意味著可以在組態檔案中靈活地組織Label的順序,而不必擔心處理流程受到影響。

實際應用場景

在實際應用中,可以利用Label機制實作複雜的日誌處理流程,例如:

  1. 將日誌事件先進行過濾和轉換,然後再輸出到不同的目的地。
  2. 將不同來源的日誌事件匯聚到同一個Label管道進行統一處理。
  3. 透過連線多個Label管道,實作更靈活和可擴充套件的日誌處理架構。

過濾與擴充日誌事件

在第5章中,我們曾經提及使用filter指令將日誌事件輸出到標準輸出。雖然這種方式很有用,但它只是filter指令全部功能的一個小側面。filter指令可以幫助我們實作以下功能:

控制日誌事件的流程

  • 過濾特定的日誌事件,以便只有特定的日誌事件被傳送到特定的消費系統
  • 從日誌事件訊息中過濾出特定的部分,並將它們記錄為日誌事件的獨立屬性(最終使得對這些資料應用邏輯變得更容易)

本章涵蓋的內容

  • 應用過濾器控制日誌事件
  • 實作record_transformer過濾器
  • 從日誌事件中擷取資訊
  • 將環境資訊注入日誌事件
  • 遮罩日誌事件中的元素以維護資料安全性

深入瞭解過濾器

Fluentd的filter指令提供了一種強大的方式來處理和轉換日誌事件。透過使用不同的過濾器,我們可以根據需求對日誌事件進行過濾、轉換和增強。

使用record_transformer過濾器

record_transformer過濾器是一種非常有用的工具,它允許我們對日誌事件的記錄進行轉換和增強。我們可以使用它來新增、刪除或修改記錄中的欄位。


#### 範例程式碼:使用`record_transformer`過濾器
```xml
<filter my.tag>
  @type record_transformer
  <record>
    hostname ${hostname}
    timestamp ${time}
  </record>
</filter>

內容解密:

  • @type record_transformer指定了過濾器的型別為record_transformer
  • <record>區塊定義了要新增到日誌事件記錄中的新欄位
  • ${hostname}${time}是內建的變數,分別代表主機名稱和時間戳記

從日誌事件中擷取資訊

除了轉換記錄外,Fluentd還提供了多種方式來從日誌事件中擷取資訊。例如,我們可以使用正規表示式來從日誌訊息中提取特定的資料。

範例程式碼:使用正規表示式擷取資訊

<filter my.tag>
  @type parser
  key_name log_message
  <parse>
    @type regexp
    expression /^(?<log_level>\w+): (?<message>.*)$/
  </parse>
</filter>

內容解密:

  • @type parser指定了過濾器的型別為parser
  • key_name log_message指定了要解析的日誌事件欄位名稱
  • <parse>區塊定義瞭解析的規則,使用正規表示式從log_message欄位中提取log_levelmessage

將環境資訊注入日誌事件

在某些情況下,我們可能需要將環境資訊注入日誌事件中,以便更好地理解和分析日誌資料。

範例程式碼:注入環境資訊

<filter my.tag>
  @type record_transformer
  <record>
    env ${ENV['MY_ENV_VAR']}
  </record>
</filter>

內容解密:

  • ${ENV['MY_ENV_VAR']}用於取得環境變數MY_ENV_VAR的值,並將其新增到日誌事件記錄中

遮罩日誌事件中的元素以維護資料安全性

為了維護資料安全性,我們可能需要遮罩日誌事件中的敏感資訊,例如密碼或個人識別資訊。

範例程式碼:遮罩敏感資訊

<filter my.tag>
  @type record_transformer
  <record>
    sensitive_info ${record['sensitive_info'] | '***'}
  </record>
</filter>

內容解密:

  • ${record['sensitive_info'] | '***'}用於遮罩sensitive_info欄位的值,如果該欄位存在,則將其值替換為***

過濾與推斷日誌事件的關鍵技術

在日誌管理與分析過程中,過濾和推斷日誌事件是至關重要的環節。這不僅能幫助我們更好地理解系統的執行狀態,還能及時發現潛在的問題並進行處理。本章將探討日誌事件過濾的應用場景和技術實作。

為什麼需要過濾日誌事件?

首先,我們需要了解為什麼要過濾日誌事件。許多日誌資訊其實是在告訴我們系統執行正常,這些資訊對於監控系統狀態非常重要。然而,並非所有這些資訊都需要被廣泛分發和儲存。例如,像 Elastic Beats 這樣的工具可以產生心跳日誌事件,表明系統執行正常,但這些資訊通常不需要被保留或分發到下游系統。

過濾日誌事件的應用場景

1. 篩選無關緊要的日誌事件

過濾掉那些確認系統執行正常的無關緊要的日誌事件,可以減少資料傳輸量和儲存成本。這樣做不僅能節省頻寬和硬體資源,還能讓重要的事件更容易被發現。

2. 識別潛在問題

有些日誌事件可能被錯誤地分類別為資訊或除錯級別,但實際上它們是某些重大問題的預警。過濾器可以幫助識別和標記這些事件,以便及時處理。

3. 處理虛假緊急情況

在某些情況下,警告或錯誤日誌可能會觸發不必要的緊急應對。透過定義過濾規則,我們可以區分真正需要立即處理的事件和可以按正常流程處理的事件,從而避免不必要的升級和混亂。

4. 調整日誌級別

有時,日誌事件可能被賦予了過高的級別(例如,將警告級別的日誌誤標為錯誤級別)。透過過濾器,我們可以調整這些日誌事件的級別,使其更準確地反映實際情況。

如何實作日誌事件過濾?

實作日誌事件過濾需要根據具體的需求和技術堆疊選擇合適的工具和方法。例如,可以使用 Fluentd 這樣的日誌收集和處理工具,透過組態過濾器來豐富、修改或篩選日誌事件。

程式碼範例:使用 Fluentd 過濾日誌事件

# 使用 Fluentd 的 filter 外掛來修改日誌事件
<filter **>
  @type record_transformer
  <record>
    # 為日誌事件新增新的欄位
    hostname ${hostname}
    # 修改現有的欄位
    log_level ${record['level']}
  </record>
</filter>

內容解密:

  1. 這段程式碼使用了 Fluentd 的 record_transformer 外掛來修改或新增日誌事件中的欄位。
  2. ${hostname} 用於動態取得主機名稱並新增到日誌事件中。
  3. ${record['level']} 用於存取現有的日誌級別欄位,並可以根據需要進行修改。
  4. 這種方式可以靈活地對日誌事件進行豐富和修改,以滿足不同的需求。

為何需要修改日誌事件?

在處理日誌事件的過程中,我們經常需要從日誌中提取更多的意義。日誌事件可能是非結構化、半結構化,甚至是結構化的,但仍需要重新解析成合適的資料結構(例如讀取JSON文字檔)。這種結構化的資料可以幫助我們過濾、路由、建立新的報告指標,並利用日誌事件資料進行測量。一旦我們投入了努力從日誌事件中提取意義,為什麼不讓下游的處理更容易呢?換句話說,就是應用DRY(不要重複自己)的原則。因此,如果已經提取了意義和結構,就不要讓別人再重複做一次。只需將衍生的資訊與日誌事件一起傳遞即可。

6.2.1 方便下游處理

當我們處理日誌事件時,經常需要提取更多的意義。日誌事件可能是非結構化、半結構化,甚至是結構化的,但仍需要重新解析成合適的資料結構。結構化的資料可以幫助我們過濾、路由、建立新的報告指標,並利用日誌事件資料進行測量。將提取的意義與日誌事件一起傳遞,可以避免下游的重複處理。

6.2.2 新增上下文

正確處理事件可能需要額外的上下文。當試圖診斷應用程式效能不佳的原因時,通常會檢視事件周圍發生了什麼——例如,伺服器是否執行了大量的執行緒?有時很容易將上下文資料與日誌事件連結起來。最簡單的方法是將額外的上下文新增到日誌事件中。

6.2.3 記錄對日誌事件的反應

我們已經提到,可能會因為日誌事件而啟動某種操作。回顧過去,瞭解哪些事件觸發了操作是有幫助的。將資訊新增到觸發的日誌事件中,可以是一種更直接、可接受的操作,而不是稍後將單獨的日誌事件相關聯,以顯示因果關係。

6.2.4 資料遮蔽/掩碼

在開發軟體時,經常需要在開發階段記錄整個被處理的資料物件。在開發和測試階段,這不是問題,因為只是測試資料。但如果資料包含敏感資訊,例如可以用來識別個人的資料(PII,個人可識別資訊),就像在醫療保健或信用卡使用中一樣,它就變成了一個挑戰。任何處理這種資料的IT系統部分都會受到許多法律、立法和合約技術要求的約束。這些要求來自國際、國家和地區的資料法律,例如:

  • GDPR(通用資料保護規則)
  • HIPAA(健康保險可攜性和責任法案)和其他醫療保健立法
  • PCI DSS(支付卡行業資料安全標準)

您可以新增許多公司可能也希望以同樣的敏感性對待一些財務會計資料。明顯的解決方案是修復軟體,使其不記錄資料或限制這種記錄的影響,限制需要應用額外極其嚴格的控制、安全機制和報告的“爆炸半徑”。Fluentd提供了優秀的手段來解決這個問題:

  • 從日誌中刪除或遮蔽/掩碼資料。掩碼通常是透過用無意義的值替換敏感值來完成的。遮蔽是透過刪除通訊中的資訊或根本不使其在日誌中可見等方式來實作的。我們可以在支付卡收據上看到資料被掩碼,用星號或雜湊字元替換您的卡號。只要不能反轉以取得原始資料,任何掩碼方法都可以使用。
  • 將Fluentd與日誌源放在一起,以便受限於提高的資料安全要求的基礎設施數量減少。提高的安全範圍越小,“攻擊面”就越小(即可能受到惡意攻擊的伺服器和軟體元件數量越小,越好)。
  • 使用RPC(遠端程式呼叫)技術直接將主應用程式的日誌連線到Fluentd,而不是使用日誌檔,以便日誌事件是瞬態的。

Fluentd 處理敏感資訊程式碼範例

# 使用Fluentd的filter外掛來遮蔽敏感資訊
<filter logs.**>
  @type record_transformer
  <record>
    # 將信用卡號碼替換為掩碼值
    credit_card "#{record['credit_card'].gsub(/\d{12}/, '************')}"
  </record>
</filter>

內容解密:

此段程式碼使用了Fluentd的record_transformer過濾器外掛來遮蔽日誌中的信用卡號碼。其中:

  1. <filter logs.**>指定了要過濾的日誌標籤。
  2. @type record_transformer定義了使用的過濾器型別。
  3. <record>區塊內定義了要對日誌記錄進行的轉換。
  4. credit_card "#{record['credit_card'].gsub(/\d{12}/, '************')}"這行程式碼將信用卡號碼中的12位數字替換為*,實作了對敏感資訊的遮蔽。

安全不是成本

很容易得出這樣的結論:安全是一種不受歡迎的成本,避免安全是好的。但現實是,今天的安全應該被視為一種資產,安全性的應用是一個正面的賣點。像Oracle這樣的SaaS解決方案提供商確實將他們的安全性作為一個優點。資料丟失的成本影響,特別是在影響程度不受限制或不被理解時,可能會非常嚴重。因此,將安全性視為資產,而不是成本,是非常重要的。

過濾與解析日誌事件

在處理日誌事件時,過濾和解析是非常重要的步驟。Fluentd 提供了多種內建的過濾外掛,可以幫助我們實作日誌事件的路由和操作。

過濾外掛

Fluentd 的核心內建了多種過濾外掛,包括:

  • record_transformer:最為複雜的內建過濾器,提供多樣化的選項來操作日誌事件。
  • grep:允許定義規則來過濾日誌事件的屬性,可以提供多個表示式來定義累積規則。
  • filter_parser:結合瞭解析器外掛和過濾器的功能。
  • stdout:允許所有事件透過過濾器,並將其寫入 stdout。

使用 grep 過濾器

grep 外掛允許我們定義一個搜尋表示式,並將其應用到日誌事件中的指定屬性。例如,我們可以擴充套件路由,使得事件中的日誌條目明確提到電腦。以下是一個例子:

<filter *>
  @type grep
  <regexp>
    key msg
    pattern /computer/
  </regexp>
</filter>

這個組態定義了一個過濾器,使用 grep 外掛,並應用一個正規表示式到 msg 屬性。如果 msg 中包含 “computer”,則該事件會被保留。

將過濾後的日誌事件輸出到 Elasticsearch

為了將匹配的日誌事件傳送到 Elasticsearch,我們需要使用 match 指令和 @type 值為 elasticsearch。Elasticsearch 外掛非常可組態,具有超過 30 個屬性,可以控制從快取控制到日誌事件如何被填充和索引等行為。

<match *>
  @type elasticsearch
  host localhost
  port 9200
  scheme http
  reload_on_failure true
  index_name fluentd-book
  logstash_format false
  include_tag_key true
  tag_key key
  <buffer>
    flush_interval 5s
  </buffer>
</match>

這個組態將匹配的日誌事件輸出到本地的 Elasticsearch,索引名為 fluentd-book,並且每 5 秒重新整理一次緩衝區。

組態詳解

  • @type elasticsearch:指定輸出外掛為 Elasticsearch。
  • host 和 port:指定 Elasticsearch 的主機和埠。
  • scheme:指定通訊協定,http 或 https。
  • index_name:指定索引名稱。
  • logstash_format:是否按照 Logstash 的格式輸出。
  • include_tag_key:是否包含標籤鍵值。
  • tag_key:指定標籤鍵值的名稱。
  • flush_interval 5s :設定緩衝區的重新整理間隔為 5 秒。

程式碼解析:

<filter *>
  @type grep
  <regexp>
    key msg
    pattern /computer/
  </regexp>
</filter>
<match *>
  @type elasticsearch
  host localhost
  port 9200
  scheme http
  reload_on_failure true
  index_name fluentd-book
  logstash_format false
  include_tag_key true
  tag_key key
  <buffer>
    flush_interval 5s
  </buffer>
</match>

內容解密:

  1. 首先,定義了一個過濾器,使用 @type grep 指定使用 grep 外掛。<regexp> 部分定義了要對哪個欄位 (key msg) 使用正規表示式 (pattern /computer/)進行匹配,篩選出包含 “computer” 的日誌事件。
  2. 接著,使用 <match *> 將所有透過過濾器的日誌事件匹配到 Elasticsearch 輸出外掛。
  3. <match> 中,使用 @type elasticsearch 指定輸出到 Elasticsearch,並設定相關引數,如主機、埠、索引名稱等。
  4. <buffer> 部分設定了緩衝區的重新整理間隔為每5秒,確保資料定期被寫入 Elasticsearch。