1. 程式人生 > >C# 面向切面編程--監控日誌記錄方案

C# 面向切面編程--監控日誌記錄方案

增加 字符 行動 不能 可能 沒有 很多 方法的參數 現在

背景:現在公司整體在做監控平臺,要求把各個部分的細節都記錄下來,在前臺頁面上有所顯示,所以現在需要做的就是一個監控日誌的記錄工作,今天講的就是渲染監控日誌的例子。

現狀:當前的渲染程序沒有為監控日誌記錄預留代碼接入口,因此要新增加監控日誌勢必要增加新的代碼。但是如果只是單單在已有邏輯中新增日誌記錄的代碼似乎不太合理:因為記錄日誌的代碼很多都是一樣的,直接插入代碼有很多重復代碼;原有代碼已經上線並且運行良好,新增代碼會破壞原有封裝,甚至增加出錯的可能;再者從設計的角度來說,記錄日誌不屬於任何一個功能的,新增日誌和每個方法的執行意圖格格不入,因此需要一種新的記錄日誌方式。

解決方案:

數據結構:設計一個通用的方法日誌記錄類,包含ID,方法名,執行時間長度,日誌結果(正常記錄正常信息,異常記錄錯誤信息),日誌結果是否為異常標誌位等等,還有List<string>包含方法中用到的參變量名稱,List<object>方法中的參變量的值(實現序列化接口或特性),從而實現可以記錄方法上下文信息並幫助排錯。所有方法執行情況日誌都用這個類,形成一個統一通用的方法執行狀態信息記錄的類。

記錄方式:對於所有需要進行日誌記錄的方法的采用對該方法所在的類進行動態代理的方式處理。在代理方法中的在原有方法的前後新增日誌記錄,動態代理采用裝飾器模式實現通常稱為AOP,AOP方面的內容請參閱: https://msdn.microsoft.com/zh-cn/library/dn574804.aspx 。以上是對已經存在的類的方法進行日誌記錄采用動態代理該類,對於方法內部的某個地方進行日誌記錄的,采用動態代理Stopwatch來實現。因為方法內部的日誌一般都要統計時間長度,動態代理Stopwatch的Start方法和Stop方法,在Start和Stop調用的時後記錄出方法的執行時間和中間參變量的值。


獲取參變量:對於方法的參數獲取比較容易,動態代理時會把參數傳遞到代理方法中,可以用對象池將該參數的句柄獲取並保存,為防止對象池持有參變量使其不能在退出方法時被垃圾回收器回收,采用弱引用的方式持有所有參變量。對於方法內部的局部變量,采用代理方法中提前實例化保存到對象池方式。對象池采用字典實現,對象池的key用字符串表示,記錄的是方法名稱+變量名+線程上下文哈希值的方式,實現多線程中記錄同一參數不同參數key的後綴(線程上下文哈希值)和不同參數值的記錄,這樣就可以在方法的外部提前獲取局部變量的值並輸出到日誌。

對象池實現:上文提到對象池采用字典存儲,但是對象池何時進行垃圾回收、清理垃圾數據呢?這時我們要自己定義一個添加對象到對象池的方法,在這個方法的第一部分就是清理垃圾數據,這樣每新增一筆數據就刪除舊數據,從而保證對象池的數據有效性。設置局部變量時要在方法執行前的代理方法中就添加,在原有代碼中再添加的時候先從對象池中去取,如果有就用已經用原代碼前添加進去的值,沒有或者已經被垃圾回收了則重新生成新的數據。

源代碼:

https://download.csdn.net/download/hirisw/10486250

C# 面向切面編程--監控日誌記錄方案