[轉] C#實現自動化Log日誌

qing2005原文地址 C#實現自動化Log日誌 html

在開發項目的時候,咱們難免要使用Log記錄日誌,使用最多的是Log4Net和EntLib Log,在須要記錄日誌的代碼處加入log.Write(日誌信息),假設我須要跟蹤業務方法,記錄方法的傳遞參數,執行時間,返回數據等;或者我須要查 看方法的調用關係,但願進入方法的時候自動記錄參數信息,出方法時記錄結果和執行時間信息。這時就是一個典型的AOP運用,Java在AOP方面是很容易 實現的,由於java有類加載器。可是.Net在AOP方面就不怎麼容易,嚴格意義上.Net沒有真正的AOP。這話並不表明.Net不能實現AOP,比 如:PostSharp和Enterprise library就能實現。java

先介紹一下PostSharp,咱們知道.net代碼將編譯成MSIL(微軟中間語言),而後CPU將MSIL的exe文件生成本地CPU的二進制文件格式,PostSharp就是在編譯過程當中加入IL代碼,於是完成AOP功能。
缺點:編譯器須要PostSharp組件,維護代碼困難,由於IL代碼很差識別;
優勢:使用方便(PostSharp2是收費版,破解也比較方便,在此不介紹破解)ide

這裏我重點介紹如何使用Enterprise Library實現自動化Log。工具


1.首先咱們須要下載Enterprise Library,最新爲5.0版本;測試


2.新建一個控制檯項目,並添加如下程序集
Microsoft.Practices.EnterpriseLibrary.Common
Microsoft.Practices.EnterpriseLibrary.Logging
Microsoft.Practices.EnterpriseLibrary.PolicyInjection
Microsoft.Practices.ServiceLocation
Microsoft.Practices.Unity
Microsoft.Practices.Unity.Interceptionui


3.添加AutoLogCallHandler類,實現ICallHandler接口
這個類是執行調用目標方法,在調用目標方法前獲取方法的參數信息,並用EntLib Log記錄日誌;
方法結束後,再次記錄日誌,並統計執行時間和異常處理this

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using Microsoft.Practices.Unity.InterceptionExtension;  
    using Microsoft.Practices.EnterpriseLibrary.Logging;  
    using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;  
    using System.Diagnostics;  
    using System.Reflection;  
      
    namespace AutoLog {  
        public class AutoLogCallHandler:ICallHandler {  
      
            private LogWriter logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();  
      
            public AutoLogCallHandler() { }  
      
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) {  
                StringBuilder sb = null;  
                ParameterInfo pi = null;  
      
                string methodName = input.MethodBase.Name;  
                logWriter.Write(string.Format("Enter method " + methodName));  
      
      
                if (input.Arguments != null && input.Arguments.Count > 0) {  
                    sb = new StringBuilder();  
                    for (int i = 0; i < input.Arguments.Count; i++) {  
                        pi = input.Arguments.GetParameterInfo(i);  
                        sb.Append(pi.Name).Append(" : ").Append(input.Arguments[i]).AppendLine();  
                    }  
                    logWriter.Write(sb.ToString());  
                }         
                  
      
                Stopwatch sw = new Stopwatch();  
                sw.Start();  
      
                IMethodReturn result = getNext()(input, getNext);  
                //若是發生異常則,result.Exception != null  
                if (result.Exception != null) {  
                    logWriter.Write("Exception:" + result.Exception.Message);  
                    //必須將異常處理掉,不然沒法繼續執行  
                    result.Exception = null;  
                }  
      
                sw.Stop();  
                logWriter.Write(string.Format("Exit method {0}, use {1}.",methodName, sw.Elapsed));  
      
                return result;  
            }  
      
            public int Order { get; set; }  
        }  
    }  

 

4.要自動化日誌就須要建立一個標記屬性,指定方法能自動進行日誌
這裏就建立AutoLogCallHandlerAttribute標記屬性spa

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using Microsoft.Practices.Unity.InterceptionExtension;  
    using Microsoft.Practices.EnterpriseLibrary.Logging;  
    using System.Diagnostics;  
    using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;  
      
    namespace AutoLog {  
      
        public class AutoLogCallHandlerAttribute:HandlerAttribute {  
      
            public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container) {  
                return new AutoLogCallHandler() { Order = this.Order };  
            }  
        }  
    }  

 5.建立實體類
