Fluentd 提供了強大的機制來豐富和管理日誌事件。透過 inject 操作,我們可以將主機名、時間戳等上下文資訊注入到日誌事件中,方便後續的過濾和分析。inject 操作支援 string、float 和 unixtime 等多種時間格式,並可設定本地時間或 UTC 時間。在實際應用中,我們可以根據需求組態 inject 操作,例如將主機名注入為 hostName 屬性。此外,Fluentd 還支援從日誌記錄中提取值來設定標籤和時間戳,例如使用 Extract 外掛提取 source 屬性作為標籤。Fluentd 的標籤路由機制允許我們根據標籤值來控制日誌事件的流向,例如使用萬用字元 AppA* 匹配所有以 AppA 開頭的標籤。Exec 外掛可以執行外部指令碼或命令,從而擴充套件 Fluentd 的功能,例如抓取網頁資訊或執行健康檢查。然而,使用 Exec 外掛需要注意效能問題,避免過多的 Exec 程式影響 Fluentd 的效能。最後,Fluentd 的標籤(Labels)機制提供更精細的日誌事件處理流程控制,可以將多個指令組合成一個管道,對特定標籤的日誌事件進行處理。

5.3 將上下文注入日誌事件

提供更多的資訊和上下文可以幫助我們更好地處理日誌事件。為此,我們可能需要操縱預定義的日誌事件屬性和捕捉額外的Fluentd值。本文將對此進行更詳細的探討。

透過將這些資訊注入日誌事件中作為可識別的日誌事件屬性,我們可以在嘗試使用過濾器排除指令時明確地參照這些值,以防止日誌事件在事件序列中被進一步處理。例如,假設與特定主機相關的日誌事件被認為是不必要的,可以透過比較屬性集與主機名稱來應用具有排除指令的過濾器,以停止將資訊傳送到任何地方。

inject操作只能與match和filter指令一起使用,這是一個遺憾,因為我們可能希望在源頭應用它。儘管如此,如果需要,這並不是一個重大的挑戰需要克服,就像我們很快就會看到的那樣。使用我們的示例組態Chapter5/Fluentd/record-origin.conf,我們可以看到注入操作在清單5.4中的工作情況。

組態注入操作

在組態時間資料的注入時,可以組態不同的時間表示形式。這由time_type屬性涵蓋,它接受以下值:

  • String:允許使用文字表示形式,並將其推遲到time_format屬性進行表示。time_format使用標準表示法,如附錄A中所述。
  • Float:自紀元以來的秒數和納秒數(例如,1510544836.154709804)。
  • Unixtime:這是傳統的自紀元以來的秒數表示形式。

在清單5.4中,我們選擇了最可讀的格式——字串格式。除了描述時間資料格式外,還可以透過包含localtimeutc屬性來指定時間為本地時間或UTC時間,這些屬性採用布林值。嘗試設定這兩個屬性可能會導致很多問題。

<match **>
  <inject>
    hostname_key hostName
    worker_id_key workerId
    tag_key tag
    time_key fluentdTime
    time_type string
    localtime true
  </inject>
  @type stdout
</match>

inject組態的屬性

inject組態的屬性與已知值的對映相關,如主機名、標籤等,到日誌事件記錄中的屬性。

要檢視此組態的效果,我們使用了monitor_agentstdout,因此只需使用命令fluentd -c ./Chapter5/fluentd/record-origin.conf執行Fluentd。結果將出現在控制檯中,類別似於:

2020-05-18 17:42:41.021702900 +0100 self: {"plugin_id":"object:34e82cc",
"plugin_category":"output","type":"stdout","output_plugin":true,"retry_count":0,"emit_records":4,"emit_count":3,"write_count":0,"rollback_count":0,"slow_flush_count":0,"flush_time_count":0,"hostName":"Cohen","workerId":0,"tag":"self","fluentdTime":"2020-05-18T17:42:41+01:00"}

輸出結果分析

在此輸出中,您將看到注入的值出現在JSON結構的末尾,使用由屬性定義的名稱;例如,“hostName”: “Cohen”,其中Cohen是用來寫這本文的PC。

5.3.1 提取值

如果我們可以將某些值注入日誌事件的記錄中,那麼很明顯應該有一個相反的能力,即從記錄中提取值以設定日誌事件的標籤和時間戳。外掛可以利用這種能力來實作與日誌事件處理相關的功能。

