結構化日誌記錄 - 更好地理解系統

ITPUB社群發表於2022-11-21

結構化日誌記錄 - 更好地理解系統

作者 Torsten Mosis  是 systemticks GmbH的軟體架構師 

原文:Structured Logging - for a better system understanding


1、開篇

正如 Raphael 關於理解系統的博文中所述,在複雜系統中隔離和定位錯誤是一項非常具有挑戰的任務。因為功能的實現總是複雜的、分散式的,跨越系統層級的,並且使用了來自許多不同組織架構、不同供應商的裝置和技術。

一種比較可行的克服這些困難的方案是以一種一致的、明確的和機器可讀的格式來記錄系統中最有價值的資訊。這種方法稱為結構化日誌記錄。在配套工具的支援下,這些追蹤資料有助於更深入地瞭解你的系統的執行活動,使你能夠理解元件之間的相互作用。

相反,當日志僅僅作為純非結構化文字資料使用時,很難獲得任何有用的資訊,尤其是在自動化日誌分析的場景下。

2、分散式系統中的典型缺點

接下來,我們談論的是分散式系統中有哪些缺點,為什麼它們如此難以被發現?

2.1 介面呼叫的順序不對

這是最突出的問題之一,同時也是最難發現的問題型別之一。跟蹤它可能會讓人很上頭,比如這種情況,整個呼叫流並未按預期順序來實現,整體功能肯定是無法完全正常工作的,但可能測試的呼叫居然獲得了預期的響應。

2.2 長時間執行的請求

從功能的角度來看,該服務的行為符合預期:只要輸入引數呼叫後就能返回一個有效結果。但是從結果來看,客戶卻無法完成他的任務,因為服務的響應時間太長了。可能不是你的服務介面引起的,而是呼叫鏈中的另一個服務介面。

2.3 冗餘呼叫

在某些情況下,一個服務介面被同一個客戶端以相同的引數頻繁地呼叫。這可能是在迴圈呼叫介面的情況下作為意外而發生。但也可能是有意為之,因為客戶端懶得自己快取管理狀態資訊。無論怎樣,這都會導致一個非功能性的問題,比如高cpu負載,因為在介面呼叫的背後可能會有一個巨大的call hierarchy,而這個call hierarchy會被反覆觸發......

2.4 其他故障

在呼叫介面時沒有滿足一些前提條件或後置條件,一個服務被一個未經授權的客戶呼叫,多個客戶不能同時得到服務,或者引數值超出範圍,都可能會導致更多的故障。當然這裡只是列舉了一部分故障來源,除此之外還有很多。

但它們都有一個共同點,即如果你還沒有記錄能貫穿上下文的日誌的觀念,就很難識別出它們。

3、什麼是需要記錄的有價值的資訊?

首先,需要確定在我們的應用場景中哪些資訊是至關重要的,也就是說所有那些幫助我們梳理出軟體元件之間是如何相互作用的資訊。因為服務介面代表著系統的最前沿,所以肯定要使用結構化日誌來記錄跟他們相關的資訊。

3.1 介面簽名

由於我們主要是監控服務介面呼叫,所以我們需要記錄所有的上下文資料,以便能將單條日誌明明白白的追溯到是哪個原始介面的呼叫引發的。

介面簽名的日誌通常包含了以下名稱和/或識別符號:

  • 介面
  • 軟體元件(實現該介面的)
  • 被呼叫的方法或函式名
  • 與該方法或函式一起攜帶的引數


為了使它更容易理解,請想象下承載我們後設資料的json結構。

結構化日誌記錄 - 更好地理解系統

這個結構是隨意的,這裡僅是一個示例用於說明目的。在生產程式碼中,你可以選擇任意其他格式,也許還可以編碼成流行的協議,如protobuf或message pack。

3.2 通訊上下文

