錯誤日誌之觀察者模式

来源:https://www.cnblogs.com/MedlarCanFly/archive/2019/09/07/11480095.html
-Advertisement-
Play Games

星期一 情景 早晨,項目組長來到小明身邊,“有人反映咱們的項目有Bug” “什麼Bug?” “不知道,你添加一個日誌模塊自己看記錄去。” ”...“ 分析 在MVC全局過濾器中自己添加有異常過濾器。 Global.asax 1 public class MvcApplication : System ...


星期一

情景

早晨,項目組長來到小明身邊,“有人反映咱們的項目有Bug” “什麼Bug?” “不知道,你添加一個日誌模塊自己看記錄去。” ”...“

分析

在MVC全局過濾器中自己添加有異常過濾器。

Global.asax

 1     public class MvcApplication : System.Web.HttpApplication
 2     {
 3         protected void Application_Start()
 4         {
 5             AreaRegistration.RegisterAllAreas();
 6             //註冊全局過濾器
 7             FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
 8             RouteConfig.RegisterRoutes(RouteTable.Routes);
 9             BundleConfig.RegisterBundles(BundleTable.Bundles);
10         }
11     }
View Code

 

 FilterConfig.cs

1     public class FilterConfig
2     {
3         public static void RegisterGlobalFilters(GlobalFilterCollection filters)
4         {
5             //向全局過濾器中添加異常過濾器
6             //只要你的項目出現了異常,就會執行過濾器里的OnException方法
7             filters.Add(new HandleErrorAttribute());
8         }
9     }
View Code

 

開工

整理思路:發生錯誤時要執行自己需要的代碼,只需要繼承IExceptionFilter,重寫OnException方法,然後把自己的過濾器註冊到全局即可。

創建過濾器,MyExceptionFilter類

 1     //因為微軟已經提供了一個HandleErrorAttribute類(它其實也是繼承了IExceptionFilter),所以我們只需繼承它即可
 2     public class MyExceptionFilter: HandleErrorAttribute
 3     {
 4         //重寫OnException方法
 5         public override void OnException(ExceptionContext filterContext)
 6         {
 7             base.OnException(filterContext);
 8 
 9             //把錯誤寫到日誌文件裡面去
10             //思考:如果同時來了多個錯誤,一起向文件中寫內容,就會發生同時訪問同一個文件問題。你會怎麼解決?
11             //提示:鎖、隊列
12 
13             //LogHelper類用來把錯誤寫到日誌裡面去
14             LogHelper.Write(filterContext.Exception.ToString());
15 
16         }
17     }

 

 

LogHelper類,用來把錯誤寫到日誌裡面去

 1     public class LogHelper
 2     {
 3         //添加一個靜態的異常信息隊列,只要出現異常就寫到隊列中。
 4         public static Queue<string> ExceptionStringQueue = new Queue<string>();
 5 
 6         //第一次用到該類型時會執行靜態構造函數,只被執行一次
 7         static LogHelper()
 8         {
 9             //創建一個線程池,將方法排入隊列以便執行
10             ThreadPool.QueueUserWorkItem(o => {
11                 while (true)
12                 {
13                     lock (ExceptionStringQueue)
14                     {
15                         //如果有錯誤信息寫入日誌
16                         if (ExceptionStringQueue.Count > 0)
17                         {
18                             string exceptionString = ExceptionStringQueue.Dequeue();
19                             //把錯誤信息寫到日誌文件中
20                             using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Log.txt", true))
21                             {
22                                 file.WriteLine(exceptionString);// 直接追加文件末尾,換行 
23                             }
24                         }
25                         else
26                         {
27                             Thread.Sleep(1000);
28                         }
29                         
30                     }
31                 }
32             });
33         }
34 
35 
36         //給外部提供方法,將錯誤信息寫入隊列
37         public static void Write(string exceptionString)
38         {
39             lock (ExceptionStringQueue)
40             {
41                 //將錯誤信息添加到隊列
42                 ExceptionStringQueue.Enqueue(exceptionString);
43             }
44         }
45     }
View Code

 

