zoukankan      html  css  js  c++  java
  • 利用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);
        }
    }

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


  • 相关阅读:
    Django Rest framework基础使用之Request/Response
    Django Rest framework基础使用之 serializer
    python基础(一)
    python实现本地图片上传到服务区
    开发中遇到的问题记录
    九、xadmin菜单分组管理
    leetcode-7-整数翻转
    leetcode-6-Z 字形变换
    leetcode-5-最长回文子串
    leetcode-3-无重复字符的最长子串
  • 原文地址:https://www.cnblogs.com/hanzhaoxin/p/3662018.html
Copyright © 2011-2022 走看看