注意:我在Work和ToString方法上方加上了AutoLogCallHandler屬性,它是AutoLogCallHandlerAttribute的簡寫形式。用以指示這兩個方法用AutoLogCallHandler的Invoke來處理。.net

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using Microsoft.Practices.Unity;  
      
    namespace AutoLog {  
      
        public class Employee : MarshalByRefObject   
        {  
              
            public Employee() {}  
      
            public string Name { get; set; }  
      
            [AutoLogCallHandler()]  
            public void Work() {  
                Console.WriteLine("Now is {0},{1} is working hard!",DateTime.Now.ToShortTimeString(),Name);  
                throw new Exception("Customer Exception");  
            }  
      
            [AutoLogCallHandler()]  
            public override string ToString() {  
                return string.Format("I'm {0}.",Name);  
            }  
        }  
    }  

 6.測試代碼
注意:必須使用PolicyInjection.Create<Employee>()來建立對象,否則沒法實現。pwa

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;  
    using Microsoft.Practices.Unity;  
    using Microsoft.Practices.EnterpriseLibrary.Logging;  
    using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;  
      
    namespace AutoLog {  
        class Program {  
      
            private static LogWriter logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();  
      
            static void Main(string[] args) {  
      
      
                Employee emp = PolicyInjection.Create<Employee>();  
      
                emp.Name = "Lele";  
      
                emp.Work();  
                Console.WriteLine(emp);  
            }  
        }  
    }  

 7.還須要用EntLib的配置工具完成Log配置,將Log信息寫入Trace.log文件中

    <?xml version="1.0"?>  
    <configuration>  
        <configSections>  
            <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />  
        </configSections>  
        <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">  
            <listeners>  
                <add name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"  
                    listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"  
                    fileName="trace.log" formatter="Text Formatter" />  
            </listeners>  
            <formatters>  
                <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"  
                    template="Timestamp: {timestamp}{newline}  
    Message: {message}{newline}  
    Category: {category}{newline}  
    Priority: {priority}{newline}  
    EventId: {eventid}{newline}  
    Severity: {severity}{newline}  
    Title:{title}{newline}  
    Machine: {localMachine}{newline}  
    App Domain: {localAppDomain}{newline}  
    ProcessId: {localProcessId}{newline}  
    Process Name: {localProcessName}{newline}  
    Thread Name: {threadName}{newline}  
    Win32 ThreadId:{win32ThreadId}{newline}  
    Extended Properties: {dictionary({key} - {value}{newline})}"  
                    name="Text Formatter" />  
            </formatters>  
            <categorySources>  
                <add switchValue="All" name="General">  
                    <listeners>  
                        <add name="Flat File Trace Listener" />  
                    </listeners>  
                </add>  
            </categorySources>  
            <specialSources>  
                <allEvents switchValue="All" name="All Events" />  
                <notProcessed switchValue="All" name="Unprocessed Category" />  
                <errors switchValue="All" name="Logging Errors & Warnings">  
                    <listeners>  
                        <add name="Flat File Trace Listener" />  
                    </listeners>  
                </errors>  
            </specialSources>  
        </loggingConfiguration>  
        <startup>  
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>  
        </startup>  
    </configuration>  

 