程式碼解說:

# 以下是一個簡單的Fluentd組態示例,用於演示inject的使用
<source>
  @type dummy
  dummy {"message": "Hello, Fluentd!"}
</source>

<match dummy.**>
  <inject>
    hostname_key host_name
    time_key log_time
    time_type string
    localtime true
  </inject>
  @type stdout
</match>

內容解密:

  1. 源組態:使用dummy外掛生成測試日誌事件。
  2. 匹配組態:匹配標籤為dummy.**的日誌事件。
  3. inject組態:將主機名、時間戳等資訊注入日誌事件記錄中。
    • hostname_key host_name:將主機名注入記錄,並命名為host_name
    • time_key log_time:將時間戳注入記錄,並命名為log_time
    • time_type string:指定時間戳的格式為字串。
    • localtime true:使用本地時間作為時間戳。
  4. stdout外掛:將處理後的日誌事件輸出到控制檯。

透過這種方式,我們可以根據需要操縱和豐富日誌事件的內容,以便更好地進行後續的處理和分析。

標籤式路由(Tag-based Routing)與日誌事件處理

在前面的章節中,我們已經使用過萬用字元(wildcards)來定義match宣告,例如<match *>。然而,我們也看到了如何操控標籤(tag)值,以控制不同階段的日誌事件處理。本文將探討如何使用標籤來控制日誌事件的路由。

動態設定標籤

Fluentd 提供了多種方式來動態設定標籤,例如使用 extract 操作從日誌事件記錄中提取屬性值作為標籤。這使得根據標籤的路由變得非常靈活。例如,如果日誌事件具有一個名為 source 的屬性,我們可以使用 extract 操作將其值提取出來作為標籤。

<inject>
  tag_key nameOfLogRecordAttribute
</inject>

標籤式路由的應用

透過定義更明確的 match 值,我們可以控制哪些指令(directives)將處理和消費日誌事件。例如,對於兩個名為 AppAAppB 的輸入源,我們可以設定相應的標籤值。

設定範例

<source>
  @type dummy
  dummy {"hello from":"App A"}
  auto_increment_key AppACounter
  tag AppA
  rate 5
</source>

<source>
  @type dummy
  dummy {"Goodbye from":"App B"}
  auto_increment_key AppBIncrement
  tag AppB
  rate 3
</source>

<match AppB>
  @type file
  path ./Chapter5/AppB-file-output
  @id AppBOut
  <buffer>...</buffer>
  <format>...</format>
</match>

<match AppA>
  @type file
  path ./Chapter5/AppA-file-output
  @id AppAOut
  <buffer>...</buffer>
  <format>...</format>
</match>

執行與結果

執行以下命令來測試設定:

fluentd -c ./Chapter5/Fluentd/monitor-file-out-tag-match.conf

輸出檔案應該反映出不同的虛擬訊息,因為路由已經根據相關的來源進行了導向。

萬用字元的使用

儘管使用了明確的標籤匹配,但仍然可以使用選擇性的萬用字元。如果我們新增一個額外的來源並將其標記為 AppAPart2,我們可以透過修改 <match AppA><match AppA*> 來捕捉 AppAAppAPart2 的日誌事件。

程式碼範例與說明

<source>
  @type dummy
  dummy {"hello from":"App A"}
  auto_increment_key AppACounter
  tag AppA
  rate 5
</source>

<source>
  @type exec
  command more .\TestData\valuePair.txt
  run_interval 7s
  tag AppAPart2
</source>

<source>
  @type dummy
  dummy {"Goodbye from":"App B"}
  auto_increment_key AppBIncrement
  tag AppB
  rate 3
</source>

<match AppB>...</match>

<match AppA*>
  @type file
  path ./Chapter5/AppA-file-output
  @id AppAOut
  <buffer>...</buffer>
  <format>...</format>
</match>

程式碼執行結果與意義

執行以下命令:

fluentd -c ./Chapter5/Fluentd/monitor-file-out-tag-match2.conf

輸出檔案應該反映出不同的虛擬訊息,而 AppA 輸出現在將包括執行 OS 命令對預定義測試資料檔案的結果。

