Fork me on GitHub

利用C#自带组件强壮程序日志

前言

在项目正式上线后,如果出现错误、异常、崩溃等情况,

我们往往第一想到的事就是查看日志。

所以日志对于一个系统的维护是非常重要的。

声明

本文中的示例代码旨在这个框架是怎么工作的,具体实现可以自由发挥。

贯穿所有的日志系统

日志系统,往往是贯穿一个程序的所有代码的;

试想一下,如果你的日志完全是由第三方组件提供的;

那么就意味着,你的所有项目都必须引用这个dll;

也许你会说自己可以2次封装,那么依然需要所有项目都引用你的这个封装后的log项目,

另一方面

一些log组件需要实例化后才可以使用,比如log4net,这又意味着你得有一个全局的静态变量,或者你自己二次封装,

但其实微软已经为我们提供了2个十分方便的静态类,用于日志的记录。

System.Diagnostics.Trace和System.Diagnostics.Debug

关于这2个类的文档可以去看MSDN

System.Diagnostics.Trace

System.Diagnostics.Debug

它使用非常方便,不用引用任何dll。

调用它的方法也很简单

using System.Diagnostics;
 
...
...
     Trace.TraceError("这是一个Error级别的日志");
     Trace.TraceWarning("这是一个Warning级别的日志");
     Trace.TraceInformation("这是一个Info级别的日志");
     Trace.WriteLine("这是一个普通日志");
     Trace.Flush();//立即输出
...
...
当然方法不止只有4个,更多的可以参考MSDN。
Trace,Debug的调用方式完全相同,不同的地方在于Debug的所有方法都有:
[Conditional("DEBUG")]
 

012117~1

表明了,在Release模式下(没有定义DEBUG常量时),该方法不会被编译的(不是不执行,而是根本不会编译到程序中去)。

也就是说 Debug.XXX() 方法仅在Debug模式下运行,这个又可以为我们省下很多事。


重写日志实现

Trace和Debug中的方法的默认行为是输出到控制台Console,和Console.Write是一样的。

但是我们通过改变他的监听器TraceListener,来实现更多的操作,

必须实现的方法有:

void Write(string message);
void WriteLine(string message);
 

不过也可以主动重写其他方法。

012130~1

随便写一个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);//记录日志
    }
}

image

由于大部分方法都是可重写的,所以其实最终输出什么都是可以非常灵活。

通过配置文件初始化监听器

通过配置文件初始化监听器比直接写代码稍稍复杂一点,但是也更方便,我们可以快速的,不重新编译系统,即可进行对日志监听器进行设定。

演示如下:


示例:

我们将ProjectTraceListener独立成一个项目,编译为dll。

