Dotnet_log4net 介绍说明

  Log4net是基于.net开发的一款非常著名的记录日志开源组件。他最早是2001年7月由NeoWorks Limited启动的项目,基本的框架源于另外的一个非常著名的姐妹组件-log4j。Log4net记录日志的功能非常强大。它可以将日志分不同的等级,比不同的样式,将日志输出到不同的媒介。

  Log4net可以从http://logging.apache.org/log4net/download.html网站下载最新版本。

  在具体应用中,对该组件进行了扩展包装,按日期记录系统异常信息以及相关系统信息。具体代码如下:     

using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Web;
using System.IO;

using Digital.Common;
using log4net;


#region 使用说明

/*
 * 在使用时,应在应用程序目录下,建立目录config(config目录作为所有相关config文件的目录),
 * 并添加log4net.config文件,该文件的内容可为如下内容:
 *
 <?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
    </configSections>
    <log4net>
        <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
            <param name="File" value="Log\"/>
            <param name="AppendToFile" value="true"/>
            <param name="MaxSizeRollBackups" value="100"/>
            <param name="StaticLogFileName" value="false"/>
            <param name="DatePattern" value="yyyyMMdd&quot;.html&quot;"/>
            <param name="RollingStyle" value="Date"/>
            <layout type="log4net.Layout.PatternLayout">
                <param name="ConversionPattern" value="&lt;HR COLOR=red&gt;%n &lt;b&gt;异常时间:&lt;/b&gt;%d &lt;BR&gt;%n &lt;b&gt;异常级别:&lt;/b&gt;%-5p  &lt;BR&gt;%n%m %n &lt;HR Size=1&gt;"/>
            </layout>
        </appender>
        <root>
            <level value="ALL"/>
            <appender-ref ref="RollingLogFileAppender"/>
        </root>
    </log4net>
</configuration>
 *
 */

#endregion


namespace Digital.Framework
{
    /// <summary>
    /// 日志类,可以添加Debug、Message、Warn、Error、Fatal等类别信息,
    /// 该类是Log4Net的包装类
    /// </summary>
    public sealed class MyLog
    {
        internal static log4net.ILog m_MyLog = log4net.LogManager.GetLogger("MyLog");

        #region 私有构造函数,单例模式,防止被实例化
        /// <summary>
        /// 私有构造函数,单例模式,防止被实例化
        /// </summary>
        private MyLog()
        {
           
        }
        #endregion
       
        #region 初始化加载配置文件log4net.config
        /// <summary>
        /// 初始化加载配置文件log4net.config
        /// </summary>
        public static void InitializeLog4Net()
        {
            log4net.Config.XmlConfigurator.Configure();
        }
        #endregion       

        #region 事件基本信息
        /// <summary>
        /// 事件基本信息
        /// </summary>
        private struct EventBody
        {
            /// <summary>
            /// 日志标题变量
            /// </summary>
            public string Title;

            /// <summary>
            /// 日志等级变量
            /// </summary>
            public LogLevel LogLevel;

            /// <summary>
            /// 日志来源变量
            /// </summary>
            public LogSource LogSource;

            /// <summary>
            ///  远程主机IP地址
            /// </summary>
            public string UserHostAddress
            {
                get
                {
                    return HttpHelper.GetClientIP(); 
                }
            }

            /// <summary>
            /// 出错页面地址
            /// </summary>
            public string ErrorPage
            {
                get
                {
                    return WebHelper.GetUrl();// RequestHelper.GetUrl();
                }
            }

            /// <summary>
            /// 页面来源地址
            /// </summary>
            public string ReferrerPage
            {
                get
                {
                    return WebHelper.GetUrlReferrer();
                }
            }

            /// <summary>
            /// 当前会话信息属性
            /// </summary>
            public string CurrentSessionInfo
            {
                get
                {
                    StringBuilder SessionInfo = new StringBuilder();
                    if (HttpContext.Current != null && HttpContext.Current.Session != null)
                    {
                        for (int i = 0; i < HttpContext.Current.Session.Count; i++)
                        {
                            SessionInfo.Append(Environment.NewLine).Append((i + 1).ToString())
                                .Append(":Session[").Append(HttpContext.Current.Session.Keys[i])
                                .Append("] = ").Append(HttpContext.Current.Session[i] == null ? "" : HttpContext.Current.Session[i].ToString());
                        }
                    }

                    if (SessionInfo.Length == 0)
                    {
                        return "Session会话信息为空!";
                    }
                    else
                    {
                        return SessionInfo.Insert(0, "Session会话信息为:" + Environment.NewLine).ToString();
                    }
                }
            }
        }
        #endregion      