#### 內容解密:

  • @type dummy:定義了一個虛擬來源,用於生成測試日誌事件。
  • tag AppAtag AppB:為不同的來源設定了不同的標籤,用於後續的路由決策。
  • <match AppA*>:使用萬用字元匹配以 AppA 開頭的所有標籤,將相關的日誌事件導向同一輸出。
  • @type exec:允許呼叫 OS 指令碼並捕捉結果,在此範例中用於讀取檔案內容。

標籤命名慣例

通常,標籤命名遵循類別似名稱空間的層次結構,使用點(.)來分隔層次(例如,AppA.ComponentB.SubComponentC)。這樣,萬用字元可以過濾不同的名稱空間(例如,AppA.*AppA.ComponentB.*)。這種命名慣例使得管理和路由日誌事件變得更加有條理和靈活。

標籤式路由(Tag-based Routing)深入解析

在日誌管理與處理的過程中,路由(Routing)是一個至關重要的環節。Fluentd 提供了靈活的路由機制,其中標籤式路由是核心功能之一。本章節將探討 Fluentd 的標籤式路由機制,並介紹相關外掛的使用方法。

使用 Exec 輸出外掛

Exec 外掛為 Fluentd 提供了強大的擴充套件能力。當內建外掛無法滿足特定需求時,可以透過以下幾種方式解決:

  1. 開發自定義外掛:針對特定需求開發專屬外掛,以滿足複雜的資料處理需求。
  2. 獨立工具:建立獨立的工具,透過 HTTP、UDP 或 Forward 外掛將資料直接饋送至 Fluentd。
  3. Exec 外掛:編寫指令碼並透過 Exec 外掛執行,以取得環境特定的資訊。

利用 Exec 外掛,可以輕鬆檢索特定環境資訊,或執行諸如使用 Wget 和 cURL 等工具抓取網頁輸出的操作。這種方法特別適用於從第三方微服務的健康檢查端點(health endpoint)提取監控資料。

使用 Exec 外掛的注意事項

Exec 外掛需要在使用時謹慎組態。每次執行 Exec 程式時,它都會在自己的執行緒中執行,以避免對其他日誌事件的處理產生負面影響。然而,如果 Exec 程式執行過慢,可能會導致以下問題:

  • 事件亂序:由於資源在執行緒間共用,Exec 外掛可能會在前一次執行尚未完成時再次被觸發,從而導致事件亂序。
  • 執行緒死亡:如果 Exec 程式過多,可能會因資源競爭導致執行緒死亡。
  • 事件積壓:日誌事件可能會因等待執行緒完成而積壓,進而影響 Fluentd 的整體效能。

因此,在使用 Exec 外掛時,需要仔細評估其效能影響。如果 Exec 程式較為耗時或計算密集,則建議獨立執行該程式並將結果寫入檔案,以避免對 Fluentd 的日誌管理造成負擔。

實踐:更新標籤命名規範

假設團隊決定採用 domain.service.source 的命名規範來組態日誌標籤。目前的組態不符合這一規範,需要更新 monitor-file-out-tag-match2.conf 組態檔,以使 AppA 的日誌僅捕捉 Part1 元件的日誌事件。

更新組態

更新後的組態應類別似於 Chapter5/ExerciseResults/monitor-file-out-tag-match-Answer.conf。重點在於修改 match 指令,以符合新的命名規範。

動態標籤與 Extract 外掛

在前面的章節中,我們介紹瞭如何動態設定標籤。現在,我們需要改進 monitor-file-out-tag-match2.conf,使其利用 Extract 外掛根據檢索到的檔案值動態設定標籤。

更新組態

更新後的組態應類別似於 Chapter5/ExerciseResults/monitor-file-out-tag-match-Answer2.conf。需要注意的是,由於標籤被更改,Exec 源的日誌事件將不再匹配輸出組態,因此不會被輸出。

標籤外掛擴充套件

除了 Fluentd 核心功能外,還有多款認證外掛可用於擴充套件標籤路由功能。以下是一些常用的標籤路由外掛:

重寫標籤過濾器(rewrite-tag-filter)

該外掛允許根據日誌事件的內容,透過正規表示式匹配結果來重寫標籤,並重新傳送事件。

路由外掛(route)

路由外掛允許根據標籤將日誌事件導向一個或多個操作,例如修改日誌事件內容或將其複製到其他輸出。

