在項目正式上線後,如果出現錯誤,異常,崩潰等情況
我們往往第一想到的事就是檢視日志
是以日志對于一個系統的維護是非常重要的
聲明
正文中的代碼隻是一個栗子,一個非常簡單的栗子,隻是說明這個架構是怎麼工作的
具體實作可以自由發揮~~~~
貫穿所有的日志系統
日志系統,往往是貫穿一個程式的所有代碼的;
試想一下,如果你的日志完全是由第三方元件提供的;
那麼就意味着,你的所有項目都必須引用這個dll;
也許你會說自己可以2次封裝,那麼依然需要所有項目都引用你的這個封裝後的log項目
另一方面
一些log元件需要執行個體化後才可以使用,比如log4net,這又意味着你得有一個全局的靜态變量,或者你自己二次封裝
但其實微軟已經為我們提供了2個十分友善的靜态類,用于日志的記錄
System.Diagnostics.Trace和System.Diagnostics.Debug
關于這2個類的文檔可以去看MSDN
System.Diagnostics.Trace
System.Diagnostics.Debug
他的使用真的是非常的友善,以至于你隻要使用一次就會愛上他
不用引用任何dll,因為他是微軟自家的東西,就在System.dll中
調用他的方法也很簡單
using System.Diagnostics;
...
...
Trace.TraceError("這是一個Error級别的日志");
Trace.TraceWarning("這是一個Warning級别的日志");
Trace.TraceInformation("這是一個Info級别的日志");
Trace.WriteLine("這是一個普通日志");
Trace.Flush();//立即輸出
...
...
當然方法不止隻有4個,更多的可以參考MSDN
Trace,Debug的調用方式完全相同,不同的地方在于
Debug的所有方法都有
[Conditional("DEBUG")]