        //公有

        #region 写日志方法
        /// <summary>
        /// 写日志方法
        /// </summary>
        public static void WriteLog()
        {
            EventBody CurrentEventBody = new EventBody();
            CurrentEventBody.Title = "未知内容";
            CurrentEventBody.LogSource = LogSource.UnknowLayer;
            CurrentEventBody.LogLevel = LogLevel.Info;

            WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
        }

        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <param name="Title">日志标题</param>
        public static void WriteLog(string Title)
        {
            EventBody CurrentEventBody = new EventBody();
            CurrentEventBody.Title = Title;
            CurrentEventBody.LogSource = LogSource.UnknowLayer;
            CurrentEventBody.LogLevel = LogLevel.Info;

            WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
        }


        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <param name="Source">日志来源</param>
        private static void WriteLog(LogSource Source)
        {
            EventBody CurrentEventBody = new EventBody();
            CurrentEventBody.Title = "未知内容";
            CurrentEventBody.LogSource = Source;
            CurrentEventBody.LogLevel = LogLevel.Info;

            WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
        }

        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <param name="Level">日志等级</param>
        private static void WriteLog(LogLevel Level)
        {
            EventBody CurrentEventBody = new EventBody();
            CurrentEventBody.Title = "未知内容";
            CurrentEventBody.LogSource = LogSource.UnknowLayer;
            CurrentEventBody.LogLevel = Level;

            WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
        }

        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <param name="Level">日志等级</param>
        /// <param name="Source">日志来源</param>
        public static void WriteLog(LogLevel Level, LogSource Source)
        {
            EventBody CurrentEventBody = new EventBody();
            CurrentEventBody.Title = "未知内容";
            CurrentEventBody.LogSource = Source;
            CurrentEventBody.LogLevel = Level;

            WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
        }

        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <param name="Title">日志标题</param>
        /// <param name="Level">日志等级</param>
        /// <param name="Source">日志来源</param>       
        public static void WriteLog(string Title, LogLevel Level, LogSource Source)
        {
            EventBody CurrentEventBody = new EventBody();
            CurrentEventBody.Title = Title;
            CurrentEventBody.LogSource = Source;
            CurrentEventBody.LogLevel = Level;

            WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
        }

        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <param name="EventLevel">日志等级</param>
        /// <param name="Source">日志来源</param>
        /// <param name="Exp">异常对象</param>
        private static void WriteLog(LogLevel Level, LogSource Source, Exception Exp)
        {
            WriteLog("未知内容", Level, Source, Exp);
        }

        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <param name="Title">日志标题</param>
        /// <param name="Level">日志等级</param>
        /// <param name="Source">日志来源</param>
        /// <param name="Exp">异常对象</param>
        public static void WriteLog(string Title, LogLevel Level, LogSource Source, Exception Exp)
        {
            WriteLog(Title, Level, Source, Exp, null);
        }


        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <param name="Title">日志标题</param>
        /// <param name="Level">日志等级</param>
        /// <param name="Source">日志来源</param>       
        /// <param name="Exp">异常对象</param>
        /// <param name="obj">异常发生对象</param>
        public static void WriteLog(string Title, LogLevel Level, LogSource Source, Exception Exp, object obj)
        {
            EventBody CurrentEventBody = new EventBody();
            CurrentEventBody.Title = Title;
            CurrentEventBody.LogLevel = Level;
            CurrentEventBody.LogSource = Source;

            for (Exception Temp = Exp; Temp != null; Temp = Temp.InnerException)
            {
                WriteLog(CurrentEventBody, Temp, obj);
            }
        }

        #endregion
      
