C#实现自动化Log日志

概述

在开发项目的时候,我们不免要使用Log记录日志,使用最多的是Log4Net和EntLib Log,在需要记录日志的代码处加入log.Write(日志信息),假设我需要跟踪业务方法,记录方法的传递参数,执行时间,返回数据等;或者我需要查看方法的调用关系,希望进入方法的时候自动记录参数信息,出方法时记录结果和执行时间信息。这时就是一个典型的AOP运用,Java在AOP方面是很容易实现的,因为java有类加载器。但是.Net在AOP方面就不怎么容易,严格意义上.Net没有真正的AOP。这话并不代表.Net不能实现AOP,比如:PostSharp和Enterprise library就能实现。

先介绍一下PostSharp,我们知道.net代码将编译成MSIL(微软中间语言),然后CPU将MSIL的exe文件生成本地CPU的二进制文件格式,PostSharp就是在编译过程中加入IL代码,因而完成AOP功能。

缺点:编译器需要PostSharp组件,维护代码困难,因为IL代码不好识别;

优点:使用方便(PostSharp2是收费版,破解也比较方便,在此不介绍破解)

这里我重点介绍如何使用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.Interception

3.添加AutoLogCallHandler类,实现ICallHandler接口

这个类是执行调用目标方法,在调用目标方法前获取方法的参数信息,并用EntLib Log记录日志;

方法结束后,再次记录日志,并统计执行时间和异常处理

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标记属性

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来处理。

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>()来创建对象,不然无法实现。

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: 
----------------------------------------

实现了自动化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);
    }
  }
}

————————————————

版权声明:本文为CSDN博主「qing2005」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qing2005/article/details/7368738

版权声明:本文来源于网友收集或网友提供,仅供学习交流之用,如果有侵权,请转告版主或者留言,本公众号立即删除。

- EOF -

技术群:添加小编微信dotnet999

公众号:dotnet讲堂

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值