把自己的過濾器註冊到全局

 1     public class FilterConfig
 2     {
 3         public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 4         {
 5             //向全局過濾器中添加異常過濾器
 6             //只要你的項目出現了異常,就會執行過濾器里的OnException方法
 7             //filters.Add(new HandleErrorAttribute());
 8             //把自己的過濾器註冊到全局
 9             filters.Add(new MyExceptionFilter());
10         }
11     }
View Code

 

自定義錯誤測試

1 throw new Exception("自定義錯誤");
View Code

 

 OK,大功告成,以後就可以根據日誌來找錯誤了。 

星期二

情景

早晨,項目組長又來到小明身邊,”昨天我用了你的錯誤日誌功能,還不錯,但是你將日誌寫在文件中整理不是太方便,還存在共用衝突問題,你改下寫到資料庫中“ ”...“

分析

查看昨天寫的代碼

發現此處是一個變化點,有可能寫到文件中,有可能寫到資料庫中,有可能......

不就是寫到不同的地方麽,簡單,多態就能搞定了。

開工

依賴於抽象,而不依賴於具體

創建IWriteLog介面

1     public interface IWriteLog
2     {
3         //把錯誤信息寫到相應的地方
4         void WriteLog(string exceptionString);
5     }
View Code

創建WriteLogToText類實現介面,用來寫入文本

1     public class WriteLogToText : IWriteLog
2     {
3         public void WriteLog(string exceptionString)
4         {
5             //將錯誤信息寫入文本
6         }
7     }
View Code

 創建WriteLogToSqlServer類實現介面,用來寫入資料庫

1     public class WriteLogToSqlServer : IWriteLog
2     {
3         public void WriteLog(string exceptionString)
4         {
5             //將錯誤信息寫入資料庫
6         }
7     }
View Code

 

對變化點進行修改

1     string exceptionString = ExceptionStringQueue.Dequeue();
2     //依賴介面
3     IWriteLog writeLog = new WriteLogToSqlServer();
4     //IWriteLog writeLog = new WriteLogToText();
5     //把錯誤信息寫到相應的地方
6     writeLog.WriteLog(exceptionString);

 OK,大功告成,又可以去美滋滋了...

星期三

情景

早晨,項目組長再一次來到小明身邊,”經過我的思考,我覺得把錯誤信息同時寫到文本和資料庫中比較好“ ”為什麼?“ “需求” “...”

分析

錯誤信息有可能要寫到不同的地方,而且不知道有多少地方,說不定明天又加了一個Redis、後天再加一個....