        #region 获取日志文件
        /// <summary>
        /// 获取日志文件
        /// </summary>
        /// <returns></returns>
        public static DataTable GetFileinfoDataTable()
        {
            DataTable objDataTable = new DataTable("Fileinfo");

            objDataTable.Columns.Add("FileName", System.Type.GetType("System.String"));
            objDataTable.Columns.Add("FileTime", System.Type.GetType("System.String"));

            string rootPath = HttpContext.Current.Server.MapPath(WebHelper.CurrentContext.Request.Path);
            rootPath = rootPath.Substring(0, rootPath.LastIndexOf('\\'));
            DirectoryInfo objDirectoryInfo = new DirectoryInfo(rootPath);
            FileInfo[] ArrFileInfo = objDirectoryInfo.GetFiles();

            DataRow objDataRow;
            File.Delete(rootPath + "/current.html");
            foreach (FileInfo objFileInfo in ArrFileInfo)
            {
                if (objFileInfo.Name.ToLower().IndexOf("errorlog") == -1 &&
                    objFileInfo.Name.ToLower().IndexOf("current") == -1 &&
                    objFileInfo.Extension == ".html")
                {
                    objDataRow = objDataTable.NewRow();
                    if (objFileInfo.Name == DateTime.Now.ToString("yyyyMMdd") + ".html")
                    {
                        File.Copy(objFileInfo.FullName, rootPath + "/current.html");
                        objDataRow["FileName"] = "current.html";
                        objDataRow["FileTime"] = DateTime.Now.ToString("yyyy年MM月dd日");
                    }
                    else
                    {
                        objDataRow["FileName"] = objFileInfo.Name;
                        objDataRow["FileTime"] = objFileInfo.Name.Replace(".html", "").Insert(4, "年").Insert(7, "月") + "日";
                    }
                    objDataTable.Rows.InsertAt(objDataRow, 0);
                }
            }
            return objDataTable;
        }
        #endregion

        //私有方法

        #region private 写日志方法

        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <param name="objEventBody">事件信息体</param>
        /// <param name="objExp">异常</param>
        private static void WriteLog(EventBody objEventBody, Exception objExp)
        {
            WriteLog(objEventBody, objExp, null);
        }

        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <param name="objEventBody">事件信息体</param>
        /// <param name="objExp">异常</param>
        private static void WriteLog(EventBody objEventBody, Exception objExp, object obj)
        {
            //事件信息初始化
            StringBuilder strEventMessage = new StringBuilder();
            strEventMessage.Append("\r\n");
            strEventMessage.Append("<b>内容标题:</b>").Append(objEventBody.Title).Append("<br>\r\n");
            strEventMessage.Append("<b>远程主机:</b>").Append(objEventBody.UserHostAddress).Append("<br>\r\n");
            strEventMessage.Append("<b>出错页面:</b>").Append(objEventBody.ErrorPage).Append("<br>\r\n");
            strEventMessage.Append("<b>页面来源:</b>").Append(objEventBody.ReferrerPage).Append("<br>\r\n");
            strEventMessage.Append("<b>会话信息:</b>").Append(objEventBody.CurrentSessionInfo).Append("<br>\r\n");
            strEventMessage.Append("<b>事件来源:</b>").Append(objEventBody.LogSource.ToString()).Append("<br>\r\n");

            if (obj != null)
            {
                string objInfo = GetObjectInfo(obj);
                strEventMessage.Append(objInfo);
            }

            switch ((LogLevel)objEventBody.LogLevel)
            {
                case LogLevel.Fatal:
                    if (m_MyLog.IsFatalEnabled)
                    {
                        m_MyLog.Fatal(strEventMessage.ToString(), objExp);
                    }
                    break;

                case LogLevel.Error:
                    if (m_MyLog.IsErrorEnabled)
                    {
                        m_MyLog.Error(strEventMessage.ToString(), objExp);
                    }
                    break;

                case LogLevel.Warn:
                    if (m_MyLog.IsWarnEnabled)
                    {
                        m_MyLog.Warn(strEventMessage.ToString(), objExp);
                    }
                    break;

                case LogLevel.Info:
                    if (m_MyLog.IsInfoEnabled)
                    {
                        m_MyLog.Info(strEventMessage.ToString(), objExp);
                    }
                    break;

                case LogLevel.Debug:
                    if (m_MyLog.IsDebugEnabled)
                    {
                        m_MyLog.Debug(strEventMessage.ToString(), objExp);
                    }
                    break;
            }
        }
        #endregion