其次,我們需要將下邊這樣一些資料新增到我們的日誌中,以便我們透過這些資料能識別出是誰在呼叫誰的介面:

  • 訊息型別(例如請求、響應、廣播、事件等)
  • 訊息的傳送者
  • 訊息的接收者
結構化日誌記錄 - 更好地理解系統

3.3 額外的後設資料

根據我們的架構和技術環境,用更有價值的後設資料來豐富我們的日誌也是很有用的,比如說:

  • 訊息序列號
  • 會話 ID
  • 例項 ID
  • 程式 ID
  • 執行緒 ID
結構化日誌記錄 - 更好地理解系統

當這些資訊都以如此一致和確定的方式提供後,可想而知,我們可以輕鬆地以程式設計的方式來處理這些資料並獲得有價值的結果。

3.4 檢查可用的內建後設資料

我們還應該清楚,工程中的日誌元件已經為我們提供了一些有用的內建後設資料。例如,Android 日誌元件的 API 強制我們顯式指定日誌級別和標籤以及實際日誌內容:

private static final String TAG = "MyApplication";
Log.i(TAG, "My important trace")

當在日誌檔案中看到相應的日誌記錄時,我們也會意識到,框架為我們隱式地放置了一些額外的後設資料:

10-18 11:05:19.112  4612  4628 I MyApplication: My important trace
  • 時間資訊(10-18 11:05:19.112)
  • 程式 ID (4612)
  • 執行緒 ID (4628)

其他日誌框架可能會提供不同的或更多的後設資料,例如行號、類名、方法名等。通常可以配置日誌內容和佈局。在某些情況下,還可以動態附加一些額外的上下文資訊。

由於在大多數專案中,底層的日誌框架是不可調整的,我們應該首先檢查它為我們提供了哪些可用的內建後設資料。最終,我們需要將我們收集的後設資料與內建後設資料對齊,以避免冗餘。

4、如何一致地記錄日誌?

眾所周知:軟體介面會隨著時間的推移而發展。但是,如果日誌是手動實現的,並且不與更改的介面一起維護,則日誌會保持不變。這是一個潛在的風險,因為日誌分析可能會把我們引向錯誤的方向,甚至讓我們得出錯誤的結論,僅僅是因為日誌資料與介面規範不一致。

因此,只要有可能,我們就應該避免手動記錄服務介面呼叫。

4.1 生成的日誌記錄優於手動記錄的日誌

假設我們很幸運,在我們的專案結構中,服務介面是可用的宣告性模型,用介面描述語言(IDL)或任何其他機器可讀的模式指定。這些模型是生成處理資訊傳送和接收的模板程式碼的輸入。這也是我們鉤住並生成相應的日誌呼叫的地方。

4.2 非侵入性的日誌記錄

在一些技術環境中,系統甚至可能為我們提供掛鉤到訊息傳輸機制本身的設施。如果是這種情況,我們應該更偏向選擇這種方式,在框架內攔截訊息。然後,應用程式程式碼將保持不變。

4.3 面向切面的日誌記錄

我們也可能有機會遇到允許使用面向切面程式設計 (AOP) 的技術環境。一些程式語言(如 Java)具有可用的 AOP 實現。它可以將橫切關注點(如日誌記錄)從應用程式程式碼中分離出來。檢查你的基礎設施提供了什麼,但通常有一種方法可以避免手動記錄。

5、結論

我們現在有了如何為服務介面應用結構化日誌的指南和方法。我們對什麼、如何、在哪裡以及何時以一致的方式記錄有價值的資料有了一個概念。最後,我們需要檢查結構化日誌方法如何在你的環境中實際應用。但這不能籠統地回答,因為這在很大程度上取決於你的要求和現有的基礎技術架構。

通訊和訊息傳輸框架的作用範圍是很巨大的。這同樣適用於日誌基礎設施。它們的API和設施能力會推動結構化日誌在你的專案結構中實現的方式。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2924365/,如需轉載,請註明出處,否則將追究法律責任。

相關文章