重寫外掛(rewrite)

重寫外掛允許根據日誌事件的屬性,使用正規表示式匹配結果來修改標籤,從而實作根據事件內容的靈活路由。

這些外掛均由 Fluentd 社群中的認可貢獻者開發,並非 Fluentd 核心功能的一部分,因此在使用前需要額外安裝。

深入理解 Fluentd 的標籤(Labels)機制

在 Fluentd 的日誌事件路由中,標籤(Tags)是一個非常重要的概念。然而,當我們需要對一組特定的日誌事件進行更複雜的處理時,標籤機制就顯得有些力不從心。這時,Fluentd 的標籤(Labels)機制就派上用場了。

標籤(Labels)與標記(Tags)的區別

首先,我們需要了解標籤(Labels)與標記(Tags)的區別。標記(Tags)是用於標識日誌事件的關鍵字,而標籤(Labels)則是用於將日誌事件歸類別到特定的處理流程中。雖然兩者都用於路由日誌事件,但它們的作用和用法是不同的。

標籤(Labels)有兩個主要方面:首先,它們可以用於將額外的屬性附加到日誌事件上;其次,它們可以用於定義一個處理流程,將多個指令(Directives)組合在一起,形成一個管道(Pipeline)。

使用 stdout 過濾器觀察日誌事件

為了更好地理解標籤(Labels)的機制,我們可以使用 stdout 過濾器來觀察日誌事件的處理過程。stdout 過濾器可以將日誌事件輸出到控制檯,從而幫助我們瞭解日誌事件的處理流程。

<filter *>
  @type stdout
</filter>

這個組態可以讓所有的日誌事件透過 stdout 過濾器,從而輸出到控制檯。

內容解密:

  • @type stdout 指定了過濾器的型別為 stdout。
  • <filter *> 表示這個過濾器會匹配所有的日誌事件。

標籤(Labels)路由示例

下面是一個使用標籤(Labels)進行路由的示例組態:

<source>
  @type tail
  path ./Chapter5/basic-file.txt
  read_lines_limit 5
  tag basicFile
  pos_file ./Chapter5/basic-file-read.pos_file
  read_from_head true
  <parse> @type none </parse>
  @label labelPipeline
</source>

<source>
  @type tail
  path ./Chapter5/basic-file2.txt
  read_lines_limit 5
  tag basicFILE2
  pos_file ./Chapter5/basic-file-read2.pos_file
  read_from_head true
  <parse> @type json </parse>
</source>

<label labelPipeline>
  <filter *>
    @type stdout
  </filter>
  <match *>
    @type file
    path ./Chapter5/label-pipeline-file-output
    @id otherSelfOut
    <buffer>...</buffer>
    <format>...</format>
  </match>
</label>

內容解密:

  • 第一個 <source> 組態使用 @label labelPipeline 將日誌事件標記為 labelPipeline
  • <label labelPipeline> 定義了一個處理流程,將匹配的日誌事件透過 stdout 過濾器輸出到控制檯,然後透過 <match> 指令將日誌事件輸出到檔案。
  • 第二個 <source> 組態沒有使用 @label,因此它的日誌事件不會被 labelPipeline 處理流程處理。

此圖示表示 Fluentd 的日誌事件處理流程

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Fluentd日誌事件上下文注入與標籤路由

package "系統架構" {
    package "前端層" {
        component [使用者介面] as ui
        component [API 客戶端] as client
    }

    package "後端層" {
        component [API 服務] as api
        component [業務邏輯] as logic
        component [資料存取] as dao
    }

    package "資料層" {
        database [主資料庫] as db
        database [快取] as cache
    }
}

ui --> client : 使用者操作
client --> api : HTTP 請求
api --> logic : 處理邏輯
logic --> dao : 資料操作
dao --> db : 持久化
dao --> cache : 快取

note right of api
  RESTful API
  或 GraphQL
end note

@enduml

此圖示內容解密:

  • 圖示表示 Fluentd 的日誌事件處理流程。
  • 日誌事件根據不同的標記被路由到不同的處理流程。
  • 被標記為 basicFile 的日誌事件會被 @label labelPipeline 處理流程處理。
  • 被標記為 basicFILE2 的日誌事件會被匹配 basicFILE2<match> 指令處理。