        #region private GetObjectInfo 获取对象所有属性信息
        /// <summary>
        /// 获取对象所有属性信息
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static string GetObjectInfo(object obj)
        {
            StringBuilder sb = new StringBuilder();
            Type t = obj.GetType();
            sb.Append("<hr size=1 /><b>对象信息:</b>").Append("<br/>\r\n");
            sb.Append("对象名称:").Append(t.Name).Append("<br/>\r\n");
            sb.Append("对象全名:").Append(t.FullName).Append("<br/>\r\n");
            sb.Append("相关属性:");
            System.Reflection.PropertyInfo[] pis = t.GetProperties();
            foreach (System.Reflection.PropertyInfo pi in pis)
            {
                if (pi.CanRead)
                {
                    sb.Append(pi.Name).Append(":[").Append(pi.GetValue(obj, null)).Append("], ");
                }
            }
            return sb.ToString();
        }
        #endregion
    }


    #region 日志等级(参考log4net等级)
    /// <summary>
    /// 日志等级(参考log4net等级)
    /// </summary>
    public enum LogLevel
    {
        /// <summary>
        /// The Fatal level designates very severe error events
        /// that will presumably lead the application to abort.
        /// </summary>
        Fatal = 110000,  //log4net.Core.Level.Fatal.Value

        /// <summary>
        ///The Error level designates error events that might  
        ///still allow the application to continue running.
        /// </summary>  
        Error = 80000,  //log4net.Core.Level.Error.Value,

        /// <summary>
        /// The Warn level designates potentially harmful
        /// situations.
        /// </summary>
        Warn = 60000,   //log4net.Core.Level.Warn.Value,

        /// <summary>
        /// The Info level designates informational messages that
        /// highlight the progress of the application at coarse-grained level.
        /// </summary>
        Info = 40000, //log4net.Core.Level.Info.Value,

        /// <summary>
        /// The Debug  level designates fine-grained informational
        /// events that are most useful to debug an application.
        /// </summary>
        Debug = 30000 //log4net.Core.Level.Debug.Value

    }
    #endregion

    #region 日志所在层LogSource
    /// <summary>
    /// 日志所在层
    /// </summary>
    public enum LogSource
    {
        /// <summary>
        /// Web层
        /// </summary>
        WebLayer,

        /// <summary>
        /// 通用层
        /// </summary>
        CommonLayer,

        /// <summary>
        /// 数据库访问层
        /// </summary>
        DataLayer,

        /// <summary>
        /// 框架层
        /// </summary>
        FrameworkLayer,

        /// <summary>
        /// 规则层
        /// </summary>
        RuleLayer,

        /// <summary>
        /// 用户控件基类层
        /// </summary>
        WebUILayer,

        /// <summary>
        /// 搜索层
        /// </summary>
        SearchLayer,

        /// <summary>
        /// 项目后台管理层
        /// </summary>
        AdminLayer,

        /// <summary>
        /// 全局
        /// </summary>
        GlobalLayer,

        /// <summary>
        /// 未知层
        /// </summary>
        UnknowLayer
    }
    #endregion
}

 另外,可参考如下网址学习log4net的应用

http://www.cnblogs.com/dragon/archive/2005/03/24/124254.aspx

http://www.rainsts.net/article.asp?id=488

 

本文仅对 Log4net 的使用做个简要说明,所有涉及到扩展和开发的部分一概忽略。

使用 Log4net,需要熟悉的东东有 Logger、Appender 以及 Layout。Logger 是日志记录器,我们使用其相关方法来完成日志记录;Appender 用于设置日志的存储方式和位置,Logger 的配置中会绑定一个或多个 Appender;Layout 关联具体的 Appender,用于设置日志字符串的格式。

1. Logger

所有的记录器都必须实现 ILog 接口,该接口提供日志记录所需的大量方法。

public interface ILog : ILoggerWrapper
{
  void Debug(...);
  void Error(...);
  void Fatal(...);
  void Info(...);
  void Warn(...);

  bool IsDebugEnabled { get; }
  bool IsErrorEnabled { get; }
  bool IsFatalEnabled { get; }
  bool IsInfoEnabled { get; }
  bool IsWarnEnabled { get; }
}


通常情况下,我们通过 LogManager.GetLogger() 来获取一个记录器。LogManager 内部维护一个 hashtable,保存新创建 Logger 引用,下次需要时直接从 hashtable 获取其实例。

ILog log = LogManager.GetLogger(this.GetType());
log.Debug("aaaaaaaaaaaaaaa");