這時候我們可以考慮創建一個集合來保存都需要寫到那些地方去。(這裡插一句:設計模式只是一種思想,實現方式肯定是不唯一的,但是思想是精髓,不能說這個代碼是這個模式,換一種方式實現就不是這個模式了。

然後依次寫入即可。

開工

對LogHelper進行修改

 1     public class LogHelper
 2     {
 3         //添加一個靜態的異常信息隊列,只要出現異常就寫到隊列中。
 4         public static Queue<string> ExceptionStringQueue = new Queue<string>();
 5 
 6         //定義一個集合來存放所有的 觀察者,
 7         public static IList<IWriteLog> writeLogList = new List<IWriteLog>();
 8 
 9         //第一次用到該類型時會執行靜態構造函數,只被執行一次
10         static LogHelper() {
11 
12             //觀察(訂閱)
13             writeLogList.Add(new WriteLogToSqlServer());
14             writeLogList.Add(new WriteLogToText());
15 
16             //創建一個線程池,將方法排入隊列以便執行
17             ThreadPool.QueueUserWorkItem(o=> {
18                 while (true)
19                 {
20                     lock (ExceptionStringQueue)
21                     {
22                         //如果有錯誤信息寫入日誌
23                         if (ExceptionStringQueue.Count > 0)
24                         {
25                             string exceptionString = ExceptionStringQueue.Dequeue();
26                             //發佈
27                             foreach (var writeLog in writeLogList)
28                             {
29                                 writeLog.WriteLog(exceptionString);
30                             }
31                         }
32                         else
33                         {
34                             Thread.Sleep(1000);
35                         }
36                     }
37                 }
38 
39             });
40         }
41 
42 
43         //給外部提供方法,將錯誤信息寫入隊列
44         public static void Write(string exceptionString) {
45             lock (ExceptionStringQueue)
46             {
47                 //將錯誤信息添加到隊列
48                 ExceptionStringQueue.Enqueue(exceptionString);
49             }
50         }
51     }

後期如果還需要寫入其它地方或者去掉一個的話,只需要Add一個或者刪除一行即可。當然,現在的代碼還有很多可優化的地方,比如把通知者(LogHelper)進行抽象,還可以通過配置文件加反射再次解耦。這裡就不做過多介紹了。因為已經星期四了...

星期四

採用Log4Net

總結

觀察者模式又叫發佈-訂閱模式,定義了一種一對多的依賴關係,讓多個觀察者同時監聽同一個對象。當對象狀態發生改變時,通知所訂閱的觀察者。

什麼時候使用?

當一個對象改變同時需要改變其他對象,並且還不知道要改變多少對象。這時應該考慮觀察者模式。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ES6
    1.什麼是ES6? ES的全稱是ECMAScript,ES6就是ES2016之後的一個泛稱,是由ECMA國際標準化組織制定的一項腳本語言的標準化規範。 2.ES6新增語法 1. let ES6中新增的用於聲明變數的關鍵字 特點: 1.let聲明的變數具有塊級作用域的特點,只在所處的塊級作用域有效 i ...
  • 1. 效果圖展示 2. 工程目錄結構 註意: webapp下的resources目錄放置easyui和js(jQuery文件是另外的) 3. 代碼 index.jsp springmvc.xml配置靜態資源 註意: 1. EasyUI和JQuery文件是放在webapp/resources目錄下的, ...
  • JS是以事件驅動為核心的一門語言。 事件的三要素:事件源、事件、事件驅動程式。 例如: 常見的事件如下: DOM:文檔對象模型。DOM 為文檔提供了結構化表示,並定義瞭如何通過腳本來訪問文檔結構。目的其實就是為了能讓js操作html元素而制定的一個規範。 DOM就是由節點組成的。 解析過程 HTML ...
  • 處理方法:數組改變用push ...
  • 一、let和const 1、let與var的區別 不存在變數提升 塊級作用域 不允許重覆聲明 2、const常量 const與let一樣,唯一區別在於聲明的常量不能被修改 二、解構賦值 es6按照一定模式,從數組和對象中提取值,對變數進行賦值,被稱為解構 1、數組的解構 + "模式匹配",只要等號兩 ...
  • 摘要: 求職還是需要認真準備的。 原文: "超實用技術面試手冊,從工作申請、面試考題再到優勢談判,GitHub獲30000星" 作者:量子位 技術人員求職面試,單刷leetcode上的大廠題庫可能還不夠。 簡歷怎麼寫才能吸引HR的眼光,可能會被技術老大問到哪些常見問題,拿到Offer之後怎樣才能讓自 ...
  • 使用電腦逛淘寶,京東等商城時,將滑鼠移入圖片中,圖片會放大,之前一直在想這種是怎麼實現的,前兩天剛寫出來,純js實現的,無任何工具庫。下麵先來看下思路吧! 剛學js的時候可能對於佈局不是很重要,但學到面向對象編程後,佈局就變得很重要了,有時候佈局會影響到整體效果;先來看下佈局吧! 佈局就搞定了,比較 ...
  • 介面隔離原則(Interface Segregation Principle): 1、客戶端不應依賴它不需要的介面 2、類間的依賴關係應該建立在最小的介面上 其實通俗來理解就是,不要在一個介面裡面放很多的方法,這樣會顯得這個類很臃腫。介面應該儘量細化,一個介面對應一個功能模塊,同時介面裡面的方法應該 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...