好了,測試一下,控制檯輸入:
Now is 14:03,Lele is working hard!
I'm Lele.
再看看Trace.log文件內容:

    ----------------------------------------  
    Timestamp: 2012/3/19 6:03:00  
      
    Message: Enter method Work  
      
    Category: General  
      
    Priority: -1  
      
    EventId: 1  
      
    Severity: Information  
      
    Title:  
      
    Machine: PC4  
      
    App Domain: AutoLog.exe  
      
    ProcessId: 4200  
      
    Process Name: D:\Codes\Enterprise Library\Enterprise Library Demos\PIAB\Demo\AutoLog\bin\Debug\AutoLog.exe  
      
    Thread Name:   
      
    Win32 ThreadId:4000  
      
    Extended Properties:   
    ----------------------------------------  
    ----------------------------------------  
    Timestamp: 2012/3/19 6:03:00  
      
    Message: Exception:Customer Exception  
      
    Category: General  
      
    Priority: -1  
      
    EventId: 1  
      
    Severity: Information  
      
    Title:  
      
    Machine: PC4  
      
    App Domain: AutoLog.exe  
      
    ProcessId: 4200  
      
    Process Name: D:\Codes\Enterprise Library\Enterprise Library Demos\PIAB\Demo\AutoLog\bin\Debug\AutoLog.exe  
      
    Thread Name:   
      
    Win32 ThreadId:4000  
      
    Extended Properties:   
    ----------------------------------------  
    ----------------------------------------  
    Timestamp: 2012/3/19 6:03:00  
      
    Message: Exit method Work, use 00:00:00.0024272.  
      
    Category: General  
      
    Priority: -1  
      
    EventId: 1  
      
    Severity: Information  
      
    Title:  
      
    Machine: PC4  
      
    App Domain: AutoLog.exe  
      
    ProcessId: 4200  
      
    Process Name: D:\Codes\Enterprise Library\Enterprise Library Demos\PIAB\Demo\AutoLog\bin\Debug\AutoLog.exe  
      
    Thread Name:   
      
    Win32 ThreadId:4000  
      
    Extended Properties:   
    ----------------------------------------  
    ----------------------------------------  
    Timestamp: 2012/3/19 6:03:00  
      
    Message: Enter method ToString  
      
    Category: General  
      
    Priority: -1  
      
    EventId: 1  
      
    Severity: Information  
      
    Title:  
      
    Machine: PC4  
      
    App Domain: AutoLog.exe  
      
    ProcessId: 4200  
      
    Process Name: D:\Codes\Enterprise Library\Enterprise Library Demos\PIAB\Demo\AutoLog\bin\Debug\AutoLog.exe  
      
    Thread Name:   
      
    Win32 ThreadId:4000  
      
    Extended Properties:   
    ----------------------------------------  
    ----------------------------------------  
    Timestamp: 2012/3/19 6:03:00  
      
    Message: Exit method ToString, use 00:00:00.0001410.  
      
    Category: General  
      
    Priority: -1  
      
    EventId: 1  
      
    Severity: Information  
      
    Title:  
      
    Machine: PC4  
      
    App Domain: AutoLog.exe  
      
    ProcessId: 4200  
      
    Process Name: D:\Codes\Enterprise Library\Enterprise Library Demos\PIAB\Demo\AutoLog\bin\Debug\AutoLog.exe  
      
    Thread Name:   
      
    Win32 ThreadId:4000  
      
    Extended Properties:   
    ----------------------------------------  
View Code

實現了自動化Log後,回過頭來再看第5步,Employee繼承了MarshalByRefObject,通常咱們的業務類或數據訪問類都有基類,那麼咱們就須要使用接口
這裏我添加一個IEmployee接口,裏面就Work方法(ToString是重寫Object的)。

    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using Microsoft.Practices.Unity;  
      
    namespace AutoLog {  
      
        public interface IEmployee {  
            void Work();  
        }  
      
        public class Employee : IEmployee   
        {  
              
            public Employee() {  
                //this.Name = "Lele";  
            }  
      
            public string Name { get; set; }  
      
            [AutoLogCallHandler()]  
            public void Work() {  
                Console.WriteLine("Now is {0},{1} is working hard!",DateTime.Now.ToShortTimeString(),Name);  
                throw new Exception("Customer Exception");  
            }  
      
            [AutoLogCallHandler()]  
            public override string ToString() {  
                return string.Format("I'm {0}.",Name);  
            }  
        }  
    }  

 而後在測試類改動一下

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;  
    using Microsoft.Practices.Unity;  
    using Microsoft.Practices.EnterpriseLibrary.Logging;  
    using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;  
      
    namespace AutoLog {  
        class Program {  
      
            private static LogWriter logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();  
      
            static void Main(string[] args) {  
      
                IEmployee emp = PolicyInjection.Create<Employee, IEmployee>();  
      
                emp.Work();  
                Console.WriteLine(emp);  
            }  
        }  
    }  
相關文章
相關標籤/搜索