所有 Logger 的参数设置都直接或间接继承自 root,其继承关系类似 namespace。比如,名为 "MyLogger.X.Y" 参数设置继承自 "MyLogger.X"。当我们创建 "MyLooger.X.Y" 记录器时,会在配置文件找该名称的记录器设置,如果没找到,则按继承关系向上查找,直到 root。因此,在创建 Logger 时,我们通常使用类型名称做为记录器的名字,缺省情况下,它会使用 root 或某一个父配置,但在需要的时候,我们随时可以为具体的类型添加一个更加 "详细" 的配置。

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
  <appender name="Console" type="log4net.Appender.ConsoleAppender">
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
    </layout>
  </appender>

  <logger name="Learn.Library.Log4netTest">
    <level value="ALL" />
  </logger>

  <root>
    <level value="OFF" />
    <appender-ref ref="Console" />
  </root>
</log4net>



在创建 Logger 设置时,需要注意 "level" 参数。Log4net 允许我们通过该参数调整日志记录级别,只有高于或等于该级别的日志才会被记录下来。比如在代码调试阶段,我们可能希望记录所有的信息,而在部署阶段,我们只希望记录级别更高的错误信息。这个参数的好处是允许我们在不修改代码的前提下,随时调整记录级别。

(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低)


"appender-ref" 参数用于绑定一个或多个具体的 Appender。

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
  <appender name="Console" type="log4net.Appender.ConsoleAppender">
  </appender>

  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
  </appender>

  <root>
    <level value="DEBUG" />
    <appender-ref ref="Console" />
    <appender-ref ref="RollingFile" />
  </root>
</log4net>


2. Appender / Layout

Log4net 提供了大量的 Appender,最常用的包括 AdoNetAppender、AspNetTraceAppender、ConsoleAppender、FileAppender、OutputDebugStringAppender。每种 Appender 都有特定一些参数,使用时直接从 《Log4net 手册》的示例中拷贝过去,就OK了。(代码摘自 Log4net 手册)

(1) AspNetTraceAppender

<appender name="AspNetTraceAppender" type="log4net.Appender.AspNetTraceAppender" >
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
  </layout>
</appender>


(2) ConsoleAppender

<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
  </layout>
</appender>


(3) OutputDebugStringAppender

<appender name="OutputDebugStringAppender" type="log4net.Appender.OutputDebugStringAppender" >
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
  </layout>
</appender>


(4) FileAppender

<appender name="FileAppender" type="log4net.Appender.FileAppender">
  <file value="log-file.txt" />
  <appendToFile value="true" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
  </layout>
</appender>


有关 Layout 详细信息,请参考 Log4net 相关文档,本文不做详述。

3. Configuration

Log4net 的配置方式十分灵活,即可以写到应用程序配置文件中,也可以使用独立配置文件。同时它还提供了监测配置文件变化的功能,这样我们随时可以调整配置,而无须重启应用程序。

(1) 使用 app.config / web.config

app.config / web.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>

  <log4net>
    <appender name="Console" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
      </layout>
    </appender>

    <root>
      <level value="DEBUG" />
      <appender-ref ref="Console" />
    </root>
  </log4net>
</configuration>


使用代码初始化配置。

log4net.Config.XmlConfigurator.Configure();


(2) 使用自定义配置文件

test.log4net

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
  <appender name="Console" type="log4net.Appender.ConsoleAppender">
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
    </layout>
  </appender>
  
  <root>
    <level value="DEBUG" />
    <appender-ref ref="Console" />
  </root>
</log4net>


使用代码初始化配置。

log4net.Config.XmlConfigurator.Configure(new FileInfo("test.log4net"));


使用 XmlConfigurator.ConfigureAndWatch() 方法除了初始化配置外,还会监测配置文件的变化,一旦发生修改,将自动刷新配置。

(3) XmlConfiguratorAttribute

我们还可以使用 XmlConfiguratorAttribute 代替 XmlConfigurator.Config()/ConfigureAndWatch(),ConfiguratorAttribute 用于定义与 Assembly 相关联的配置文件名。

方式1: 关联到 test.log4net,并监测变化。

[assembly: log4net.Config.XmlConfigurator(ConfigFile="test.log4net", Watch=true)]


方式2: 关联到 test.exe.log4net (或 test.dll.log4net,文件名前缀为当前程序集名称),并监测变化。

[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension="log4net", Watch=true)]

 

posted @ 2010-03-04 12:05  kim zeng  阅读(360)  评论(0编辑  收藏  举报