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

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

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

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

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

另一方面

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

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

System.Diagnostics.TraceSystem.Diagnostics.Debug

调用方法

using System.Diagnostics;

...
...
     Trace.TraceError("这是一个Error级别的日志");
     Trace.TraceWarning("这是一个Warning级别的日志");
     Trace.TraceInformation("这是一个Info级别的日志");
     Trace.WriteLine("这是一个普通日志");
     Trace.Flush();//立即输出
...
...

Trace,Debug的调用方式完全相同,不同的地方在于Debug的所有方法都有 [Conditional("DEBUG")],表明了,在Release模式下(没有定义DEBUG常量时),该方法不会被编译的(不是不执行,而是根本不会编译到程序中去),也就是说 Debug.XXX() 方法仅在Debug模式下运行,这个又可以为我们省下很多事

重写日志实现

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

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

必须实现的方法有

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

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

简单示例

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);
    }
}

特殊例子

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, "计算员工工资出现异常");
    }
}

调用方法

程序入口初始化

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);//记录日志
    }
}

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

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

特别是在Web项目中,这将变得更加方便

  • 监听器

    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);
      }
    

    }

  • 配置文件

    <?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就可以了

配合 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);
    }
}

知识共享许可协议
《利用C#自带组件强壮程序日志》 常伟华 创作。
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议 | 3.0 中国大陆许可协议进行许可。

站内公告