寫一個跟蹤的類庫
摘要:本類庫出自《asp.net電子商務高級編程》一書的源碼,作者Kevin Hoffman。我們在開發程序的時候常常需要跟蹤一些變量的值,系統狀態等。一般我們在底層架構裏提供完成這個任務的功能,我把這本書的兩個類先提取出來給大家看看,看看有沒有可用的價值,這個類庫可以把要跟蹤輸出的信息輸出在一個安全的位置,它把程序集的跟蹤輸出和asp.net的跟蹤輸出做了合併。並且提供了在異常拋出的時候獲取系統進程信息,線程信息以及應用程序域等方面的信息。
/**//*
* Class : GWTrace
* Namespace : GW.MonitorServices
* Assembly : GW.MonitorServices
* Author : Kevin Hoffman
* Description : Enhanced tracing functionality to consolidate system and http tracing log and
* provide support for trace switches.
*/
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
namespace GW.MonitorServices
{
/**//// <summary>
/// 跟蹤類,這裏可以輸出一個自定義跟蹤消息,
/// 也可以跟蹤輸出一個方法的執行情況,把這些
/// 跟蹤消息存放在合適的位置,包括類庫和頁面跟蹤
/// </summary>
public sealed class GWTrace
{
private GWTrace() { } // 用私有構造函數防治實例華.
//從web.config來獲取設置的跟蹤級別
private static readonly TraceSwitch traceSwitch =
new TraceSwitch("GWTrace", "GW Current Tracing Level");
/**//// <summary>
/// 獲取跟蹤等級
/// </summary>
public static TraceLevel CurrentTraceLevel
{
get
{
return traceSwitch.Level;
}
}
/**//// <summary>
/// 默認輸出信息性消息,警告和錯誤處理信息
/// </summary>
/// <param name="message">要顯示的的消息</param>
/// <param name="args">一個數組參數,用來拼接成最終消息</param>
[Conditional("TRACE")]
public static void Trace( string message, params Object[] args )
{
Trace( TraceLevel.Info, message, args );
}
/**//// <summary>
/// 指定跟蹤等級來輸出跟蹤消息,跟蹤指定的跟蹤級別,在不同的地方輸出跟蹤消息
/// 如果HttpContext可用的話,就把消息輸出到頁面跟蹤裏,總之,這個方法保證跟蹤
/// 消息始終能記錄在安全的位置.
/// </summary>
/// <param name="msgLevel">跟蹤等級</param>
/// <param name="message">跟蹤消息</param>
/// <param name="arrData">跟蹤參數</param>
[Conditional("TRACE")]
public static void Trace( TraceLevel msgLevel,
string message,
params Object[] arrData )
{
//如果跟蹤級別小於或者等於設置的級別時再輸出跟蹤信息
if ( msgLevel <= traceSwitch.Level )
{
// 對輸入的參數做一些處理,防治出錯
// SafeFormat是把信息和對象數組拼接成一個字符串
//和string.Format()的功能差不多
message = ( message == null ? string.Empty : message.Trim() );
message = MonitorUtilities.SafeFormat( message, arrData );
//記錄跟蹤消息,如果上HttpContext可用的話
//把跟蹤信息輸出到頁面裏並且如果跟蹤信息
//是Error級別的話,使用紅色標識跟蹤信息
try
{
System.Diagnostics.Trace.WriteLine( message );
System.Web.HttpContext httpContext =
System.Web.HttpContext.Current;
if ( httpContext != null )
{
if ( msgLevel == TraceLevel.Error )
httpContext.Trace.Warn( message );
else
httpContext.Trace.Write( message );
}
}
catch
{
//什麼也不用做,下面這句我不會翻譯
// Do nothing: do not corrupt the current error
// with a failure to trace an error
}
}
}
/**//// <summary>
/// 使用TraceLevel.Info級別跟蹤一個方法
/// 可以跟蹤當時傳入方法的一些參數的值
/// 本方法調用它的重載方法
/// </summary>
/// <param name="method">要跟蹤的方法</param>
[Conditional("TRACE")]
public static void EnteringMethod( MethodBase method )
{
EnteringMethod( TraceLevel.Info, method );
}
/**//// <summary>
/// 指定級別跟蹤一個方法,這裏可以跟蹤方法的名字
/// 方法的簽名等,這裏用了反射和中間
/// 語言的一些知識,構造函數在MSIL裏用.ctor表示
/// </summary>
/// <param name="msgLevel">跟蹤級別</param>
/// <param name="method">要跟蹤的方法</param>
[Conditional("TRACE")]
public static void EnteringMethod( TraceLevel msgLevel,
MethodBase method )
{
try
{
if ( traceSwitch.Level >= TraceLevel.Error )
{
string methodName =
( method.Name.Equals(".ctor") ? "Constructor" : method.Name );
Trace ( msgLevel,
"Entering {0}.{1}() [Signature: {2}]",
method.DeclaringType.Name, methodName, method.ToString() );
}
}
catch
{
//這裏也什麼都不做,因爲這裏出現了異常,如果處理的話會拋出一個新的
//異常,造成死循環
// Again, do nothing here. The failure to trace should not create
// another failure.
}
}
}
}
/**//*
* Class : MonitorUtilities
* Namespace : GW.MonitorServices
* Assembly : GW.MonitorServices
* Author : Kevin Hoffman
* Description : Utility class (static methods only) for us in logging information about important events.
*/
using System;
using System.Text;
using System.Runtime.Remoting.Messaging;
namespace GW.MonitorServices
{
/**//// <summary>
/// Summary description for MonitorUtilities.
/// </summary>
public class MonitorUtilities
{
/**//// <summary>
/// 把一個異常的堆棧信息處理後返回一個字符串
/// 一個異常可能是另一個異常實例引發的,這裏通過
/// 遞歸把 所有的異常消息都處理並返回信息,最後
/// 形成一個包含異常足夠多信息的字符串
/// </summary>
/// <param name="ex">傳輸的異常</param>
/// <returns>返回的字符串</returns>
public static string ExpandStackTrace( Exception ex )
{
StringBuilder buffer = new StringBuilder(1024);
while (ex != null)
{
if (buffer.Length > 0)
buffer.Insert(0, ex.StackTrace + "/nRe-Thrown (" + ex.Message + ")/n");
else
buffer.Insert(0, ex.StackTrace + "/n");
ex = ex.InnerException;
}
buffer.Replace(" in ", "/n/tin/n");
return buffer.ToString();
}
/**//// <summary>
/// 返回機器名
/// </summary>
/// <returns></returns>
public static string GetMachineName()
{
return System.Environment.MachineName;
}
/**//// <summary>
/// 返回一些進程信息,默認情況下線程信息是不可以獲取的,要改一下注冊表,下面的
/// 英文告訴你怎麼做,我不懂英文,就不拽了哦,總之就是返回進程ID啦,進程名稱啦
/// 線程表示啦,應用程序域啦之類的信息
/// In order to use the GetProcessInfo method, the ASP.NET must have access
/// to the performance information registry keys. To accomplish this,
/// do the following:
/// <pre>
/// Open REGEDT32.EXE
/// Navigate to HKEY_LOCAL_MACHINE/Software/Microsoft/Windows NT/CurrentVersion/PerfLib
/// Navigate to the Security Menu
/// Click Permissions
/// Select the local machine account under which ASP.NET is running (default is ASPNET)
/// Click Add
/// Now this application and all ASP.NET apps on the machine have access to this data.
/// This function should NOT EVER be called if your application is running on a third
/// party hosting company
/// </pre>
/// </summary>
/// <returns></returns>
public static string GetProcessInfo()
{
try
{
System.Diagnostics.Process curProcess =
System.Diagnostics.Process.GetCurrentProcess();
return string.Format(
"[Process:{0}, {1}][Thread: {2}][AppDomain:{3}",
curProcess.Id, curProcess.ProcessName,
AppDomain.GetCurrentThreadId(),
AppDomain.CurrentDomain.FriendlyName );
}
catch
{
return "Process Information Unavailable";
}
}
/**//// <summary>
/// 這個方法用來把一個字符串和一個對象數組進行格式化
/// 這裏調用的也是string.Format方法,但是這是一個
/// 不引發異常的版本,嘿嘿,因爲這幾個類就是做錯誤處理的,
/// 所以儘量不要引發新的異常
/// </summary>
/// <param name="format"></param>
/// <param name="formatArgs"></param>
/// <returns></returns>
public static string SafeFormat(string format, params Object[] formatArgs )
{
format = ( format == null ? string.Empty : format.Trim() );
try
{
return string.Format(format, formatArgs );
}
catch
{
return format + " (Error binding arguments)";
}
}
}
}
以上兩個文件是類庫的組成文件,然後建立一個asp.net程序,引入上面的兩個文件編譯的程序集,設置一下web.config文件,如下。
<configuration>
<system.diagnostics>
<switches>
<add name="GWTrace" value="4" />
</switches>
</system.diagnostics>
<system.web>
然後新建一個default.aspx頁面,在代碼視圖裏輸入以下代碼,運行一下就可以看到成果了。
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Reflection;
using GW.MonitorServices;
namespace WawaCMPArticles
{
public class _Default : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
// 在此處放置用戶代碼以初始化頁面
GWTrace.Trace("打倒{0}","鳥大哥");
GWTrace.Trace(System.Diagnostics.TraceLevel.Error,"鳥大哥是{0}","壞淫");
this.Replace("鳥大哥是好人","好人","豬頭");
this.ThrowNewException(0);
}
public void ThrowNewException(int p)
{
try
{
int i = 5/p;
}
catch(System.DivideByZeroException e)
{
Response.Write(MonitorUtilities.ExpandStackTrace(e) + "<br>");
Response.Write(MonitorUtilities.GetMachineName() + "<br>");
Response.Write(MonitorUtilities.GetProcessInfo() + "<br>");
}
}
public void Replace(string s1,string s2,string s3)
{
GWTrace.EnteringMethod( MethodBase.GetCurrentMethod() );//跟蹤輸出本方法
Response.Write(s1.Replace(s2,s3) + "<br>");
}
Web 窗體設計器生成的代碼#region Web 窗體設計器生成的代碼
override protected void OnInit(EventArgs e)
{
InitializeComponent();
this.Trace.IsEnabled =true;//啓用頁面跟蹤
base.OnInit(e);
}
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
最近我見博客園有人討論監測跟蹤和錯誤處理方面的內容,我也來湊湊熱鬧。下次再把錯誤處理的類提取出來,做些註釋,和大家討論一下如何改進,這樣偶們個人類庫裏的代碼就越來越多,越來越好,想什麼時候用就什麼時候用,嘿嘿。錯誤處理好像微軟的Microsoft.ApplicationBlocks.ExceptionManagement挺好用的,相關信息請參考下面的文章或者微軟的視頻教程。
http://edobnet.cnblogs.com/archive/2004/09/10/41759.html