表明了,在Release模式下(沒有定義DEBUG常量時),該方法不會被編譯的(不是不執行,而是根本不會編譯到程式中去)
也就是說 Debug.XXX() 方法僅在Debug模式下運作,這個又可以為我們省下很多事
重寫日志實作
Trace和Debug中的方法的預設行為是輸出到控制台Console,和Console.Write是一樣的
但是我們通過改變他的監聽器TraceListener,來實作更多的操作
必須實作的方法有
void Write(string message);
void WriteLine(string message);
不過也可以主動重寫其他方法
随便寫一個MyTraceListener
class MyTraceListener : TraceListener
{
public override void Write(string message)
{
File.AppendAllText("d:\\1.log",message);
}
public override void WriteLine(string message)
{
File.AppendAllText("d:\\1.log", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + message + Environment.NewLine);
}
}
現在程式入口中初始化監聽器Trace.Listeners
PS下:Trace和Debug的監聽器的共用的
static void Main(string[] args)
{
Trace.Listeners.Clear(); //清除系統監聽器 (就是輸出到Console的那個)
Trace.Listeners.Add(new MyTraceListener()); //添加MyTraceListener執行個體
}
在随便來個方法測試下
private static void Test()
{
try
{
int i = 0;
Console.WriteLine(5 / i); //出現除0異常
}
catch (Exception ex)
{
Trace.TraceError("出現異常:" + ex.Message);//記錄日志
}
}
由于大部分方法都是可重寫的,是以其實最終輸出什麼都是可以靈活處理的
例如這樣
public override void Write(object o, string category)
{
string msg = "";
if (string.IsNullOrWhiteSpace(category) == false) //category參數不為空
{
msg = category + " : ";
}
if (o is Exception) //如果參數o是異常類,輸出異常消息+堆棧,否則輸出o.ToString()
{
var ex = (Exception)o;
msg += ex.Message + Environment.NewLine;
msg += ex.StackTrace;
}
else if(o != null)
{
msg = o.ToString();
}
WriteLine(msg);
}
private static void Test()
{
try
{
int i = 0;
Console.WriteLine(5 / i); //出現除0異常
}
catch (Exception ex)
{
Trace.Write(ex, "計算員工工資出現異常");
}
}
其他的就自己舉一反三了
通過配置檔案初始化監聽器
通過配置檔案初始化監聽器比直接寫代碼稍稍複雜一點,但是也更友善,我們可以快速的,不重新編譯系統,即可進行對日志監聽器進行設定
特别是在Web項目中,這将變得更加友善
我把剛才的MyTraceListener獨立成一個項目,編譯為dll
并且為他增加一個構造函數和FilePath屬性用于設定将log檔案的位置
public class MyTraceListener : TraceListener
{
public string FilePath { get; private set; }
public MyTraceListener(string filepath)
{
FilePath = filepath;
}
public override void Write(string message)
{
File.AppendAllText(FilePath, message);
}
public override void WriteLine(string message)
{
File.AppendAllText(FilePath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + message + Environment.NewLine);
}
public override void Write(object o, string category)
{
string msg = "";
if (string.IsNullOrWhiteSpace(category) == false) //category參數不為空
{
msg = category + " : ";
}
if (o is Exception) //如果參數o是異常類,輸出異常消息+堆棧,否則輸出o.ToString()
{
var ex = (Exception)o;
msg += ex.Message + Environment.NewLine;
msg += ex.StackTrace;
}
else if (o != null)
{
msg = o.ToString();
}
WriteLine(msg);
}
}
MyTraceListener
配置檔案
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<clear /><!--清除預設監聽器-->
<!--添加自定義監聽器 initializeData 就是初始化參數-->
<add name="MyTraceListener" type="MyLog.MyTraceListener, MyLog, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" initializeData="d:\1.log" />
</listeners>
</trace>
<switches>
<!--這裡可以設定監聽級别,可以設定Error,Warning,Info或者留白-->
<add name="MyTraceListener" value="Error" />
</switches>
</system.diagnostics>
</configuration>
其中type參數可以這樣獲得
typeof(MyLog.MyTraceListener).AssemblyQualifiedName
Version,Culture,PublicKeyToken 也可以忽略
測試一下
沒有任何問題
而且如果你用了log4net等第三方元件的話,隻需要在實作TraceListener的項目中引用log4net就可以了
說完了...拜拜~~
代碼下載下傳
LogDemo.rar
撸主發飙了.......
#13樓 2014-04-02 09:25 永遠的麥子
兄弟寫得非常好。
不過我有兩個問題:
1,目前是往文本檔案寫,如果同時也要往系統事件或資料庫中寫,要怎麼處理?
2,像企業庫這些第三方元件,可以設定按日期或限定檔案大小去循環生成日志,這又要怎麼處理?
#14樓 2014-04-02 09:26 潇湘吹雨
部落格君,這個Trace方式,在寫入操作比較頻繁的時候,經常出現很多guid命名的檔案,然後寫入的一條内容
#23樓 2014-04-02 10:27 censhao
不錯,适用簡單的程式。
複雜的程式,比如輕易就能産生幾G日志檔案的程式裡還是log4net好用。
兄弟們啊,你們真的是來看文章的嗎? 不是我的對手派來玩我的吧...............咳咳....雞凍了.....
好吧,怪我沒說清楚,我再集中這些問題,用一個栗子簡單回答一下
public class MyTraceListener : TraceListener
{
log4net _log = new log4net();
public MyTraceListener(string filepath)
{
_log = new log4net();
_log.FilePath = filepath;
}
public override void Write(string message)
{
_log.Info(message);
}
public override void WriteLine(string message)
{
_log.Info(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + message + Environment.NewLine);
}
}
這樣是不是就可以用log4net了啊,是不是就可以用其他log系統了啊 ,是不是就想寫資料庫就寫資料庫 想寫檔案就寫檔案, 寫幹啥就幹啥了啊~~~~~~
兄弟們啊~~~~~~~
我寫的文章,除了純代碼,其他的都是想表達一種思想,一種解決方案.希望各位看官不要局限于文章中的現成的代碼,要多關注整個文章的主題思路,謝謝!
我釋出的代碼,沒有任何版權,遵守WTFPL協定(如有引用,請遵守被引用代碼的協定)
qq群:5946699 希望各位喜愛C#的朋友可以在這裡交流學習,分享程式設計的心得和快樂