ProjectTraceListener.cs

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4: using System.Diagnostics;
   5: using System.IO;
   6:  
   7: namespace ProjectLog
   8: {
   9:     public class ProjectTraceListener : TraceListener
  10:     {
  11:         public string FilePath { get; private set; }
  12:  
  13:         public ProjectTraceListener(string filePath)
  14:         {
  15:             FilePath = filePath;
  16:         }
  17:  
  18:         public override void Write(string message)
  19:         {
  20:             File.AppendAllText(FilePath, message);
  21:         }
  22:         public override void WriteLine(string message)
  23:         {
  24:             File.AppendAllText(FilePath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss    ") + message + Environment.NewLine);
  25:         }
  26:         public override void Write(object o, string category)
  27:         {
  28:             string message = string.Empty;
  29:             if (!string.IsNullOrEmpty(category))
  30:             {
  31:                 message = category + ":";
  32:             }
  33:             if (o is Exception)//如果参数对象o是与Exception类兼容,输出异常消息+堆栈,否则输出o.ToString()
  34:             {
  35:                 var ex = (Exception)o;
  36:                 message += ex.Message + Environment.NewLine;
  37:                 message += ex.StackTrace;
  38:             }
  39:             else if(null != o)
  40:             {
  41:                 message += o.ToString();
  42:             }
  43:  
  44:             WriteLine(message);
  45:         }
  46:     }
  47: }

 

在控制台项目中测试:

App.config

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <system.diagnostics>
   4:     <trace autoflush="false" indentsize="4">
   5:       <listeners>
   6:         <clear/>
   7:         <!--清除默认监听器-->
   8:         <!--添加自定义监听器 initializeData 就是初始化参数-->
   9:         <add name="ProjectTraceListener" type="ProjectLog.ProjectTraceListener, ProjectLog, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" initializeData="d:\Error.log" />
  10:       </listeners>
  11:     </trace>
  12:     <switches>
  13:       <!--这里可以设定监听级别,可以设置Error,Warning,Info或者留空-->
  14:       <add name="ProjectTraceListener" value="Error" />
  15:     </switches>
  16:   </system.diagnostics>
  17: </configuration>

 

Program.cs

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4: using System.Diagnostics;
   5: using ProjectLog;
   6:  
   7: namespace ProjectLogDemo
   8: {
   9:     class Program
  10:     {
  11:         static void Main(string[] args)
  12:         {
  13:             //删除初始化代码,改为在配置文件中设置
  14:             //Trace.Listeners.Clear();  //清除系统监听器 (就是输出到Console的那个)
  15:             //Trace.Listeners.Add(new ProjectTraceListener(@"d:\Error.log")); //添加ProjectTraceListener实例
  16:             Test();
  17:         }
  18:  
  19:         private static void Test()
  20:         {
  21:             try
  22:             {
  23:                 int i = 0;
  24:                 Console.WriteLine(5 / i); //出现除0异常
  25:             }
  26:             catch (Exception ex)
  27:             {
  28:                 Trace.Write(ex, "计算员工工资出现异常");
  29:             }
  30:         }
  31:     }
  32: }

 

在web项目中测试:

Web.config

   1: <?xml version="1.0"?>
   2: <configuration>
   3:  
   4:     <appSettings />
   5:     <connectionStrings />
   6:     <system.web>
   7:         <compilation debug="true">
   8:  
   9:         </compilation>
  10:         <!--
  11:             通过 <authentication> 节可以配置
  12:             安全身份验证模式,ASP.NET 
  13:             使用该模式来识别来访用户身份。 
  14:         -->
  15:         <authentication mode="Windows" />
  16:         <!--
  17:             如果在执行请求的过程中出现未处理的错误,
  18:             则通过 <customErrors> 节
  19:             可以配置相应的处理步骤。具体而言,
  20:             开发人员通过该节可配置要显示的 html 错误页,
  21:             以代替错误堆栈跟踪。
  22: 
  23:         <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
  24:             <error statusCode="403" redirect="NoAccess.htm" />
  25:             <error statusCode="404" redirect="FileNotFound.htm" />
  26:         </customErrors>
  27:         -->
  28:  
  29:     </system.web>
  30:     <system.diagnostics>
  31:       <trace autoflush="false" indentsize="4">
  32:         <listeners>
  33:           <clear/>
  34:           <!--清除默认监听器-->
  35:           <!--添加自定义监听器 initializeData 就是初始化参数-->
  36:           <add name="ProjectTraceListener" type="ProjectLog.ProjectTraceListener, ProjectLog, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" initializeData="d:\Error.log" />
  37:         </listeners>
  38:       </trace>
  39:       <switches>
  40:         <!--这里可以设定监听级别,可以设置Error,Warning,Info或者留空-->
  41:         <add name="ProjectTraceListener" value="Error" />
  42:       </switches>
  43:     </system.diagnostics>
  44: </configuration>

 

Default.aspx

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Web;
   4: using System.Web.UI;
   5: using System.Web.UI.WebControls;
   6: using System.Diagnostics;
   7: using ProjectLog;
   8:  
   9: namespace ProjectLogDemoByWeb
  10: {
  11:     public partial class _Default : System.Web.UI.Page
  12:     {
  13:         protected void Page_Load(object sender, EventArgs e)
  14:         {
  15:             //删除初始化代码,改为在配置文件中设置
  16:             //System.Diagnostics.Trace.Listeners.Clear();  //清除系统监听器 (就是输出到Console的那个)
  17:             //System.Diagnostics.Trace.Listeners.Add(new ProjectLog.ProjectTraceListener(@"d:\Error.log")); //添加ProjectTraceListener实例
  18:             Test();
  19:         }
  20:  
  21:         private static void Test()
  22:         { 
  23:             try
  24:             {
  25:                 int i = 0;
  26:                 Console.WriteLine(5 / i); //出现除0异常
  27:             }
  28:             catch (Exception ex)
  29:             {
  30:                 System.Diagnostics.Trace.Write(ex, "计算员工工资出现异常");
  31:             }
  32:         }
  33:     }
  34: }

配置文件中的type参数可以这样获得:

typeof(MyLog.MyTraceListener).AssemblyQualifiedName

拓展

以log4net为例说明此框架对其他log系统的引用。

public class ProjectTraceListener : 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);
    }
}

原文来自:冰麟轻武的博客园


posted @ 2014-04-13 12:15  韩兆新  阅读(13797)  评论(0编辑  收藏  举报