log4net_log4net配置 - CSDN
精华内容
参与话题
  • C#一个完整的Log4net使用实例

    万次阅读 2019-04-28 10:02:47
    Log4net库是.Net下一个非常优秀的开源日志记录组件,是一个帮助程序员将日志信息输出到各种目标(控制台、文件、数据库等)的工具。它具有:支持多数框架、可输出日志到多种目标、层级日志体系、可使用XML配置、可...

    Log4net库是.Net下一个非常优秀的开源日志记录组件,是一个帮助程序员将日志信息输出到各种目标(控制台、文件、数据库等)的工具。它具有:支持多数框架、可输出日志到多种目标、层级日志体系、可使用XML配置、可动态配置、模块化和可扩展化设计、灵活、高性能等特征。

    日志记录器(Logger)的行为是分等级的,一般可分为5种日志等级(Level),优先级从高到低:

    1、FATAL(致命错误):记录系统中出现的能使用系统完全失去功能,服务停止,系统崩溃等使系统无法继续运行下去的错误。例如,数据库无法连接,系统出现死循环。

    2、ERROR(一般错误):记录系统中出现的导致系统不稳定,部分功能出现混乱或部分功能失效一类的错误。例如,数据字段为空,数据操作不可完成,操作出现异常等。

    3、WARN(警告):记录系统中不影响系统继续运行,但不符合系统运行正常条件,有可能引起系统错误的信息。例如,记录内容为空,数据内容不正确等。

    4、INFO(一般信息):记录系统运行中应该让用户知道的基本信息。例如,服务开始运行,功能已经开户等。

    5、DEBUG (调试信息):记录系统用于调试的一切信息,内容或者是一些关键数据内容的输出。

    我们可以控制到应用程序中相应级别的日志信息的开关。比如在定义了INFO级别, 则应用程序中所有DEBUG级别的日志信息将不被打印出来。

    使用实例:

    1、新建WPF应用程序LogDemo;

    2、在项目中添加对log4net.dll的引用,这里引用版本是2.0.8.0。

    3、在App.config文件中添加配置信息;

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <!--log4net配置start-->
      <configSections>
        <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/>
      </configSections>
      <log4net>
        <appender name="RollingLogFileAppender_DateFormat" type="log4net.Appender.RollingFileAppender">
          <file value="D:/Log/Demo_"/>
          <appendToFile value="true"/>
          <rollingStyle value="Date"/>
          <datePattern value="yyyy-MM-dd&quot;.log&quot;"/>
          <staticLogFileName value="false"/>
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread](%file:%line) %-5level %logger [%property{NDC}] - %message%newline"/>
          </layout>
        </appender>
        <root>
          <appender-ref ref="RollingLogFileAppender_DateFormat"/>
        </root>
      </log4net>
      <!--log4net配置end-->
      <startup> 
          <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
      </startup>
    </configuration>

    4、在AssemblyInfo.cs中添加配置项

    //Log4net.config配置文件
    [assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "config", Watch = true)]

    5、新建XML文件夹添加Config.xml配置文件

    <?xml version="1.0" encoding="utf-8" ?>
    <appSettings>
      <!--日志等级-->
      <LogLevel>0</LogLevel>
      <!--日志目录-->
      <LogFilePath>D:/Log</LogFilePath>
      <!--日志存在天数-->
      <LogFileExistDay>1</LogFileExistDay>
    </appSettings>

    注意修改Config.xml文件属性: 

    6、新建Utility文件夹,分别添加日志记录类LogHelper.cs、全局使用参数类Parameter.cs、XML文件读取类XMLHelper.cs;

    LogHelper.cs

    using System;
    using System.Reflection;
    using static LogDemo.Utility.Parameter;
    
    namespace LogDemo.Utility
    {
        /// <summary>
        /// Fatal级别的日志由系统全局抓取
        /// </summary>
        public class LogHelper
        {
            public static readonly log4net.ILog log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
    
            public static void Debug(object messsage)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Debug)
                {
                    log.Debug(messsage);
                }
            }
    
            public static void DebugFormatted(string format, params object[] args)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Debug)
                {
                    log.DebugFormat(format, args);
                }
            }
    
            public static void Info(object message)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Info)
                {
                    log.Info(message);
                }
            }
    
            public static void InfoFormatted(string format, params object[] args)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Info)
                {
                    log.InfoFormat(format, args);
                }
            }
    
            public static void Warn(object message)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Warn)
                {
                    log.Warn(message);
                }
            }
    
            public static void WarnFormatted(string format, params object[] args)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Warn)
                {
                    log.WarnFormat(format, args);
                }
            }
    
            public static void Error(object message)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Error)
                {
                    log.Error(message);
                }
            }
    
            public static void Error(object message, Exception exception)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Error)
                {
                    log.Error(message, exception);
                }
            }
    
            public static void ErrorFormatted(string format, params object[] args)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Error)
                {
                    log.ErrorFormat(format, args);
                }
            }
    
            public static void Fatal(object message)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Fatal)
                {
                    log.Fatal(message);
                }
            }
    
            public static void Fatal(object message, Exception exception)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Fatal)
                {
                    log.Fatal(message, exception);
                }
            }
    
            public static void FatalFormatted(string format, params object[] args)
            {
                if ((int)Parameter.LogLevel <= (int)LogLevelEnum.Fatal)
                {
                    log.FatalFormat(format, args);
                }
            }
        }
    }
    

    Parameter.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace LogDemo.Utility
    {
        public class Parameter
        {
            /// <summary>
            /// 日志等级
            /// </summary>
            public enum LogLevelEnum
            {
                Debug = 0,
                Info = 1,
                Warn = 2,
                Error = 3,
                Fatal = 4
            }
    
            /// <summary>
            /// 当前保存日志等级
            /// </summary>
            public static LogLevelEnum LogLevel;
    
            /// <summary>
            /// 日志存放路径
            /// </summary>
            public static string LogFilePath;
    
            /// <summary>
            /// 日志存放天数
            /// </summary>
            public static int LogFileExistDay;
        }
    }
    

    XMLHelper.cs

    using System;
    using System.IO;
    using System.Xml;
    using static LogDemo.Utility.Parameter;
    
    namespace LogDemo.Utility
    {
        public static class XMLHelper
        {
            public static void ReadXml()
            {
                try
                {
                    XmlDocument doc = new XmlDocument();
                    doc.Load(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "XML", "Config.xml"));
                    var node = doc.SelectSingleNode("appSettings");
                    Parameter.LogLevel = (LogLevelEnum)Enum.Parse(typeof(LogLevelEnum), node.SelectSingleNode("LogLevel").InnerText);
                    Parameter.LogFilePath = node.SelectSingleNode("LogFilePath").InnerText;
                    Parameter.LogFileExistDay = int.Parse(node.SelectSingleNode("LogFileExistDay").InnerText);
    
                    LogHelper.Debug("XML文件读取成功。");
                }
                catch (Exception ex)
                {
                    LogHelper.log.Error(string.Format("XML文件读取失败。{0}", ex));
                }
            }
        }
    }
    

    7、在App.xaml.cs中添加系统全局抓取日志记录

    using LogDemo.Utility;
    using System.Windows;
    
    namespace LogDemo
    {
        /// <summary>
        /// App.xaml 的交互逻辑
        /// </summary>
        public partial class App : Application
        {
            protected override void OnStartup(StartupEventArgs e)
            {
                base.OnStartup(e);
                this.DispatcherUnhandledException += App_DispatcherUnhandledException;
            }
    
            private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
            {
                LogHelper.Fatal(e.Exception);//添加系统全局抓取日志记录
                e.Handled = true;
            }
        }
    }
    

    8、主界面xaml

    <Window x:Class="LogDemo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:LogDemo"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Label Content="现在可以查看日志了" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="32"></Label>
        </Grid>
    </Window>

     9、交互逻辑

    using LogDemo.Utility;
    using System;
    using System.IO;
    using System.Threading.Tasks;
    using System.Windows;
    
    namespace LogDemo
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                Init();
            }
    
            private void Init()
            {
                //读取XML配置信息
                XMLHelper.ReadXml();
                //日志清除
                Task.Factory.StartNew(() =>
                {
                    DirectoryInfo di = new DirectoryInfo(Parameter.LogFilePath);
                    if (!di.Exists)
                        di.Create();
                    FileInfo[] fi = di.GetFiles("Demo_*.log");
                    DateTime dateTime = DateTime.Now;
                    foreach (FileInfo info in fi)
                    {
                        TimeSpan ts = dateTime.Subtract(info.LastWriteTime);
                        if (ts.TotalDays > Parameter.LogFileExistDay)
                        {
                            info.Delete();
                            LogHelper.Debug(string.Format("已删除日志。{0}", info.Name));
                        }
                    }
                    LogHelper.Debug("日志清理完毕。");
                });
            }
        }
    }
    

    10、项目结构 

    11、运行结果

    展开全文
  • log4net 详解

    2018-11-11 22:50:44
    非常完善的 log4net 详细说明 作者:未知(搜了很久,未能找到原创者) https://www.cnblogs.com/lzrabbit/archive/2012/03/23/2413180.html 1、概述 log4net 是 .Net 下一个非常优秀的开源日志记录组件。log4net ...

    log4net 详解

    作者:未知(搜了很久,未能找到原创者)
    https://www.cnblogs.com/lzrabbit/archive/2012/03/23/2413180.html

    1、概述

    log4net 是 .Net 下一个非常优秀的开源日志记录组件。log4net 记录日志的功能非常强大。它可以将日志分不同的等级,以不同的格式,输出到不同的媒介。本文主要是介绍如何在 Visual Studio 2008 中使用 log4net 快速创建系统日志,如何扩展以输出自定义字段。

    官网:https://logging.apache.org/log4net

    2、一个简单的使用实例

    第一步: 在项目中添加对 log4net.dll 的引用,这里引用版本是 1.2.10.0 。

    第二步: 程序启动时读取 log4net 的配置文件。

    如果是 CS 程序,在根目录的 Program.cs 中的 Main 方法中添加:

    log4net.Config.XmlConfigurator.Configure();
    

    如果是 BS 程序,在根目录的 Global.asax.cs(没有新建一个)中的 Application_Start 方法中添加:

    log4net.Config.XmlConfigurator.Configure();
    

    无论 BS 还是 CS 程序都可直接在项目的 AssemblyInfo.cs 文件里添加以下的语句:

    [assembly: log4net.Config .XmlConfigurator()]
    

    也可以使用自定义的配置文件,具体请参见 4.4 关联配置文件。

    第三步: 修改配置文件。如果是 CS 程序,则在默认的 App.config 文件(没有新建一个)中添加内容;如果是 BS 程序,则添加到 Web.config 文件中,添加内容一样,这里不再列出。

    App.config 文件添加内容如下:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
      </configSections>
      <log4net>
        <root>
          <level value="WARN" />
          <appender-ref ref="LogFileAppender" />
          <appender-ref ref="ConsoleAppender" />
        </root>
        <logger name="testApp.Logging">
          <level value="DEBUG"/>
        </logger>
        <appender name="LogFileAppender" type="log4net.Appender.FileAppender" >
          <param name="File" value="log-file.txt" />
          <param name="AppendToFile" value="true" />
          <layout type="log4net.Layout.PatternLayout">
            <param name="Header" value="\[Header\] "/>
            <param name="Footer" value="\[Footer\] "/>
            <param name="ConversionPattern" value="%d \[%t\] %-5p %c \[%x\]  - %m%n" />
          </layout>
          <filter type="log4net.Filter.LevelRangeFilter">
            <param name="LevelMin" value="DEBUG" />
            <param name="LevelMax" value="WARN" />
          </filter>
        </appender>
        <appender name="ConsoleAppender"  type="log4net.Appender.ConsoleAppender" >
          <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern"value="%d \[%t\] %-5p %c \[%x\] - %m%n" />
          </layout>
        </appender>
      </log4net>
    </configuration>
    

    第四步: 在程序使用。

    log4net.ILog log = log4net.LogManager.GetLogger("testApp.Logging"); // 获取一个日志记录器
    log.Info(DateTime.Now.ToString() + ": login success"); // 写入一条新 log
    

    这样就将信息同时输出到控制台和写入到文件名为 “log-file.txt” 的文件中,其中 “log-file.txt” 文件的路径是当前程序运行所在目录;也可以定义为绝对路径,配置如:

    <param name="File" value="C:/log-file.txt" />
    

    这样就写入 C 盘根目录下 log-file.txt 文件中了,具体使用技巧参见4.2.1。

    本例的实现请参见 8.6 附件。

    3、Log4net的主要组成部分

    3.1 Appenders

    Appenders 用来定义日志的输出方式,即日志要写到哪种介质上去。较常用的 log4net 已经实现好了,直接在配置文件中调用即可,可参见上面配置文件例子;当然也可以自己写一个,需要从 log4net.Appender.AppenderSkeleton 类继承。它还可以通过配置 Filters 和 Layout 来实现日志的过滤和输出格式。

    已经实现的输出方式有:

    • AdoNetAppender 将日志记录到数据库中。可以采用 SQL 和存储过程两种方式。
    • AnsiColorTerminalAppender 将日志高亮输出到 ANSI 终端。
    • AspNetTraceAppender 能用 asp.net 中 Trace 的方式查看记录的日志。
    • BufferingForwardingAppender 在输出到子 Appenders 之前先缓存日志事件。
    • ConsoleAppender 将日志输出到应用程序控制台。
    • EventLogAppender 将日志写到 Windows Event Log。
    • FileAppender 将日志输出到文件。
    • ForwardingAppender 发送日志事件到子 Appenders。
    • LocalSyslogAppender 将日志写到 local syslog service (仅用于 UNIX 环境下)。
    • MemoryAppender 将日志存到内存缓冲区。
    • NetSendAppender 将日志输出到 Windows Messenger service,这些日志信息将在用户终端的对话框中显示。
    • OutputDebugStringAppender 将日志输出到 Debuger,如果程序没有 Debuger,就输出到系统 Debuger。如果系统 Debuger 也不可用,将忽略消息。
    • RemoteSyslogAppender 通过 UDP 网络协议将日志写到 Remote syslog service。
    • RemotingAppender 通过 .NET Remoting 将日志写到远程接收端。
    • RollingFileAppender 将日志以回滚文件的形式写到文件中。
    • SmtpAppender 将日志写到邮件中。
    • SmtpPickupDirAppender 将消息以文件的方式放入一个目录中,像 IIS SMTP agent 这样的 SMTP 代理就可以阅读或发送它们。
    • TelnetAppender 客户端通过 Telnet 来接受日志事件。
    • TraceAppender 将日志写到 .NET trace 系统。
    • UdpAppender 将日志以无连接UDP数据报的形式送到远程宿主或用 UdpClient 的形式广播。

    3.2 Filters

    使用过滤器可以过滤掉 Appender 输出的内容。过滤器通常有以下几种:

    • DenyAllFilter 阻止所有的日志事件被记录
    • LevelMatchFilter 只有指定等级的日志事件才被记录
    • LevelRangeFilter 日志等级在指定范围内的事件才被记录
    • LoggerMatchFilter 与Logger名称匹配,才记录
    • PropertyFilter 消息匹配指定的属性值时才被记录
    • StringMathFilter 消息匹配指定的字符串才被记录

    3.3 Layout

    Layout 用于控制 Appender 的输出格式,可以是线性的也可以是 XML。

    一个 Appender 能有一个 Layout。

    最常用的 Layout 应该是经典格式的 PatternLayout ,其次是 SimpleLayout ,RawTimeStampLayout 和 ExceptionLayout 。然后还有 IRawLayout ,XMLLayout 等几个,使用较少。Layout 可以自己实现,需要从 log4net.Layout.LayoutSkeleton 类继承,来输出一些特殊需要的格式,在后面扩展时就重新实现了一个 Layout。

    SimpleLayout 简单输出格式,只输出日志级别与消息内容。

    RawTimeStampLayout 用来格式化时间,在向数据库输出时会用到。样式如 “yyyy-MM-dd HH:mm:ss” 。

    ExceptionLayout 需要给 Logger 的方法传入 Exception 对象作为参数才起作用,否则就什么也不输出。输出的时候会包含 Message 和 Trace。

    PatterLayout 使用最多的一个 Layout ,能输出的信息很多,使用方式可参见上面例子中的配置文件。PatterLayout 的格式化字符串见文后附注 8.1。

    3.4 Loggers

    Logger 是直接和应用程序交互的组件。Logger 只是产生日志,然后由它引用的 Appender 记录到指定的媒介,并由 Layout 控制输出格式。

    Logger 提供了多种方式来记录一个日志消息,也可以有多个 Logger 同时存在。每个实例化的 Logger 对象对被 log4net 作为命名实体(Named Entity)来维护。log4net 使用继承体系,也就是说假如存在两个 Logger,名字分别为 a.b.c 和 a.b 。那么 a.b 就是 a.b.c 的祖先。每个 Logger 都继承了它祖先的属性。所有的 Logger 都从 Root 继承,Root 本身也是一个 Logger 。

    日志的等级,它们由高到底分别为:

    OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL

    高于等级设定值方法(如何设置参见“配置文件详解”)都能写入日志,Off 所有的写入方法都不写到日志里,ALL 则相反。例如当我们设成 Info 时,logger.Debug 就会被忽略而不写入文件,但是 FATAL ,ERROR ,WARN ,INFO 会被写入,因为他们等级高于 INFO 。

    在具体写日志时,一般可以这样理解日志等级:

    • FATAL(致命错误):记录系统中出现的能使用系统完全失去功能,服务停止,系统崩溃等使系统无法继续运行下去的错误。例如,数据库无法连接,系统出现死循环。
    • ERROR(一般错误):记录系统中出现的导致系统不稳定,部分功能出现混乱或部分功能失效一类的错误。例如,数据字段为空,数据操作不可完成,操作出现异常等。
    • WARN(警告):记录系统中不影响系统继续运行,但不符合系统运行正常条件,有可能引起系统错误的信息。例如,记录内容为空,数据内容不正确等。
    • INFO(一般信息):记录系统运行中应该让用户知道的基本信息。例如,服务开始运行,功能已经开户等。
    • DEBUG (调试信息):记录系统用于调试的一切信息,内容或者是一些关键数据内容的输出。

    Logger 实现的 ILog 接口,ILog 定义了5个方法(Debug,Info,Warn,Error,Fatal)分别对不同的日志等级记录日志。这 5 个方法还有 5 个重载。以 Debug 为例说明一下,其它的和它差不多。

    ILog 中对 Debug 方法的定义如下:

    void Debug(object message);
    void Debug(object message, Exception ex);
    

    还有一个布尔属性:

    bool IsDebugEnabled { get; }
    

    如果使用 Debug(object message, Exception ex) ,则无论 Layout 中是否定义了 %exception ,默认配置下日志都会输出 Exception 。包括 Exception 的 Message 和 Trace 。如果使用 Debug(object message) ,则日志是不会输出 Exception 。

    最后还要说一个 LogManager 类,它用来管理所有的 Logger 。它的 GetLogger 静态方法,可以获得配置文件中相应的 Logger :

    log4net.ILog log = log4net.LogManager.GetLogger("logger-name");
    

    3.5 Object Renders

    它将告诉 logger 如何把一个对象转化为一个字符串记录到日志里。( ILog 中定义的接口接收的参数是 Object ,而不是 String 。)

    例如你想把 Orange 对象记录到日志中,但此时 logger 只会调用 Orange 默认的 ToString 方法而已。所以要定义一个 OrangeRender 类实现 log4net.ObjectRender.IObjectRender 接口,然后注册它(我们在本文中的扩展不使用这种方法,而是直接实现一个自定义的 Layout )。这时 logger 就会知道如何把 Orange 记录到日志中了。

    3.6 Repository

    Repository 主要用于日志对象组织结构的维护。

    4、配置文件详解

    4.1 配置文件构成

    主要有两大部分,一是申明一个名为 “log4net” 的自定义配置节,如下所示:

    <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
    </configSections>
    

    二是 <log4net> 节的具体配置,这是下面要重点说明的。

    4.1.1

    所有的配置都要在 <log4net> 元素里定义。

    支持的属性:

    debug 可选,取值是 true 或 false ,默认是 false 。设置为 true ,开启 log4net 的内部调试。
    update 可选,取值是 Merge(合并)或 Overwrite(覆盖),默认值是 Merge 。设置为 Overwrite ,在提交配置的时候会重置已经配置过的库。
    threshold 可选,取值是 repository(库)中注册的 level ,默认值是 ALL。

    支持的子元素:

    appender 0 或多个
    logger 0 或多个
    renderer 0 或多个
    root 最多一个
    param 0 或多个

    4.1.2 <root>

    实际上就是一个根 logger ,所有其它 logger 都默认继承它,如果配置文件里没有显式定义,则框架使用根日志中定义的属性。root 元素没有属性。

    支持的子元素:

    appender-ref 0 个或多个,要引用的 appender 的名字。
    level 最多一个。 只有在这个级别或之上的事件才会被记录。
    param 0 个或多个, 设置一些参数。

    4.1.3 <logger>

    支持的属性:

    name 必须的,logger 的名称
    additivity 可选,取值是 true 或 false ,默认值是 true 。设置为 false 时将阻止父 logger 中的 appender 。

    支持的子元素:

    appender-ref 0 个或多个,要引用的 appender 的名字。
    level 最多一个。只有在这个级别或之上的事件才会被记录。
    param 0 个或多个,设置一些参数。

    4.1.4 <appender>

    定义日志的输出方式,只能作为 log4net 的子元素。name 属性必须唯一,type 属性必须指定。

    支持的属性:

    name 必须的,Appender 对象的名称
    type 必须的,Appender 对象的输出类型

    支持的子元素:

    appender-ref 0 个或多个,允许此 appender 引用其他 appender ,并不是所以 appender 类型都支持。
    filter 0 个或多个,定义此 app 使用的过滤器。
    layout 最多一个。定义 appender 使用的输出格式。
    param 0 个或多个, 设置 Appender 类中对应的属性的值。

    实际上 <appender> 所能包含的子元素远不止上面 4 个。

    4.1.5 <layout>

    布局,只能作为 <appender> 的子元素。

    支持的属性:

    type 必须的,Layout 的类型

    支持的子元素:

    param 0个或多个, 设置一些参数。

    4.1.6 <filter>

    过滤器,只能作为 <appender> 的子元素。

    支持的属性:

    type 必须的,Filter 的类型

    支持的子元素:

    param 0 个或多个, 设置一些参数。

    4.1.7 <param>

    元素可以是任何元素的子元素。

    支持的属性:

    name 必须的,取值是父对象的参数名。
    value 可选的,value 和 type 中,必须有一个属性被指定。value 是一个能被转化为参数值的字符串。
    type 可选的,value 和 type 中,必须有一个属性被指定。type 是一个类型名,如果 type 不是在 log4net 程序集中定义的,就需要使用全名。

    支持的子元素:

    param 0 个或多个, 设置一些参数。

    4.2 <appender> 配置

    <appender> 在配置文件中至少有一个,也可以有多个,有些 <appender> 类型还可以引用其他 <appender> 类型,具体参数可参见上表。

    下面只对写入回滚文件与输出到数据库(这里使用 SQL 数据库)配置体会说一下,其他配置可参考官方网站:http://logging.apache.org/log4net/release/config-examples.html

    4.2.1 写入回滚文件

    <appender name="ReflectionLayout" type="log4net.Appender.RollingFileAppender,log4net">
    
        <!--日志文件路径,“/”与“/”作用相同,到达的目录相同,文件夹不存在则新建 -->
        <!--按文件大小方式输出时在这里指定文件名,并且当天的日志在下一天时在文件名后自动追加当天日期形成新文件。-->
        <!--按照日期形式输出时,直接连接元素 DatePattern 的 value 形成文件路径。此处使用这种方式。 -->
        <!--param 的名称,可以直接查对应的 appender 类的属性名即可,这里要查的就是 RollingFileAppender 类的属性 -->
        <param name="File" value="D:/Log/" />
          <!--是否追加到文件-->
        <param name="AppendToFile" value="true" />
        <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
        <!--使用Unicode编码-->
        <Encoding value="UTF-8" />
        <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->
        <param name="MaxSizeRollBackups" value="10" />
        <!--是否只写到一个文件中-->
        <param name="StaticLogFileName" value="false" />
        <!--按照何种方式产生多个日志文件(日期\[Date\],文件大小\[Size\],混合\[Composite\])-->
        <param name="RollingStyle" value="Composite" />
        <!--按日期产生文件夹和文件名[在日期方式与混合方式下使用]-->
        <!--此处按日期产生文件夹,文件名固定。注意&quot; 的位置-->
        <param name="DatePattern" value="yyyy-MM-dd/&quot;ReflectionLayout.log&quot;"  />
        <!--这是按日期产生文件夹,并在文件名前也加上日期-->
        <param name="DatePattern" value="yyyyMMdd/yyyyMMdd&quot;-TimerServer.log&quot;"  />
        <!--这是先按日期产生文件夹,再形成下一级固定的文件夹 -->
        <param name="DatePattern" value="yyyyMMdd/&quot;TimerServer/TimerServer.log&quot;"  />
        <!--每个文件的大小。只在混合方式与文件大小方式下使用。超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志-->
        <param name="maximumFileSize" value="500KB" />
        <!--计数类型为1,2,3…-->  
        <param name="CountDirection" value="1"/>
        <!--过滤设置,LevelRangeFilter为使用的过滤器。 -->
        <filter type="log4net.Filter.LevelRangeFilter">
            <param name="LevelMin" value="DEBUG" />
            <param name="LevelMax" value="WARN" />
        </filter>
    
        <!--记录的格式。一般用 log4net.Layout.**PatternLayout** 布局-->
        <!--此处用继承了 log4net.Layout.**PatternLayout** 的自定义布局,TGLog.ExpandLayout2 为命名空间。%property{Operator}、%property{Action}是自定义的输出-->
        <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
            <param name="ConversionPattern" value="记录时间:%date 线程ID:[%thread] 日志级别:%-5level 记录类:%logger  操作者ID:%property{Operator} 操作类型:%property{Action}%n  当前机器名:%property%n当前机器名及登录用户:%username %n  记录位置:%location%n 消息描述:%property{Message}%n  异常:%exception%n 消息:%message%newline%n%n" />
        </layout>
    </appender>
    

    注意这些配置属性有些是可选的,如果需要,一定要写正确,否则要么输出的不是自己想要的结果,要么干脆不输出任何信息。

    4.2.2 写入 SQL 数据库

    需要在相应的数据库中准备好一张表,创建语句如下:

    CREATE TABLE [Log] (
        [ID] [int] IDENTITY (1, 1) NOT NULL ,
        [Date] [datetime] NOT NULL ,
        [Thread] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
        [Level] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
        [Logger] [varchar] (200) COLLATE Chinese_PRC_CI_AS NULL ,
        [Operator] [int] NULL ,
        [Message] [text] COLLATE Chinese_PRC_CI_AS NULL ,
        [ActionType] [int] NULL ,
        [Operand] [varchar] (300) COLLATE Chinese_PRC_CI_AS NULL ,
        [IP] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
        [MachineName] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
        [Browser] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
        [Location] [text] COLLATE Chinese_PRC_CI_AS NULL ,
        [Exception] [text] COLLATE Chinese_PRC_CI_AS NULL
    )
    
    <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender,log4net">
        <!--BufferSize为缓冲区大小,只有日志记录超设定值才会一块写入到数据库-->
        <bufferSize value="10" /><!—或写为<param name="BufferSize" value="10" />-->
    
        <!--引用-->
        <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    
        <!--连接数据库字符串-->
        <connectionString value="data source=.;initial catalog=Test;integrated security=false;persist security info=True;User ID=sa;Password=;" />
    
        <!--插入到表Log-->
        <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Operator],[Message],[ActionType],[Operand],[IP],[MachineName],[Browser],[Location],[Exception]) VALUES (@log_date, @thread, @log_level, @logger,@operator, @message,@action_type,@operand,@ip,@machineName,@browser,@location,@exception)" />
    
        <!--日志记录时间,RawTimeStampLayout为默认的时间输出格式 -->
        <parameter>
            <parameterName value="@log_date" />
            <dbType value="DateTime" />
            <layout type="log4net.Layout.RawTimeStampLayout" />
        </parameter>
    
        <!--线程号-->
        <parameter>
            <parameterName value="@thread" />
            <dbType value="String" />
            <!—长度不可以省略,否则不会输出-->
            <size value="100" />
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%thread" />
            </layout>
        </parameter>
    
        <!--日志等级-->
        <parameter>
            <parameterName value="@log_level" />
            <dbType value="String" />
            <size value="100" />
            <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%level" />
            </layout>
        </parameter>
    
        <!--日志记录类名称-->
        <parameter>
            <parameterName value="@logger" />
            <dbType value="String" />
                <size value="200" />
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%logger" />
            </layout>
        </parameter>
        
        <!--操作者。这个是自定义的输出字段,使用重新实现的布局器ReflectionLayout -->
        <parameter>
            <parameterName value="@operator" />
            <!--置为Int32时只有bufferSize的 value<="1"才正确输出,没有找出原因。-->
            <dbType value="Int16" />
            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
                <conversionPattern value="%property{Operator}" />
            </layout>
        </parameter>
    
        <!--操作对象-->
        <parameter>
            <parameterName value="@operand" />
            <dbType value="String" />
            <size value="300" />
            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
                <conversionPattern value="%property{Operand}" />
            </layout>
        </parameter>
    
        <!--IP地址-->
        <parameter>
            <parameterName value="@ip" />
            <dbType value="String" />
            <size value="20" />
            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
                <conversionPattern value="%property{IP}" />
            </layout>
        </parameter>
    
        <!--机器名-->
        <parameter>
            <parameterName value="@machineName" />
            <dbType value="String" />
            <size value="100" />
            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
                <conversionPattern value="%property{MachineName}" />
            </layout>
        </parameter>
    
        <!--浏览器-->
        <parameter>
            <parameterName value="@browser" />
            <dbType value="String" />
            <size value="50" />
            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
                <conversionPattern value="%property{Browser}" />
            </layout>
        </parameter>
    
        <!--日志消息-->
        <parameter>
            <parameterName value="@message" />
            <dbType value="String" />
            <size value="3000" />
            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
                <conversionPattern value="%property{Message}" />
            </layout>
        </parameter>
    
        <!--动作类型-->
        <parameter>
            <parameterName value="@action_type" />
            <dbType value="Int16" />
            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
                <conversionPattern value="%property{ActionType}" />
            </layout>
        </parameter>
    
        <!--记录日志的位置-->
        <parameter>
            <parameterName value="@location" />
            <dbType value="String" />
            <size value="2000" />
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%location" />
            </layout>
        </parameter>
    
        <!--异常信息。ExceptionLayout 为异常输出的默认格式-->
        <parameter>
            <parameterName value="@exception" />
            <dbType value="String" />
            <size value="4000" />
            <layout type="log4net.Layout.ExceptionLayout" />
        </parameter>
    </appender>
    

    注意:

    • 向表中输出的字段不能多于数据表本身字段,而反之则可以,但这些多余字段一定使其可以为空,否则便写不到数据库;
    • 输出字段的类型一定是对应数据表字段数据类型可以隐式转换的,而且长度也不能超过,否则也不能写入;
    • 数据表字段设置尽量可以为空,这样可以避免一条日志记录存在空数据导致后面的日志都记录不了。

    4.3 <logger> 的配置

    在配置文件 <appender> 中的配置好了输出的介质,格式,过滤方式,还要定义日志对象 <logger>

    在框架的体系里,所有的日志对象都是根日志(root logger)的后代。 因此如果一个日志对象没有在配置文件里显式定义,则框架使用根日志中定义的属性。在 <root> 标签里,可以定义 level 级别值和 Appender 的列表。如果没有定义 LEVEL 的值,则缺省为 DEBUG 。可以通过 <appender-ref> 标签定义日志对象使用的Appender对象。<appender-ref> 声明了在其他地方定义的 Appender 对象的一个引用。在一个 logger 对象中的设置会覆盖根日志的设置。而对 Appender 属性来说,子日志对象则会继承父日志对象的 Appender 列表。这种缺省的行为方式也可以通过显式地设定 <logger> 标签的 additivity 属性为 false 而改变。

    <root> 不显式申明时使用默认的配置。我觉得在使用时不定义 <root> ,自定义多个 <logger> ,在程序中记录日志时直接使用 <logger> 的 name 来查找相应的 <logger> ,这样更灵活一些。例如:

    <!--同时写两个文件和数据库-->
    <logger name="ReflectionLayout">
        <level value="DEBUG"/>
        <appender-ref ref="HashtableLayout"/>
        <appender-ref ref="ReflectionLayout"/>
        <appender-ref ref="ADONetAppender"/>
    </logger>
    

    4.4 关联配置文件

    log4net 默认关联的是应用程序的配置文件 App.config ( BS 程序是 Web.config ),可以使用程序集自定义属性来进行设置。下面来介绍一下这个自定义属性:

    log4net.Config.XmlConifguratorAttribute。

    XmlConfiguratorAttribute 有 3 个属性:

    • ConfigFile: 配置文件的名字,文件路径相对于应用程序目录 (AppDomain.CurrentDomain.BaseDirectory)。ConfigFile 属性不能和 ConfigFileExtension 属性一起使用。
    • ConfigFileExtension: 配置文件的扩展名,文件路径相对于应用程序的目录。ConfigFileExtension 属性不能和 ConfigFile 属性一起使用。
    • Watch:如果将 Watch 属性设置为 true ,就会监视配置文件。当配置文件发生变化的时候,就会重新加载。

    如果 ConfigFile 和 ConfigFileExtension 都没有设置,则使用应用程序的配置文件 App.config(Web.config)。

    可以在项目的 AssemblyInfo.cs 文件里添加以下的语句:

     // 监视默认的配置文件,App.exe.config   
    [assembly: log4net.Config.XmlConfigurator(Watch = true)]
    
    // 监视配置文件,App.exe.log4net。
    [assembly: log4net. Config.XmlConfigurator(ConfigFileExtension = "log4net", Watch = true)]
    
    // 使用配置文件log4net.config,不监视改变。
    // 注意log4net.config文件的目录,BS程序在站点目录//下,CS则在应用程序启动目录下。
    // 如调试时在/bin/Debug下,一般将文件属性的文件输出目录调为 // 始终复制即可。
    [assembly: log4net. Config.XmlConfigurator(ConfigFile = "log4net.config")]
    
    // 使用配置文件 log4net.config ,不监视改变
    [assembly: log4net. Config.XmlConfigurator()]
    

    也可以在 Global.asax的Application_Start 里或者是 Program.cs 中的 Main 方法中添加,注意这里一定是绝对路径,如下所示:

    // 这是在BS程序下,使用自定义的配置文件 log4net.xml ,使用 Server.MapPath("~") + // @"/log4net.xml” 来取得路径。/log4net.xml 为相对于站点的路径
    // ConfigureAndWatch() 相当于 Configure(Watch = true)
    log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(Server.MapPath("~") + @"/log4net.xml"));
    
    // 这是在CS程序下,可以用以下方法获得:
    string assemblyFilePath = Assembly.GetExecutingAssembly().Location;
    string assemblyDirPath = Path.GetDirectoryName(assemblyFilePath);
    
    string configFilePath = assemblyDirPath + " [//log4net.xml](file://log4net.xml/)";
    log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(configFilePath));
    

    或直接使用绝对路径:

    // 使用自定义的配置文件,直接绝对路径为:c:/log4net.config
    log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(@"c:/log4net.config"));
    

    5、如何记录日志

    log4net 使用很方便,先申明一个封装类 ILog 的对象,如下:

    log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout");
    

    其中 “ReflectionLayout” 便是我们自定义的日志对象 <logger> 的 name 的值。

    对应 5 个日志输出级别,log 有 5 个方法,每个方法都有两个重载,使用如下:

    try
    {
        log.Debug("这是一个测试!");
    
    }
    catch(Exception ec)
    {
        log.Error("出现错误!", ec);
    }
    

    如果我们需要输出的消息是要区别开来,不按一个字符串全部输出,就需要进行一些扩展了。

    6、log4net 的简单扩展

    6.1 通过重写布局 Layout 输出传入的 message 对象的属性

    6.1.1 重写 Layout 类

    通过继承 log4net.Layout.PatternLayout 类,使用 log4net.Core.LoggingEvent 类的方法得到了要输出的 message 类的名称,然后通过反射得到各个属性的值,使用 PatternLayout 类 AddConverter 方法传入得到的值。这里注意要引用用到的类的命名空间。

    代码见附注 8.2 。

    6.1.2 配置相应的配置文件

    配置文件其他地方不用改动,只是需要改动 <appender> 中的 <layout> 。例如:

    <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
        <param name="ConversionPattern" value="记录时间:%date %newline操作者ID:%property{Operator} %newline操作类型:%property{Action}%n %newline消息描述:%property{Message}%n %newline异常:%exception%n " />
    </layout>
    

    其中 <layout> 的 type 由原来的 log4net.Layout.PatternLayout 换为自定义的 TGLog.ExpandLayout2.ReflectionLayout(TGLog.ExpandLayout2 为命名空间)。%property{Operator} 输出的即为 message 类对象的属性 Operator 的值。数据库配置同样,相应的字段如果是自定义的,则输出选用自定义的 <layout> 。例:

    <!--动作类型-->
    <parameter>
        <parameterName value="@action_type" />
        <dbType value="Int16" />
        <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
            <conversionPattern value="%property{ActionType}" />
        </layout>
    </parameter>
    

    6.1.3 程序中如何使用

    和一般使用方法基本相同,只是传入的参数是一个自定义的类,类的属性和配置文件中 <layout> 所有的 %property{属性} 是一致的,即 %property{属性} 在输出的时候就查找传入 message 类中有无对应的属性,如果有就输出值,没有则输出 null 。例:

    log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout");
    
    try
    {
        log.Debug(new LogMessage(1, "操作对象:0", (int)TGLog.ActionType.Other, "这是四个参数测试"));
    }
    catch(Exception ex)
    {
        log.Error(new LogMessage(1, "操作对象:0", (int)TGLog.ActionType.Other, "这是全部参数测试", "192.168.1.1", "MyComputer", "Maxthon(MyIE2)Fans"), ex);
    }
    

    LogMessage 的全部属性的构造方法如下:

    public LogMessage(int operatorID, string operand, int ActionType, string message, string ip, string machineName, string browser)
    {
      this.ActionType = ActionType;
      this.Operator = operatorID;
      this.Message = message;
      this.Operand = operand;
      this.IP = ip;
      this.Browser = browser;
      this.MachineName = machineName;
    }
    

    6.2 通过重新实现 ILog 接口来增加输入的参数

    6.2.1重写 LogImpl,LogManager 类及实现 ILog 接口

    这种方式是通过构造一个名为 IMyLog 接口,是继承 Ilog 接口而来,然后分别在 MyLogImplMyLogManager 重新实现 IMyLog 接口,增加了每种方法的参数。MyLogImplMyLogManager 分别继承 LogImplLogManager 而来。

    代码分别见 8.3、8.4、8.5 。

    6.2.2配置相应的配置文件

    配置文件其他地方不用改动,只是需要改动 中的 元素 name 为ConversionPattern 的 value 中输出格式。例如:

    <layout type=" log4net.Layout.**PatternLayout** ">
        <param name="ConversionPattern" value="记录时间:%date  操作者ID:%property{Operator}  操作类型:%property{Action}%n  消息描述:%property{Message}%n  异常:%exception%n "/>
    </layout>
    

    %property{参数} 中的参数在 MyLogImpl 类中定义,如语句:

    loggingEvent.Properties["Operator"] = operatorID;
    

    就定义了 Operator 输出参数,即 %property{Operator} 输出的即为 IMyLog 中的参数 operatorID 的值。

    数据库配置同样。例:

    <!--动作类型-->
    <parameter>
      <parameterName value="@action_type" />
      <dbType value="Int16" />
      <layout type=" log4net.Layout.**PatternLayout** ">
        <conversionPattern value="%property{ActionType}" />
      </layout>
    </parameter>
    

    6.2.3 程序中如何使用

    先引用 IMyLog ,MyLogManager 所在的命名空间,创建一个 IMyLog 对象,myLog 的 5 个方法,每个方法都有四个重载,增加了多参数的重载。例:

    IMyLog myLog = MyLogManager.GetLogger("ExpandILog");
    
    try
    {
        myLog.Debug("这是一个参数重载测试!");          
    }
    catch(Exception ex)
    {
        log.Error(1, "操作对象:0", (int)TGLog.ActionType.Other, "这是全部参数测试", "192.168.1.1", "MyComputer", "Maxthon(MyIE2)Fans", ex);
    }
    

    7、总结

    log4net 功能很多,这里只是对已经尝试用过的功能总结一下,普通写日志已经足够。需要注意的是:

    1. log4net本身也有一些缺陷,比如一个记录引起了 log4net 本身的异常,就会使后面的日志无法记录下来,尤其是在写入数据库时。例如使用 6.1 扩展后,int 型的属性在 <appender> 的元素 <bufferSize> 设置不为 1 时,<dbType value="Int32"/> 时,就不能输出到数据库,而 <dbType value="Int16"/> 则没任何问题。
    2. log4net 本身出现了异常,比如配置文件出现错误,有些日志输出方式会记录下这些异常,例如应用程序控制台;有些则不会输出这些错误,如数据库与文件。
    3. 扩展时也会留下一些问题。例如在使用 6.1 扩展输出字段时就会出现,在 log.debug(object message) 中,如果 message 是一个自定义的类,属性与配置文件中输出设置也一致,构造函数时也只构造一个参数的实例,写文件与写数据库都成功,而将 message 按没有扩展的方式直接传入一个字符串,即 log.debug(“信息内容”) 使用则只能写入文件,而数据库则没写入。自定义的 Layout 就是继承默认的 PatternLayout ,本来不应该出错,但出现了问题。原因分析是自定义的 message 类有类型为 int 的属性,作为一个对象传入时在默认值 0,而直接使用字符串则 int 型的字段得不到默认值,引发异常。所以建议在有扩展存在时,最好多设几个 <logger> ,区分清楚,按照统一的形式记录日志,不要混合使用。
    4. 配置文件的设置一定要准确,在一点不正确就会导致日志不能正常输出,所以在配置时先从最简单的开始,同时输出方式选择一种能输出 log4net 本身异常的方式,成功后一点一点加在新配置,这样出错了也容易找到那个地方配置有问题。
    5. log4net 扩展性很强,几乎所有的组件都可以重写,在配置文件中配置好就可以使用。

    8、附注:

    8.1 PatterLayout 格式化字符表

    见转载原文:https://www.cnblogs.com/lzrabbit/archive/2012/03/23/2413180.html

    8.2 Layout 类代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using log4net.Layout;
    using log4net.Layout.Pattern;
    using System.Reflection;
    using System.Collections;
    using FastReflectionLib;
    
    namespace TGLog.ExpandLayout2
    {
        public class ReflectionLayout : PatternLayout
        {
            public ReflectionLayout()
            {
                this.AddConverter("property", typeof(ReflectionPatternConverter));
            }
        }
    
        public class ReflectionPatternConverter : PatternLayoutConverter
        {
            protected override void Convert(System.IO.TextWriter writer, log4net.Core.LoggingEvent loggingEvent)
            {
                if (Option != null)
                {
                    // 写入指定键的值
                    WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent));
                }
                else
                {
                    // 写入所有关键值对
                    WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties());
                }
            }
    
            /// <summary>
            /// 通过反射获取传入的日志对象的某个属性的值
            /// </summary>
            /// <param name="property"></param>
            /// <returns></returns>
            private object LookupProperty(string property, log4net.Core.LoggingEvent loggingEvent)
            {
                object propertyValue = string.Empty;
                PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property);
    
                if (propertyInfo != null)
                {
                    propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null);
                }
    
                return propertyValue;
            }
        }
    }
    

    8.3 MyLogImpl 类代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using log4net.Core;
    
    namespace TGLog.ExpandILog
    {
        public class MyLogImpl : LogImpl, IMyLog
        {
            /// <summary>
            /// The fully qualified name of this declaring type not the type of any subclass.
            /// </summary>
            private readonly static Type ThisDeclaringType = typeof(MyLogImpl);
    
            public MyLogImpl(ILogger logger): base(logger)
            {
            }
    
            #region Implementation of IMyLog
    
            public void Debug(int operatorID, string operand, int actionType, object message, string ip, string browser, string machineName)
            {
                Debug(operatorID, operand, actionType, message, ip, browser, machineName, null);
            }
    
            public void Debug(int operatorID, string operand, int actionType, object message, string ip, string browser, string machineName, System.Exception t)
            {
                if (this.IsDebugEnabled)
                {
                    LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Info, message, t);
    
                    loggingEvent.Properties["Operator"] = operatorID;
                    loggingEvent.Properties["Operand"] = operand;
                    loggingEvent.Properties["ActionType"] = actionType;
                    loggingEvent.Properties["IP"] = ip;
                    loggingEvent.Properties["Browser"] = browser;
                    loggingEvent.Properties["MachineName"] = machineName;
    
                    Logger.Log(loggingEvent);
                }
            }
    
            public void Info(int operatorID, string operand, int actionType, object message, string ip, string browser, string machineName)
            {
                Info(operatorID, operand, actionType, message, ip, browser, machineName, null);
            }
    
            public void Info(int operatorID, string operand, int actionType, object message, string ip, string browser, string machineName, System.Exception t)
            {
                if (this.IsInfoEnabled)
                {
                    LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Info, message, t);
    
                    loggingEvent.Properties["Operator"] = operatorID;
                    loggingEvent.Properties["Operand"] = operand;
                    loggingEvent.Properties["ActionType"] = actionType;
                    loggingEvent.Properties["IP"] = ip;
                    loggingEvent.Properties["Browser"] = browser;
                    loggingEvent.Properties["MachineName"] = machineName;
    
                    Logger.Log(loggingEvent);
                }
            }
    
            public void Warn(int operatorID, string operand, int actionType, object message, string ip, string browser, string machineName)
            {
                Warn(operatorID, operand, actionType, message, ip, browser, machineName, null);
            }
    
            public void Warn(int operatorID, string operand, int actionType, object message, string ip, string browser, string machineName, System.Exception t)
            {
                if (this.IsWarnEnabled)
                {
                    LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Info, message, t);
    
                    loggingEvent.Properties["Operator"] = operatorID;
                    loggingEvent.Properties["Operand"] = operand;
                    loggingEvent.Properties["ActionType"] = actionType;
                    loggingEvent.Properties["IP"] = ip;
                    loggingEvent.Properties["Browser"] = browser;
                    loggingEvent.Properties["MachineName"] = machineName;
    
                    Logger.Log(loggingEvent);
                }
            }
    
            public void Error(int operatorID, string operand, int actionType, object message, string ip, string browser, string machineName)
            {
                Error(operatorID, operand, actionType, message, ip, browser, machineName, null);
            }
    
            public void Error(int operatorID, string operand, int actionType, object message, string ip, string browser, string machineName, System.Exception t)
            {
                if (this.IsErrorEnabled)
                {
                    LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Info, message, t);
    
                    loggingEvent.Properties["Operator"] = operatorID;
                    loggingEvent.Properties["Operand"] = operand;
                    loggingEvent.Properties["ActionType"] = actionType;
                    loggingEvent.Properties["IP"] = ip;
                    loggingEvent.Properties["Browser"] = browser;
                    loggingEvent.Properties["MachineName"] = machineName;
    
                    Logger.Log(loggingEvent);
                }
            }
    
            public void Fatal(int operatorID, string operand, int actionType, object message, string ip, string browser, string machineName)
            {
                Fatal(operatorID, operand, actionType, message, ip, browser, machineName, null);
            }
    
            public void Fatal(int operatorID, string operand, int actionType, object message, string ip, string browser, string machineName, System.Exception t)
            {
                if (this.IsFatalEnabled)
                {
                    LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Info, message, t);
    
                    loggingEvent.Properties["Operator"] = operatorID;
                    loggingEvent.Properties["Operand"] = operand;
                    loggingEvent.Properties["ActionType"] = actionType;
                    loggingEvent.Properties["IP"] = ip;
                    loggingEvent.Properties["Browser"] = browser;
                    loggingEvent.Properties["MachineName"] = machineName;
    
                    Logger.Log(loggingEvent);
                }
            }
    
            #endregion Implementation of IMyLog
    
        }
    }
    

    8.4 MyLogManager 类代码

    #region Copyright & License
    
    //
    // Copyright 2001-2005 The Apache Software Foundation
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    // http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    //
    
    #endregion
    
    using System;
    using System.Reflection;
    using System.Collections;
    using log4net;
    using log4net.Core;
    using log4net.Repository;
    using log4net.Repository.Hierarchy;
    
    namespace TGLog.ExpandILog
    {
        public class MyLogManager
        {
            #region Static Member Variables
    
            /// <summary>
            /// The wrapper map to use to hold the <see cref="EventIDLogImpl"/> objects
            /// </summary>
            private static readonly WrapperMap s_wrapperMap = new WrapperMap(newWrapperCreationHandler(WrapperCreationHandler));
    
            #endregion
     
            #region Constructor
     
            /// <summary>
            /// Private constructor to prevent object creation
            /// </summary>
            private MyLogManager() { }
    
            #endregion
     
            #region Type Specific Manager Methods
     
            /// <summary>
            /// Returns the named logger if it exists
            /// </summary>
            /// <remarks>
            /// <para>If the named logger exists (in the default hierarchy) then it
            /// returns a reference to the logger, otherwise it returns
            /// <c>null</c>.</para>
            /// </remarks>
            /// <param name="name">The fully qualified logger name to look for</param>
            /// <returns>The logger found, or null</returns>
            public static IMyLog Exists(string name)
            {
                return Exists(Assembly.GetCallingAssembly(), name);
            }
     
            /// <summary>
            /// Returns the named logger if it exists
            /// </summary>
            /// <remarks>
            /// <para>If the named logger exists (in the specified domain) then it
            /// returns a reference to the logger, otherwise it returns
            /// <c>null</c>.</para>
            /// </remarks>
            /// <param name="domain">the domain to lookup in</param>
            /// <param name="name">The fully qualified logger name to look for</param>
            /// <returns>The logger found, or null</returns>
            public static IMyLog Exists(string domain, string name)
            {
                return WrapLogger(LoggerManager.Exists(domain, name));
            }
    
            /// <summary>
            /// Returns the named logger if it exists
            /// </summary>
            /// <remarks>
            /// <para>If the named logger exists (in the specified assembly's domain) then it
            /// returns a reference to the logger, otherwise it returns
            /// <c>null</c>.</para>
            /// </remarks>
            /// <param name="assembly">the assembly to use to lookup the domain</param>
            /// <param name="name">The fully qualified logger name to look for</param>
            /// <returns>The logger found, or null</returns>
            public static IMyLog Exists(Assembly assembly, string name)
            {
                return WrapLogger(LoggerManager.Exists(assembly, name));
            }
    
            /// <summary>
            /// Returns all the currently defined loggers in the default domain.
            /// </summary>
            /// <remarks>
            /// <para>The root logger is <b>not</b> included in the returned array.</para>
            /// </remarks>
            /// <returns>All the defined loggers</returns>
            public static IMyLog[] GetCurrentLoggers()
            {
                return GetCurrentLoggers(Assembly.GetCallingAssembly());
            }
    
            /// <summary>
            /// Returns all the currently defined loggers in the specified domain.
            /// </summary>
            /// <param name="domain">the domain to lookup in</param>
            /// <remarks>
            /// The root logger is <b>not</b> included in the returned array.
            /// </remarks>
            /// <returns>All the defined loggers</returns>
            public static IMyLog[] GetCurrentLoggers(string domain)
            {
                return WrapLoggers(LoggerManager.GetCurrentLoggers(domain));
            }
    
            /// <summary>
            /// Returns all the currently defined loggers in the specified assembly's domain.
            /// </summary>
            /// <param name="assembly">the assembly to use to lookup the domain</param>
            /// <remarks>
            /// The root logger is <b>not</b> included in the returned array.
            /// </remarks>
            /// <returns>All the defined loggers</returns>
            public static IMyLog[] GetCurrentLoggers(Assembly assembly)
            {
                return WrapLoggers(LoggerManager.GetCurrentLoggers(assembly));
            }
    
            /// <summary>
            /// Retrieve or create a named logger.
            /// </summary>
            /// <remarks>
            /// <para>Retrieve a logger named as the <paramref name="name"/>
            /// parameter. If the named logger already exists, then the
            /// existing instance will be returned. Otherwise, a new instance is
            /// created.</para>
            ///
            /// <para>By default, loggers do not have a set level but inherit
            /// it from the hierarchy. This is one of the central features of
            /// log4net.</para>
            /// </remarks>
            /// <param name="name">The name of the logger to retrieve.</param>
            /// <returns>the logger with the name specified</returns>
            public static IMyLog GetLogger(string name)
            {
                return GetLogger(Assembly.GetCallingAssembly(), name);
            }
    
            /// <summary>
            /// Retrieve or create a named logger.
            /// </summary>
            /// <remarks>
            /// <para>Retrieve a logger named as the <paramref name="name"/>
            /// parameter. If the named logger already exists, then the
            /// existing instance will be returned. Otherwise, a new instance is
            /// created.</para>
            ///
            /// <para>By default, loggers do not have a set level but inherit
            /// it from the hierarchy. This is one of the central features of
            /// log4net.</para>
            /// </remarks>
            /// <param name="domain">the domain to lookup in</param>
            /// <param name="name">The name of the logger to retrieve.</param>
            /// <returns>the logger with the name specified</returns>
            public static IMyLog GetLogger(string domain, string name)
            {
                return WrapLogger(LoggerManager.GetLogger(domain, name));
            }
    
            /// <summary>
            /// Retrieve or create a named logger.
            /// </summary>
            /// <remarks>
            /// <para>Retrieve a logger named as the <paramref name="name"/>
            /// parameter. If the named logger already exists, then the
            /// existing instance will be returned. Otherwise, a new instance is
            /// created.</para>
            ///
            /// <para>By default, loggers do not have a set level but inherit
            /// it from the hierarchy. This is one of the central features of
            /// log4net.</para>
            /// </remarks>
            /// <param name="assembly">the assembly to use to lookup the domain</param>
            /// <param name="name">The name of the logger to retrieve.</param>
            /// <returns>the logger with the name specified</returns>
            public static IMyLog GetLogger(Assembly assembly, string name)
            {
                return WrapLogger(LoggerManager.GetLogger(assembly, name));
            }
    
            /// <summary>
            /// Shorthand for <see cref="LogManager.GetLogger(string)"/>.
            /// </summary>
            /// <remarks>
            /// Get the logger for the fully qualified name of the type specified.
            /// </remarks>
            /// <param name="type">The full name of <paramref name="type"/> will
            /// be used as the name of the logger to retrieve.</param>
            /// <returns>the logger with the name specified</returns>
            public static IMyLog GetLogger(Type type)
            {
                return GetLogger(Assembly.GetCallingAssembly(), type.FullName);
            }
     
            /// <summary>
            /// Shorthand for <see cref="LogManager.GetLogger(string)"/>.
            /// </summary>
            /// <remarks>
            /// Get the logger for the fully qualified name of the type specified.
            /// </remarks>
            /// <param name="domain">the domain to lookup in</param>
            /// <param name="type">The full name of <paramref name="type"/> will
            /// be used as the name of the logger to retrieve.</param>
            /// <returns>the logger with the name specified</returns>
            public static IMyLog GetLogger(string domain, Type type)
            {
                return WrapLogger(LoggerManager.GetLogger(domain, type));
            }
    
            /// <summary>
            /// Shorthand for <see cref="LogManager.GetLogger(string)"/>.
            /// </summary>
            /// <remarks>
            /// Get the logger for the fully qualified name of the type specified.
            /// </remarks>
            /// <param name="assembly">the assembly to use to lookup the domain</param>
            /// <param name="type">The full name of <paramref name="type"/> will
            /// be used as the name of the logger to retrieve.</param>
            /// <returns>the logger with the name specified</returns>
            public static IMyLog GetLogger(Assembly assembly, Type type)
            {
                return WrapLogger(LoggerManager.GetLogger(assembly, type));
            }
    
            #endregion
     
            #region Extension Handlers
    
            /// <summary>
            /// Lookup the wrapper object for the logger specified
            /// </summary>
            /// <param name="logger">the logger to get the wrapper for</param>
            /// <returns>the wrapper for the logger specified</returns>
            private static IMyLog WrapLogger(ILogger logger)
            {
                return (IMyLog)s_wrapperMap.GetWrapper(logger);
            }
     
            /// <summary>
            /// Lookup the wrapper objects for the loggers specified
            /// </summary>
            /// <param name="loggers">the loggers to get the wrappers for</param>
            /// <returns>Lookup the wrapper objects for the loggers specified</returns>
            private static IMyLog[] WrapLoggers(ILogger[] loggers)
            {
                IMyLog[] results = new IMyLog[loggers.Length];
                for (int i = 0; i < loggers.Length; i++)
                {
                    results[i] = WrapLogger(loggers[i]);
                
                return results;
            }
    
            /// <summary>
            /// Method to create the <see cref="ILoggerWrapper"/> objects used by
            /// this manager.
            /// </summary>
            /// <param name="logger">The logger to wrap</param>
            /// <returns>The wrapper for the logger specified</returns>
            private static ILoggerWrapper WrapperCreationHandler(ILogger logger)
            {
                return new MyLogImpl(logger);
            }
    
            #endregion
        }
    }
    ``
    
    ### 8.5 IMyLog 类代码
    
    ```csharp
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using log4net;
    
    namespace TGLog.ExpandILog
    {
        public interface IMyLog : ILog
        {
            void Debug(int operatorID, string operand, int actionType, object message,
    string ip, string browser, string machineName);
    
            void Debug(int operatorID, string operand, int actionType,object message,
    string ip, string browser, string machineName, Exception t);
    
            void Info(int operatorID, string operand, int actionType, object message,
    string ip, string browser, string machineName);
    
            void Info(int operatorID, string operand, int actionType, object message,
    string ip, string browser, string machineName, Exception t);
    
            void Warn(int operatorID, string operand, int actionType, object message,
    string ip, string browser, string machineName);
    
            void Warn(int operatorID, string operand, int actionType, object message,
     string ip, string browser, string machineName, Exception t);
    
            void Error(int operatorID, string operand, int actionType, object message,
    string ip, string browser, string machineName);
    
            void Error(int operatorID, string operand, int actionType, object message,
    string ip, string browser, string machineName, Exception t);
    
            void Fatal(int operatorID, string operand, int actionType, object message,
    string ip, string browser, string machineName);
    
            void Fatal(int operatorID, string operand, int actionType, object message,
    string ip, string browser, string machineName, Exception t);
        }
    }
    

    8.6 附件

    使用 log4net 记录日志

    8.7 参考

    1. http://peibing211.blog.163.com/blog/static/37116360200992811595469/
    2. http://www.cnblogs.com/qiangzi/archive/2009/09/10/1541023.html
    3. http://blog.chinaunix.net/u/23701/showart_1414206.html
    4. http://itrust.cnblogs.com/archive/2005/01/25/97225.html
    5. http://www.cnitblog.com/seeyeah/archive/2009/09/20/61491.aspx
    6. http://www.cnblogs.com/zhmore/archive/2009/03/19/1416707.html
    7. http://blog.shinylife.net/blog/article.asp?id=948
    8. http://www.cnblogs.com/manhoo/archive/2009/06/25/1511066.html
    展开全文
  • winform+log4net简单示例

    热门讨论 2020-07-30 23:30:40
    winform结合log4net,把异常信息记录到一个txt文本的简单例子,适合管理系统之类的应用。要知道错误的可重现性对于维护人员来说是很重要的^-^。 使用log4net要注意以下几点: 1)在app.config中写log4net的配置数据 2...
  • 非常完善的Log4net详细说明

    万次阅读 多人点赞 2018-03-14 17:28:33
    1、概述log4net是.Net下一个非常优秀的开源日志记录组件。log4net记录日志的功能非常强大。它可以将日志分不同的等级,以不同的格式,输出到不同的媒介。本文主要是介绍如何在Visual Studio2008中使用log4net快速...

    1、概述

    log4net是.Net下一个非常优秀的开源日志记录组件。log4net记录日志的功能非常强大。它可以将日志分不同的等级,以不同的格式,输出到不同的媒介。本文主要是介绍如何在Visual Studio2008中使用log4net快速创建系统日志,如何扩展以输出自定义字段。

    2、一个简单的使用实例

    第一步:在项目中添加对log4net.dll的引用,这里引用版本是1.2.10.0。

    第二步:程序启动时读取log4net的配置文件。

    如果是CS程序,在根目录的Program.cs中的Main方法中添加:

    log4net.Config.XmlConfigurator.Configure();

    如果是BS程序,在根目录的Global.asax.cs(没有新建一个)中的Application_Start方法中添加:

    log4net.Config.XmlConfigurator.Configure();

    无论BS还是CS程序都可直接在项目的AssemblyInfo.cs文件里添加以下的语句:

    [assembly: log4net.Config .XmlConfigurator()]

    也可以使用自定义的配置文件,具体请参见4.4 关联配置文件。

    第三步:修改配置文件。如果是CS程序,则在默认的App.config文件(没有新建一个)中添加内容;如果是BS程序,则添加到Web.config文件中,添加内容一样,这里不再列出。

    App.config文件添加内容如下:

    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

      <configSections>

    <section name="log4net"

    type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

      </configSections>

     

      <log4net>

        <root>

          <level value="WARN" />

          <appender-ref ref="LogFileAppender" />

          <appender-ref ref="ConsoleAppender" />

        </root>

     

        <logger name="testApp.Logging">

          <level value="DEBUG"/>

        </logger>

     

        <appender name="LogFileAppender" type="log4net.Appender.FileAppender" >

          <param name="File" value="log-file.txt" />

          <param name="AppendToFile" value="true" />

     

          <layout type="log4net.Layout.PatternLayout">

            <param name="Header" value="[Header] "/>

            <param name="Footer" value="[Footer] "/>

            <param name="ConversionPattern" value="%d [%t] %-5p %c [%x]  - %m%n" />

          </layout>

     

          <filter type="log4net.Filter.LevelRangeFilter">

            <param name="LevelMin" value="DEBUG" />

            <param name="LevelMax" value="WARN" />

          </filter>

        </appender>

     

        <appender name="ConsoleAppender"  type="log4net.Appender.ConsoleAppender" >

          <layout type="log4net.Layout.PatternLayout">

            <param name="ConversionPattern"  value="%d [%t] %-5p %c [%x] - %m%n" />

          </layout>

        </appender>

     

      </log4net>

    </configuration>

    第四步:在程序使用。

    log4net.ILog log = log4net.LogManager.GetLogger("testApp.Logging");//获取一个日志记录器

    log.Info(DateTime.Now.ToString() + ": login success");//写入一条新log

    这样就将信息同时输出到控制台和写入到文件名为“log-file.txt”的文件中,其中“log-file.txt”文件的路径是当前程序运行所在目录;也可以定义为绝对路径,配置如:

    <param name="File" value="C:/log-file.txt" />就写入C盘根目录下log-file.txt文件中,具体使用技巧参见4.2.1。

     

    本例的实现请参见8.6附件。

    3、Log4net的主要组成部分

    3.1 Appenders

    Appenders用来定义日志的输出方式,即日志要写到那种介质上去。较常用的Log4net已经实现好了,直接在配置文件中调用即可,可参见上面配置文件例子;当然也可以自己写一个,需要从log4net.Appender.AppenderSkeleton类继承。它还可以通过配置Filters和Layout来实现日志的过滤和输出格式。

    已经实现的输出方式有:

    AdoNetAppender 将日志记录到数据库中。可以采用SQL和存储过程两种方式。

    AnsiColorTerminalAppender 将日志高亮输出到ANSI终端。

    AspNetTraceAppender  能用asp.net中Trace的方式查看记录的日志。

    BufferingForwardingAppender 在输出到子Appenders之前先缓存日志事件。

    ConsoleAppender 将日志输出到应用程序控制台。

    EventLogAppender 将日志写到Windows Event Log。

    FileAppender 将日志输出到文件。

    ForwardingAppender 发送日志事件到子Appenders。

    LocalSyslogAppender 将日志写到local syslog service (仅用于UNIX环境下)。

    MemoryAppender 将日志存到内存缓冲区。

    NetSendAppender 将日志输出到Windows Messenger service.这些日志信息将在用户终端的对话框中显示。

    OutputDebugStringAppender 将日志输出到Debuger,如果程序没有Debuger,就输出到系统Debuger。如果系统Debuger也不可用,将忽略消息。

    RemoteSyslogAppender 通过UDP网络协议将日志写到Remote syslog service。

    RemotingAppender 通过.NET Remoting将日志写到远程接收端。

    RollingFileAppender 将日志以回滚文件的形式写到文件中。

    SmtpAppender 将日志写到邮件中。

    SmtpPickupDirAppender 将消息以文件的方式放入一个目录中,像IIS SMTP agent这样的SMTP代理就可以阅读或发送它们。

    TelnetAppender 客户端通过Telnet来接受日志事件。

    TraceAppender 将日志写到.NET trace 系统。

    UdpAppender 将日志以无连接UDP数据报的形式送到远程宿主或用UdpClient的形式广播。

    3.2 Filters

    使用过滤器可以过滤掉Appender输出的内容。过滤器通常有以下几种:

    DenyAllFilter 阻止所有的日志事件被记录

    LevelMatchFilter 只有指定等级的日志事件才被记录

    LevelRangeFilter 日志等级在指定范围内的事件才被记录

    LoggerMatchFilter 与Logger名称匹配,才记录

    PropertyFilter 消息匹配指定的属性值时才被记录

    StringMathFilter 消息匹配指定的字符串才被记录

    3.3 Layouts

    Layout用于控制Appender的输出格式,可以是线性的也可以是XML。

    一个Appender只能有一个Layout。

    最常用的Layout应该是经典格式的PatternLayout,其次是SimpleLayout,RawTimeStampLayout和ExceptionLayout。然后还有IRawLayout,XMLLayout等几个,使用较少。Layout可以自己实现,需要从log4net.Layout.LayoutSkeleton类继承,来输出一些特殊需要的格式,在后面扩展时就重新实现了一个Layout。

    SimpleLayout简单输出格式,只输出日志级别与消息内容。

    RawTimeStampLayout 用来格式化时间,在向数据库输出时会用到。

    样式如“yyyy-MM-dd HH:mm:ss“

    ExceptionLayout需要给Logger的方法传入Exception对象作为参数才起作用,否则就什么也不输出。输出的时候会包含Message和Trace。

    PatterLayout使用最多的一个Layout,能输出的信息很多,使用方式可参见上面例子中的配置文件。PatterLayout的格式化字符串见文后附注8.1。

    3.4 Loggers

    Logger是直接和应用程序交互的组件。Logger只是产生日志,然后由它引用的Appender记录到指定的媒介,并由Layout控制输出格式。

    Logger提供了多种方式来记录一个日志消息,也可以有多个Logger同时存在。每个实例化的Logger对象对被log4net作为命名实体(Named Entity)来维护。log4net使用继承体系,也就是说假如存在两个Logger,名字分别为a.b.c和a.b。那么a.b就是a.b.c的祖先。每个Logger都继承了它祖先的属性。所有的Logger都从Root继承,Root本身也是一个Logger。

    日志的等级,它们由高到底分别为:

    OFF > FATAL > ERROR > WARN > INFO > DEBUG  > ALL 

    高于等级设定值方法(如何设置参见“配置文件详解”)都能写入日志, Off所有的写入方法都不写到日志里,ALL则相反。例如当我们设成Info时,logger.Debug就会被忽略而不写入文件,但是FATAL,ERROR,WARN,INFO会被写入,因为他们等级高于INFO。

    在具体写日志时,一般可以这样理解日志等级:

    FATAL(致命错误):记录系统中出现的能使用系统完全失去功能,服务停止,系统崩溃等使系统无法继续运行下去的错误。例如,数据库无法连接,系统出现死循环。

    ERROR(一般错误):记录系统中出现的导致系统不稳定,部分功能出现混乱或部分功能失效一类的错误。例如,数据字段为空,数据操作不可完成,操作出现异常等。

    WARN(警告):记录系统中不影响系统继续运行,但不符合系统运行正常条件,有可能引起系统错误的信息。例如,记录内容为空,数据内容不正确等。

    INFO(一般信息):记录系统运行中应该让用户知道的基本信息。例如,服务开始运行,功能已经开户等。

    DEBUG (调试信息):记录系统用于调试的一切信息,内容或者是一些关键数据内容的输出。

    Logger实现的ILog接口,ILog定义了5个方法(Debug,Inof,Warn,Error,Fatal)分别对不同的日志等级记录日志。这5个方法还有5个重载。以Debug为例说明一下,其它的和它差不多。

    ILog中对Debug方法的定义如下:

    void Debug(object message);

    void Debug(object message, Exception ex);

    还有一个布尔属性:

    bool IsDebugEnabled { get; }

    如果使用Debug(object message, Exception ex),则无论Layout中是否定义了%exception,默认配置下日志都会输出Exception。包括Exception的Message和Trace。如果使用Debug(object message),则日志是不会输出Exception。

    最后还要说一个LogManager类,它用来管理所有的Logger。它的GetLogger静态方法,可以获得配置文件中相应的Logger:

    log4net.ILog log = log4net.LogManager.GetLogger("logger-name");

    3.5 Object Renders

    它将告诉logger如何把一个对象转化为一个字符串记录到日志里。(ILog中定义的接口接收的参数是Object,而不是String。)

    例如你想把Orange对象记录到日志中,但此时logger只会调用Orange默认的ToString方法而已。所以要定义一个OrangeRender类实现log4net.ObjectRender.IObjectRender接口,然后注册它(我们在本文中的扩展不使用这种方法,而是直接实现一个自定义的Layout)。这时logger就会知道如何把Orange记录到日志中了。

    3.6 Repository

    Repository主要用于日志对象组织结构的维护。

    4、配置文件详解

    4.1 配置文件构成

    主要有两大部分,一是申明一个名为“log4net“的自定义配置节,如下所示:

      <configSections>

    <section name="log4net"

    type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

      </configSections>

    二是<log4net>节的具体配置,这是下面要重点说明的。

    4.1.1<log4net>

    所有的配置都要在<log4net>元素里定义。

    支持的属性:

    debug

    可选,取值是true或false,默认是false。设置为true,开启log4net的内部调试。

    update

    可选,取值是Merge(合并)或Overwrite(覆盖),默认值是Merge。设置为Overwrite,在提交配置的时候会重置已经配置过的库。

    threshold

    可选,取值是repository(库)中注册的level,默认值是ALL。

    支持的子元素:

    appender

    0或多个

    logger

    0或多个

    renderer

    0或多个

    root

    最多一个

    param

    0或多个

     

    4.1.2 <root>

    实际上就是一个根logger,所有其它logger都默认继承它,如果配置文件里没有显式定义,则框架使用根日志中定义的属性。root元素没有属性。

    支持的子元素:

    appender-ref

    0个或多个,要引用的appender的名字。

    level

    最多一个。 只有在这个级别或之上的事件才会被记录。

    param

    0个或多个, 设置一些参数。

     

    4.1.3 <logger>

    支持的属性:

    name

    必须的,logger的名称

    additivity

    可选,取值是true或false,默认值是true。设置为false时将阻止父logger中的appender。

    支持的子元素:

    appender-ref

    0个或多个,要引用的appender的名字。

    level

    最多一个。 只有在这个级别或之上的事件才会被记录。

    param

    0个或多个, 设置一些参数。

     

    4.1.4 <appender>

    定义日志的输出方式,只能作为 log4net 的子元素。name属性必须唯一,type属性必须指定。

    支持的属性:

    name

    必须的,Appender对象的名称

    type

    必须的,Appender对象的输出类型

    支持的子元素:

    appender-ref

    0个或多个,允许此appender引用其他appender,并不是所以appender类型都支持。

    filter

    0个或多个,定义此app使用的过滤器。

    layout

    最多一个。定义appender使用的输出格式。

    param

    0个或多个, 设置Appender类中对应的属性的值。

    实际上<appender>所能包含的子元素远不止上面4个。

     

    4.1.5 <layout>

    布局,只能作为<appender>的子元素。

    支持的属性:

    type

    必须的,Layout的类型

    支持的子元素:

    param

    0个或多个, 设置一些参数。

     

    4.1.6 <filter>

    过滤器,只能作为<appender>的子元素。

    支持的属性:

    type

    必须的,Filter的类型

    支持的子元素:

    param

    0个或多个, 设置一些参数。

     

    4.1.7 <param>

    <param>元素可以是任何元素的子元素。

    支持的属性:

    name

    必须的,取值是父对象的参数名。

    value

    可选的,value和type中,必须有一个属性被指定。value是一个能被转化为参数值的字符串。

    type

    可选的,value和type中,必须有一个属性被指定。type是一个类型名,如果type不是在log4net程序集中定义的,就需要使用全名。

    支持的子元素:

    param

    0个或多个, 设置一些参数。

     

    4.2 <appender>配置

       <appender>在配置文件中至少有一个,也可以有多个,有些<appender>类型还可以引用其他<appender>类型,具体参数可参见上表。

    下面只对写入回滚文件与输出到数据库(这里使用SQL数据库)配置体会说一下,其他配置可参考官方网站:http://logging.apache.org/log4net/release/config-examples.html

    4.2.1写入回滚文件

        <appender name="ReflectionLayout" type="log4net.Appender.RollingFileAppender,log4net">

    <!--日志文件路径,“/”与“/”作用相同,到达的目录相同,文件夹不存在则新建 -->

    <!--按文件大小方式输出时在这里指定文件名,并且当天的日志在下一天时在文件名后自动追加当天日期形成新文件。-->

    <!—按照日期形式输出时,直接连接元素DatePattern的value形成文件路径。此处使用这种方式 -->

    <!--param的名称,可以直接查对应的appender类的属性名即可,这里要查的就是RollingFileAppender类的属性 -->

          <param name="File" value="D:/Log/" />

     

          <!--是否追加到文件-->

          <param name="AppendToFile" value="true" />

     

          <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->

          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

     

          <!—使用Unicode编码-->

          <Encoding value="UTF-8" />

     

          <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->

          <param name="MaxSizeRollBackups" value="10" />

     

          <!--是否只写到一个文件中-->

          <param name="StaticLogFileName" value="false" />

     

          <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->

          <param name="RollingStyle" value="Composite" />

     

          <!--按日期产生文件夹和文件名[在日期方式与混合方式下使用]-->

    <!—此处按日期产生文件夹,文件名固定。注意&quot; 的位置-->

          <param name="DatePattern" value="yyyy-MM-dd/&quot;ReflectionLayout.log&quot;"  />

    <!—这是按日期产生文件夹,并在文件名前也加上日期-->

          <param name="DatePattern" value="yyyyMMdd/yyyyMMdd&quot;-TimerServer.log&quot;"  />

    <!—这是先按日期产生文件夹,再形成下一级固定的文件夹—>

          <param name="DatePattern" value="yyyyMMdd/&quot;TimerServer/TimerServer.log&quot;"  />

     

          <!--每个文件的大小。只在混合方式与文件大小方式下使用。

    超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。

    可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志-->

          <param name="maximumFileSize" value="500KB" />

     

    <!--计数类型为1,2,3…-->
          <param name="CountDirection" value="1"/>

     

    <!—过滤设置,LevelRangeFilter为使用的过滤器。 -->

          <filter type="log4net.Filter.LevelRangeFilter">

            <param name="LevelMin" value="DEBUG" />

            <param name="LevelMax" value="WARN" />

          </filter>

     

          <!--记录的格式。一般用log4net.Layout.PatternLayout布局-->

    <!—此处用继承了log4net.Layout.PatternLayout的自定义布局,TGLog.ExpandLayout2

    为命名空间。%property{Operator}、%property{Action}是自定义的输出-->

          <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

            <param name="ConversionPattern"

     value="记录时间:%date 线程ID:[%thread] 日志级别:%-5level 记录类:%logger     操作者ID:%property{Operator} 操作类型:%property{Action}%n             当前机器名:%property%n当前机器名及登录用户:%username %n               记录位置:%location%n 消息描述:%property{Message}%n                    异常:%exception%n 消息:%message%newline%n%n" />

          </layout>

    </appender>

    注意这些配置属性有些是可选的,如果需要,一定要写正确,否则要么输出的不是自己想要的结果,要么干脆不输出任何信息。

    4.2.1写入SQL数据库

    需要在相应的数据库中准备好一张表,创建语句如下:

    CREATE TABLE [Log] (

    [ID] [int] IDENTITY (1, 1) NOT NULL ,

    [Date] [datetime] NOT NULL ,

    [Thread] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,

    [Level] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,

    [Logger] [varchar] (200) COLLATE Chinese_PRC_CI_AS NULL ,

    [Operator] [int] NULL ,

    [Message] [text] COLLATE Chinese_PRC_CI_AS NULL ,

    [ActionType] [int] NULL ,

    [Operand] [varchar] (300) COLLATE Chinese_PRC_CI_AS NULL ,

    [IP] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,

    [MachineName] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,

    [Browser] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,

    [Location] [text] COLLATE Chinese_PRC_CI_AS NULL ,

    [Exception] [text] COLLATE Chinese_PRC_CI_AS NULL

    )

    <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender,log4net">

    <!--BufferSize为缓冲区大小,只有日志记录超设定值才会一块写入到数据库-->

    <bufferSize value="10" /><!—或写为<param name="BufferSize" value="10" />-->

     

    <!--引用-->

    <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

     

    <!--连接数据库字符串-->

    <connectionString value="data source=.;initial catalog=Test;integrated security=false;persist security info=True;User ID=sa;Password=;" />

     

    <!--插入到表Log-->

    <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Operator],[Message],[ActionType],[Operand],[IP],[MachineName],[Browser],[Location],[Exception]) VALUES (@log_date, @thread, @log_level, @logger,@operator, @message,@action_type,@operand,@ip,@machineName,@browser,@location,@exception)" />

     

    <!—日志记录时间,RawTimeStampLayout为默认的时间输出格式 -->

          <parameter>

            <parameterName value="@log_date" />

            <dbType value="DateTime" />

            <layout type="log4net.Layout.RawTimeStampLayout" />

          </parameter>

     

          <!--线程号-->

          <parameter>

            <parameterName value="@thread" />

            <dbType value="String" />

    <!—长度不可以省略,否则不会输出-->

            <size value="100" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%thread" />

            </layout>

          </parameter>

     

          <!--日志等级-->

          <parameter>

            <parameterName value="@log_level" />

            <dbType value="String" />

            <size value="100" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%level" />

            </layout>

          </parameter>

     

          <!--日志记录类名称-->

          <parameter>

            <parameterName value="@logger" />

            <dbType value="String" />

            <size value="200" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%logger" />

            </layout>

          </parameter>

         

          <!--操作者。这个是自定义的输出字段,使用重新实现的布局器ReflectionLayout -->

          <parameter>

            <parameterName value="@operator" />

    <!—设置为Int32时只有bufferSize的 value<="1"才正确输出,没有找出原因。-->

            <dbType value="Int16" />

            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

              <conversionPattern value="%property{Operator}" />

            </layout>

          </parameter>

     

          <!--操作对象-->

          <parameter>

            <parameterName value="@operand" />

            <dbType value="String" />

            <size value="300" />

            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

              <conversionPattern value="%property{Operand}" />

            </layout>

          </parameter>

     

          <!—IP地址-->

          <parameter>

            <parameterName value="@ip" />

            <dbType value="String" />

            <size value="20" />

            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

              <conversionPattern value="%property{IP}" />

            </layout>

          </parameter>

     

          <!--机器名-->

          <parameter>

            <parameterName value="@machineName" />

            <dbType value="String" />

            <size value="100" />

            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

              <conversionPattern value="%property{MachineName}" />

            </layout>

          </parameter>

     

          <!--浏览器-->

          <parameter>

            <parameterName value="@browser" />

            <dbType value="String" />

            <size value="50" />

            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

              <conversionPattern value="%property{Browser}" />

            </layout>

          </parameter>

         

          <!—日志消息-->

          <parameter>

            <parameterName value="@message" />

            <dbType value="String" />

            <size value="3000" />

            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

              <conversionPattern value="%property{Message}" />

            </layout>

          </parameter>

     

          <!--动作类型-->

          <parameter>

            <parameterName value="@action_type" />

            <dbType value="Int16" />

            <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

              <conversionPattern value="%property{ActionType}" />

            </layout>

          </parameter>

     

          <!—记录日志的位置-->

          <parameter>

            <parameterName value="@location" />

            <dbType value="String" />

            <size value="2000" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%location" />

            </layout>

          </parameter>

         

          <!—异常信息。ExceptionLayout 为异常输出的默认格式-->

          <parameter>

            <parameterName value="@exception" />

            <dbType value="String" />

            <size value="4000" />

            <layout type="log4net.Layout.ExceptionLayout" />

          </parameter>

    </appender>

    注意:

    向表中输出的字段不能多于数据表本身字段,而反之则可以,但这些多余字段一定使其可以为空,否则便写不到数据库;

    输出字段的类型一定是对应数据表字段数据类型可以隐式转换的,而且长度也不能超过,否则也不能写入;

    数据表字段设置尽量可以为空,这样可以避免一条日志记录存在空数据导致后面的日志都记录不了。

    4.3<logger>的配置

    在配置文件<appender>中的配置好了输出的介质,格式,过滤方式,还要定义日志对象<logger>。

    在框架的体系里,所有的日志对象都是根日志(root logger)的后代。 因此如果一个日志对象没有在配置文件里显式定义,则框架使用根日志中定义的属性。在<root>标签里,可以定义level级别值和Appender的列表。如果没有定义LEVEL的值,则缺省为DEBUG。可以通过<appender-ref>标签定义日志对象使用的Appender对象。<appender-ref>声明了在其他地方定义的Appender对象的一个引用。在一个logger对象中的设置会覆盖根日志的设置。而对Appender属性来说,子日志对象则会继承父日志对象的Appender列表。这种缺省的行为方式也可以通过显式地设定<logger>标签的additivity属性为false而改变。

    <root>不显式申明时使用默认的配置。我觉得在使用时不定义<root>,自定义多个<logger>,在程序中记录日志时直接使用<logger>的name来查找相应的<logger>,这样更灵活一些。例如:

    <!--同时写两个文件和数据库-->

    <logger name="ReflectionLayout">

          <level value="DEBUG"/>

          <appender-ref ref="HashtableLayout"/>

          <appender-ref ref="ReflectionLayout"/>

          <appender-ref ref="ADONetAppender"/>

    </logger>

    4.4关联配置文件

    log4net默认关联的是应用程序的配置文件App.config(BS程序是Web.config),可以使用程序集自定义属性来进行设置。下面来介绍一下这个自定义属性:

    log4net.Config.XmlConifguratorAttribute。

     

    XmlConfiguratorAttribute有3个属性:

    ConfigFile: 配置文件的名字,文件路径相对于应用程序目录

    (AppDomain.CurrentDomain.BaseDirectory)。ConfigFile属性不能和ConfigFileExtension属性一起使用。

    ConfigFileExtension: 配置文件的扩展名,文件路径相对于应用程序的目录。ConfigFileExtension属性不能和ConfigFile属性一起使用。

    Watch: 如果将Watch属性设置为true,就会监视配置文件。当配置文件发生变化的时候,就会重新加载。

    如果ConfigFile和ConfigFileExtension都没有设置,则使用应用程序的配置文件App.config(Web.config)。

     

    可以在项目的AssemblyInfo.cs文件里添加以下的语句:

     //监视默认的配置文件,App.exe.config   

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

     

    //监视配置文件,App.exe.log4net。

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

     

    //使用配置文件log4net.config,不监视改变。注意log4net.config文件的目录,BS程序在站点目录//下,CS则在应用程序启动目录下,如调试时在/bin/Debug下,一般将文件属性的文件输出目录调为//始终复制即可

    [assembly: log4net. Config.XmlConfigurator(ConfigFile = "log4net.config")]

     

    //使用配置文件log4net.config,不监视改变

    [assembly: log4net. Config.XmlConfigurator()]

     

    也可以在Global.asax的Application_Start里或者是Program.cs中的Main方法中添加,注意这里一定是绝对路径,如下所示:

    //这是在BS程序下,使用自定义的配置文件log4net.xml,使用Server.MapPath("~") + //@"/log4net.xml”来取得路径。/log4net.xml为相对于站点的路径

    // ConfigureAndWatch()相当于Configure(Watch = true)

    log4net.Config.XmlConfigurator.ConfigureAndWatch(

    new System.IO.FileInfo(Server.MapPath("~") + @"/log4net.xml"));

    //这是在CS程序下,可以用以下方法获得:

    string assemblyFilePath = Assembly.GetExecutingAssembly().Location;

    string assemblyDirPath = Path.GetDirectoryName(assemblyFilePath);

    string configFilePath = assemblyDirPath + " //log4net.xml";

    log4net.Config.XmlConfigurator.ConfigureAndWatch(

    new FileInfo(configFilePath));

     

    或直接使用绝对路径:

    //使用自定义的配置文件,直接绝对路径为:c:/log4net.config

    log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(@"c:/log4net.config"));

     

    5、如何记录日志

    Log4net使用很方便,先申明一个封装类ILog 的对象,如下:

    log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout");

    其中"ReflectionLayout"便是我们自定义的日志对象<logger>的name的值。

    对应5个日志输出级别,log有5 个方法,每个方法都有两个重载,使用如下:

    try

                {

                    log.Debug("这是一个测试!");

                }

                catch(Exception ec)

                {

                    log.Error("出现错误!", ec);

             }

    如果我们需要输出的消息是要区别开来,不按一个字符串全部输出,就需要进行一些扩展了。

    6、Log4net的简单扩展

    6.1通过重写布局Layout输出传入的 message对象的属性

    6.1.1重写Layout类

    通过继承log4net.Layout.PatternLayout类,使用log4net.Core.LoggingEvent类的方法得到了要输出的message类的名称,然后通过反射得到各个属性的值,使用PatternLayout类AddConverter方法传入得到的值。这里注意要引用用到的类的命名空间。

    代码见附注8.2。

     

    6.1.2配置相应的配置文件

    配置文件其他地方不用改动,只是需要改动<appender>中的<layout>。例如:

    <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

            <param name="ConversionPattern"

     value="记录时间:%date    操作者ID:%property{Operator}             

    操作类型:%property{Action}%n  消息描述:%property{Message}%n                    异常:%exception%n " />

          </layout>

    其中<layout>的type由原来的log4net.Layout.PatternLayout换为自定义的TGLog.ExpandLayout2.ReflectionLayout(TGLog.ExpandLayout2为命名空间)。%property{Operator}输出的即为message类对象的属性Operator的值。数据库配置同样,相应的字段如果是自定义的,则输出选用自定义的<layout>。例:

    <!--动作类型-->

      <parameter>

          <parameterName value="@action_type" />

          <dbType value="Int16" />

          <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

             <conversionPattern value="%property{ActionType}" />

          </layout>

      </parameter>

    6.1.3程序中如何使用

    和一般使用方法基本相同,只是传入的参数是一个自定义的类,类的属性和配置文件中<layout>所有的%property{属性}是一致的,即%property{属性}在输出的时候就查找传入message类中有无对应的属性,如果有就输出值,没有则输出null。例:

    log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout");

    try

                {

                    log.Debug(new LogMessage(

    1,

    "操作对象:0",

     (int)TGLog.ActionType.Other,

     "这是四个参数测试")

    );

                }

                catch(Exception ec)

                {

                    log.Error(new LogMessage(

                                        1,

                                        "操作对象:0",

                                        (int)TGLog.ActionType.Other,

                                        "这是全部参数测试",

                                        "192.168.1.1",

                                        "MyComputer",

                                        "Maxthon(MyIE2)Fans"),

                             ec

    );

          }

    LogMessage的全部属性的构造方法如下:

    public LogMessage(

                int operatorID,

                string operand,

                int ActionType,

                string message,

                string ip,

                string machineName,

                string browser

                )

         {

                this.ActionType = ActionType;

                this.Operator = operatorID;

                this.Message = message;

                this.Operand = operand;

                this.IP = ip;

                this.Browser = browser;

                this.MachineName = machineName;

    }

    6.2通过重新实现ILog接口来增加输入的参数

    6.2.1重写LogImpl,LogManager类及实现ILog接口

    这种方式是通过构造一个名为IMyLog接口,是继承Ilog接口而来,然后分别在MyLogImpl,MyLogManager重新实现IMyLog接口,增加了每种方法的参数。MyLogImpl,MyLogManager分别继承LogImpl,LogManager而来。

    代码分别见8.3、8.4、8.5:

    6.2.2配置相应的配置文件

    配置文件其他地方不用改动,只是需要改动<appender>中的<layout>元素name为ConversionPattern的value中输出格式。例如:

    <layout type=" log4net.Layout.PatternLayout ">

            <param name="ConversionPattern"

     value="记录时间:%date    操作者ID:%property{Operator}             

    操作类型:%property{Action}%n  消息描述:%property{Message}%n                    异常:%exception%n " />

          </layout>

    %property{参数}中的参数在MyLogImpl类中定义,如语句:

    loggingEvent.Properties["Operator"] = operatorID;

    就定义了Operator输出参数,即%property{Operator}输出的即为IMyLog中的参数operatorID的值。

    数据库配置同样。例:

    <!--动作类型-->

      <parameter>

          <parameterName value="@action_type" />

          <dbType value="Int16" />

          <layout type=" log4net.Layout.PatternLayout ">

             <conversionPattern value="%property{ActionType}" />

          </layout>

      </parameter>

    6.2.3程序中如何使用

    先引用IMyLog ,MyLogManager所在的命名空间,创建一个IMyLog对象,myLog的5 个方法,每个方法都有四个重载,增加了多参数的重载。例:

    IMyLog myLog = MyLogManager.GetLogger("ExpandILog");

    try

                {

    myLog.Debug("这是一个参数重载测试!");          

    }

                catch(Exception ec)

                {

                    log.Error(

                              1,

                              "操作对象:0",

                              (int)TGLog.ActionType.Other,

                              "这是全部参数测试",

                              "192.168.1.1",

                              "MyComputer",

                              "Maxthon(MyIE2)Fans",

                              ec

    );

          }

    7、总结

    Log4net 功能很多,这里只是对已经尝试用过的功能总结一下,普通写日志已经足够。需要注意的是:

    1.            Log4net本身也有一些缺陷,比如一个记录引起了log4net本身的异常,就会使后面的日志无法记录下来,尤其是在写入数据库时。例如使用6.1扩展后,int型的属性在<appender >的元素<bufferSize>设置不为1时,<dbType value="Int32" />时,就不能输出到数据库,而<dbType value="Int16" />则没任何问题。

    2.            Log4net本身出现了异常,比如配置文件出现错误,有些日志输出方式会记录下这些异常,例如应用程序控制台;有些则不会输出这些错误,如数据库与文件。

    3.            扩展时也会留下一些问题。例如在使用6.1扩展输出字段时就会出现,在log.debug(object message)中,如果message是一个自定义的类,属性与配置文件中输出设置也一致,构造函数时也只构造一个参数的实例,写文件与写数据库都成功,而将message按没有扩展的方式直接传入一个字符串,即log.debug(“信息内容”)使用则只能写入文件,而数据库则没写入。自定义的Layout 就是继承默认的PatternLayout,本来不应该出错,但出现了问题。原因分析是自定义的message类有类型为int的属性,作为一个对象传入时在默认值0,而直接使用字符串则int型的字段得不到默认值,引发异常。所以建议在有扩展存在时,最好多设几个<logger>,区分清楚,按照统一的形式记录日志,不要混合使用。

    4.            配置文件的设置一定要准确,在一点不正确就会导致日志不能正常输出,所以在配置时先从最简单的开始,同时输出方式选择一种能输出log4net本身异常的方式,成功后一点一点加在新配置,这样出错了也容易找到那个地方配置有问题。

    5.            log4net扩展性很强,几乎所有的组件都可以重写,在配置文件中配置好就可以使用。

    8、附注:

    8.1PatterLayout格式化字符表

    转换字符

    效果

    a

    等价于appdomain

    appdomain

    引发日志事件的应用程序域的友好名称。(使用中一般是可执行文件的名字。)

    c

    等价于 logger

    C

    等价于 type

    class

    等价于 type

    d

    等价于 date

    date

    发生日志事件的本地时间。 使用 DE>%utcdate 输出UTC时间。date后面还可以跟一个日期格式,用大括号括起来。DE>例如:%date{HH:mm:ss,fff}或者%date{dd MMM yyyy HH:mm:ss,fff}。如果date后面什么也不跟,将使用ISO8601 格式 。

    日期格式和.Net中DateTime类的ToString方法中使用的格式是一样。

    另外log4net还有3个自己的格式Formatter。 它们是 "ABSOLUTE", "DATE"和"ISO8601"分别代表 AbsoluteTimeDateFormatter, DateTimeDateFormatter和Iso8601DateFormatter。例如:%date{ISO8601}或%date{ABSOLUTE}。

    它们的性能要好于ToString。

    exception

    异常信息

    日志事件中必须存了一个异常对象,如果日志事件不包含没有异常对象,将什么也不输出。异常输出完毕后会跟一个换行。一般会在输出异常前加一个换行,并将异常放在最后。

    F

    等价于 file

    file

    发生日志请求的源代码文件的名字。

    警告:只在调试的时候有效。调用本地信息会影响性能。

    identity

    当前活动用户的名字(Principal.Identity.Name).

    警告:会影响性能。(我测试的时候%identity返回都是空的。)

    l

    等价于 location

    L

    等价于 line

    location

    引发日志事件的方法(包括命名空间和类名),以及所在的源文件和行号。

    警告:会影响性能。没有pdb文件的话,只有方法名,没有源文件名和行号。

    level

    日志事件等级

    line

    引发日志事件的行号

    警告:会影响性能。

    logger

    记录日志事件的Logger对象的名字。

    可以使用精度说明符控制Logger的名字的输出层级,默认输出全名。

    注意,精度符的控制是从右开始的。例如:logger 名为 "a.b.c", 输出模型为%logger{2} ,将输出"b.c"。

    m

    等价于 message

    M

    等价于 method

    message

    由应用程序提供给日志事件的消息。

    mdc

    MDC (旧为:ThreadContext.Properties) 现在是事件属性的一部分。 保留它是为了兼容性,它等价于 property。

    method

    发生日志请求的方法名(只有方法名而已)。

    警告:会影响性能。

    n

    等价于 newline

    newline

    换行符

    ndc

    NDC (nested diagnostic context)

    p

    等价于 level

    P

    等价于 property

    properties

    等价于 property

    property

    输出事件的特殊属性。例如: %property{user} 输出user属性。属性是由loggers或appenders添加到时间中的。 有一个默认的属性"DE>log4net:HostName"总是会有。DE>

    %property将输出所有的属性 。

    (扩展后可以使用)

     

    r

    等价于 timestamp

    t

    等价于 thread

    timestamp

    从程序启动到事件发生所经过的毫秒数。

    thread

    引发日志事件的线程,如果没有线程名就使用线程号。

    type

    引发日志请求的类的全名。.

    可以使用精度控制符。例如: 类名是 "log4net.Layout.PatternLayout", 格式模型是%type{1} 将输出"PatternLayout"。(也是从右开始的。)

    警告:会影响性能。

    u

    等价于 identity

    username

    当前用户的WindowsIdentity。(类似:HostName/Username)

    警告:会影响性能。

    utcdate

    发生日志事件的UTC时间。DE>后面还可以跟一个日期格式,用大括号括起来。DE>例如:%utcdate{HH:mm:ss,fff}或者%utcdate{dd MMM yyyy HH:mm:ss,fff}。如果utcdate后面什么也不跟,将使用ISO8601 格式 。

    日期格式和.Net中DateTime类的ToString方法中使用的格式是一样。

    另外log4net还有3个自己的格式Formatter。 它们是 "ABSOLUTE", "DATE"和"ISO8601"分别代表 AbsoluteTimeDateFormatter, DateTimeDateFormatter和Iso8601DateFormatter。例如:%date{ISO8601}或%date{ABSOLUTE}。

    它们的性能要好于ToString。

    w

    等价于 username

    x

    等价于 ndc

    X

    等价于 mdc

    %

    %%输出一个百分号

    关于调用本地信息(caller location information)的说明:

    %type %file %line %method %location %class %C %F %L %l %M 都会调用本地信息。这样做会影响性能。本地信息使用System.Diagnostics.StackTrace得到。.Net 1.0 不支持System.Diagnostics.StackTrace 类。

    本地信息在调试模式下可以正常获取,在非调试模式下可能获取不到,或只能获取一部分。(根据我的测试,其实是需要有一个程序数据库(.pdb)文件。)

    %property属性要用代码来设置才能使用(也就是扩展一下),

    默认属性log4net:HostName不用设置。

    转义字符的修饰符:

    Format modifier

    left justify

    minimum width

    maximum width

    comment

    %20logger

    false

    20

    none

    如果logger名不足20个字符,就在左边补空格。

    %-20logger

    true

    20

    none

    如果logger名不足20个字符,就在右边补空格。

    %.30logger

    NA

    none

    30

    超过30个字符将截断。

    %20.30logger

    false

    20

    30

    logger名要在20到30之间,少了在左边补空格,多了截断。

    %-20.30logger

    true

    20

    30

    logger名要在20到30之间,少了在右边补空格,多了截断。

    8.2Layout类代码

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using log4net.Layout;

    using log4net.Layout.Pattern;

    using System.Reflection;

    using System.Collections;

    using FastReflectionLib;

     

    namespace TGLog.ExpandLayout2

    {

        public class ReflectionLayout : PatternLayout

        {

            public ReflectionLayout()

            {

                this.AddConverter("property", typeof(ReflectionPatternConverter));

            }

        }

     

        public class ReflectionPatternConverter : PatternLayoutConverter

        {

            protected override void Convert(

    System.IO.TextWriter writer,

     log4net.Core.LoggingEvent loggingEvent

    )

            {

                if (Option != null)

                {

                    // 写入指定键的值

                    WriteObject(

    writer,

     loggingEvent.Repository,

     LookupProperty(Option,

     loggingEvent)

    );

                }

                else

                {

                    // 写入所有关键值对

                    WriteDictionary(

    writer,

    loggingEvent.Repository,

     loggingEvent.GetProperties()

    );

                }

            }

     

            /// <summary>

            /// 通过反射获取传入的日志对象的某个属性的值

            /// </summary>

            /// <param name="property"></param>

            /// <returns></returns>

            private object LookupProperty(

    string property,

     log4net.Core.LoggingEvent loggingEvent)

            {

                object propertyValue = string.Empty;

     

                PropertyInfo propertyInfo =

    loggingEvent.MessageObject.GetType().GetProperty(property);

                if (propertyInfo != null)

                {

                    propertyValue =

    propertyInfo.GetValue(loggingEvent.MessageObject, null);

                }

                return propertyValue;

            }

        }

    }

    8.3 MyLogImpl类代码

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using log4net.Core;

     

    namespace TGLog.ExpandILog

    {

        public class MyLogImpl : LogImpl, IMyLog

        {

            /// <summary>

            /// The fully qualified name of this declaring type not the type of any subclass.

            /// </summary>

            private readonly static Type ThisDeclaringType = typeof(MyLogImpl);

     

            public MyLogImpl(ILogger logger)

                : base(logger)

            {       

            }

     

            #region Implementation of IMyLog

     

            public void Debug(int operatorID, string operand, int actionType,object message,

     string ip, string browser, string machineName)

            {

                Debug(operatorID,  operand,  actionType, message,

      ip,  browser, machineName, null);

            }

     

            public void Debug(int operatorID, string operand, int actionType,object message,

    string ip, string browser, string machineName, System.Exception t)

            {

                if (this.IsDebugEnabled)

                {

                    LoggingEvent loggingEvent =

    new LoggingEvent(ThisDeclaringType, Logger.Repository,

                                           Logger.Name, Level.Info, message, t);

                    loggingEvent.Properties["Operator"] = operatorID;

                    loggingEvent.Properties["Operand"] = operand;

                    loggingEvent.Properties["ActionType"] = actionType;

                    loggingEvent.Properties["IP"] = ip;

                    loggingEvent.Properties["Browser"] = browser;

                    loggingEvent.Properties["MachineName"] = machineName;

                    Logger.Log(loggingEvent);

                }

            }

     

            public void Info(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName)

            {

                Info(operatorID, operand, actionType, message, ip, browser, machineName, null);

            }

     

            public void Info(int operatorID, string operand, int actionType, object message,

     string ip, string browser, string machineName, System.Exception t)

            {

                if (this.IsInfoEnabled)

                {

                    LoggingEvent loggingEvent =

     new LoggingEvent(ThisDeclaringType, Logger.Repository,

     Logger.Name, Level.Info, message, t);

                    loggingEvent.Properties["Operator"] = operatorID;

                    loggingEvent.Properties["Operand"] = operand;

                    loggingEvent.Properties["ActionType"] = actionType;

                    loggingEvent.Properties["IP"] = ip;

                    loggingEvent.Properties["Browser"] = browser;

                    loggingEvent.Properties["MachineName"] = machineName;

                    Logger.Log(loggingEvent);

                }

            }

     

            public void Warn(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName)

            {

                Warn(operatorID, operand, actionType, message, ip, browser, machineName, null);

            }

     

            public void Warn(int operatorID, string operand, int actionType, object message,

     string ip, string browser, string machineName, System.Exception t)

            {

                if (this.IsWarnEnabled)

                {

                    LoggingEvent loggingEvent =

     new LoggingEvent(ThisDeclaringType, Logger.Repository,

    Logger.Name, Level.Info, message, t);

                    loggingEvent.Properties["Operator"] = operatorID;

                    loggingEvent.Properties["Operand"] = operand;

                    loggingEvent.Properties["ActionType"] = actionType;

                    loggingEvent.Properties["IP"] = ip;

                    loggingEvent.Properties["Browser"] = browser;

                    loggingEvent.Properties["MachineName"] = machineName;

                    Logger.Log(loggingEvent);

                }

            }

     

            public void Error(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName)

            {

                Error(operatorID, operand, actionType, message, ip, browser, machineName, null);

            }

     

            public void Error(int operatorID, string operand, int actionType, object message,

     string ip, string browser, string machineName, System.Exception t)

            {

                if (this.IsErrorEnabled)

                {

                    LoggingEvent loggingEvent =

     new LoggingEvent(ThisDeclaringType, Logger.Repository,

     Logger.Name, Level.Info, message, t);

                    loggingEvent.Properties["Operator"] = operatorID;

                    loggingEvent.Properties["Operand"] = operand;

                    loggingEvent.Properties["ActionType"] = actionType;

                    loggingEvent.Properties["IP"] = ip;

                    loggingEvent.Properties["Browser"] = browser;

                    loggingEvent.Properties["MachineName"] = machineName;

                    Logger.Log(loggingEvent);

                }

            }

     

            public void Fatal(int operatorID, string operand, int actionType, object message,

     string ip, string browser, string machineName)

            {

                Fatal(operatorID, operand, actionType, message, ip, browser, machineName, null);

            }

     

            public void Fatal(int operatorID, string operand, int actionType, object message,

     string ip, string browser, string machineName, System.Exception t)

            {

                if (this.IsFatalEnabled)

                {

                    LoggingEvent loggingEvent =

     new LoggingEvent(ThisDeclaringType, Logger.Repository,

                                           Logger.Name, Level.Info, message, t);

                    loggingEvent.Properties["Operator"] = operatorID;

                    loggingEvent.Properties["Operand"] = operand;

                    loggingEvent.Properties["ActionType"] = actionType;

                    loggingEvent.Properties["IP"] = ip;

                    loggingEvent.Properties["Browser"] = browser;

                    loggingEvent.Properties["MachineName"] = machineName;

                    Logger.Log(loggingEvent);

                }

            }

            #endregion Implementation of IMyLog

        }

    }

     

    8.4 MyLogManager类代码

    #region Copyright & License

    //

    // Copyright 2001-2005 The Apache Software Foundation

    //

    // Licensed under the Apache License, Version 2.0 (the "License");

    // you may not use this file except in compliance with the License.

    // You may obtain a copy of the License at

    //

    // http://www.apache.org/licenses/LICENSE-2.0

    //

    // Unless required by applicable law or agreed to in writing, software

    // distributed under the License is distributed on an "AS IS" BASIS,

    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

    // See the License for the specific language governing permissions and

    // limitations under the License.

    //

    #endregion

     

    using System;

    using System.Reflection;

    using System.Collections;

    using log4net;

    using log4net.Core;

    using log4net.Repository;

    using log4net.Repository.Hierarchy;

     

    namespace TGLog.ExpandILog

    {

        public class MyLogManager

        {

            #region Static Member Variables

     

            /// <summary>

            /// The wrapper map to use to hold the <see cref="EventIDLogImpl"/> objects

            /// </summary>

            private static readonly WrapperMap s_wrapperMap = new WrapperMap(newWrapperCreationHandler(WrapperCreationHandler));

     

            #endregion

     

            #region Constructor

     

            /// <summary>

            /// Private constructor to prevent object creation

            /// </summary>

            private MyLogManager() { }

     

            #endregion

     

            #region Type Specific Manager Methods

     

            /// <summary>

            /// Returns the named logger if it exists

            /// </summary>

            /// <remarks>

            /// <para>If the named logger exists (in the default hierarchy) then it

            /// returns a reference to the logger, otherwise it returns

            /// <c>null</c>.</para>

            /// </remarks>

            /// <param name="name">The fully qualified logger name to look for</param>

            /// <returns>The logger found, or null</returns>

            public static IMyLog Exists(string name)

            {

                return Exists(Assembly.GetCallingAssembly(), name);

            }

     

            /// <summary>

            /// Returns the named logger if it exists

            /// </summary>

            /// <remarks>

            /// <para>If the named logger exists (in the specified domain) then it

            /// returns a reference to the logger, otherwise it returns

            /// <c>null</c>.</para>

            /// </remarks>

            /// <param name="domain">the domain to lookup in</param>

            /// <param name="name">The fully qualified logger name to look for</param>

            /// <returns>The logger found, or null</returns>

            public static IMyLog Exists(string domain, string name)

            {

                return WrapLogger(LoggerManager.Exists(domain, name));

            }

     

            /// <summary>

            /// Returns the named logger if it exists

            /// </summary>

            /// <remarks>

            /// <para>If the named logger exists (in the specified assembly's domain) then it

            /// returns a reference to the logger, otherwise it returns

            /// <c>null</c>.</para>

            /// </remarks>

            /// <param name="assembly">the assembly to use to lookup the domain</param>

            /// <param name="name">The fully qualified logger name to look for</param>

            /// <returns>The logger found, or null</returns>

            public static IMyLog Exists(Assembly assembly, string name)

            {

                return WrapLogger(LoggerManager.Exists(assembly, name));

            }

     

            /// <summary>

            /// Returns all the currently defined loggers in the default domain.

            /// </summary>

            /// <remarks>

            /// <para>The root logger is <b>not</b> included in the returned array.</para>

            /// </remarks>

            /// <returns>All the defined loggers</returns>

            public static IMyLog[] GetCurrentLoggers()

            {

                return GetCurrentLoggers(Assembly.GetCallingAssembly());

            }

     

            /// <summary>

            /// Returns all the currently defined loggers in the specified domain.

            /// </summary>

            /// <param name="domain">the domain to lookup in</param>

            /// <remarks>

            /// The root logger is <b>not</b> included in the returned array.

            /// </remarks>

            /// <returns>All the defined loggers</returns>

            public static IMyLog[] GetCurrentLoggers(string domain)

            {

                return WrapLoggers(LoggerManager.GetCurrentLoggers(domain));

            }

     

            /// <summary>

            /// Returns all the currently defined loggers in the specified assembly's domain.

            /// </summary>

            /// <param name="assembly">the assembly to use to lookup the domain</param>

            /// <remarks>

            /// The root logger is <b>not</b> included in the returned array.

            /// </remarks>

            /// <returns>All the defined loggers</returns>

            public static IMyLog[] GetCurrentLoggers(Assembly assembly)

            {

                return WrapLoggers(LoggerManager.GetCurrentLoggers(assembly));

            }

     

            /// <summary>

            /// Retrieve or create a named logger.

            /// </summary>

            /// <remarks>

            /// <para>Retrieve a logger named as the <paramref name="name"/>

            /// parameter. If the named logger already exists, then the

            /// existing instance will be returned. Otherwise, a new instance is

            /// created.</para>

            ///

            /// <para>By default, loggers do not have a set level but inherit

            /// it from the hierarchy. This is one of the central features of

            /// log4net.</para>

            /// </remarks>

            /// <param name="name">The name of the logger to retrieve.</param>

            /// <returns>the logger with the name specified</returns>

            public static IMyLog GetLogger(string name)

            {

                return GetLogger(Assembly.GetCallingAssembly(), name);

            }

     

            /// <summary>

            /// Retrieve or create a named logger.

            /// </summary>

            /// <remarks>

            /// <para>Retrieve a logger named as the <paramref name="name"/>

            /// parameter. If the named logger already exists, then the

            /// existing instance will be returned. Otherwise, a new instance is

            /// created.</para>

            ///

            /// <para>By default, loggers do not have a set level but inherit

            /// it from the hierarchy. This is one of the central features of

            /// log4net.</para>

            /// </remarks>

            /// <param name="domain">the domain to lookup in</param>

            /// <param name="name">The name of the logger to retrieve.</param>

            /// <returns>the logger with the name specified</returns>

            public static IMyLog GetLogger(string domain, string name)

            {

                return WrapLogger(LoggerManager.GetLogger(domain, name));

            }

     

            /// <summary>

            /// Retrieve or create a named logger.

            /// </summary>

            /// <remarks>

            /// <para>Retrieve a logger named as the <paramref name="name"/>

            /// parameter. If the named logger already exists, then the

            /// existing instance will be returned. Otherwise, a new instance is

            /// created.</para>

            ///

            /// <para>By default, loggers do not have a set level but inherit

            /// it from the hierarchy. This is one of the central features of

            /// log4net.</para>

            /// </remarks>

            /// <param name="assembly">the assembly to use to lookup the domain</param>

            /// <param name="name">The name of the logger to retrieve.</param>

            /// <returns>the logger with the name specified</returns>

            public static IMyLog GetLogger(Assembly assembly, string name)

            {

                return WrapLogger(LoggerManager.GetLogger(assembly, name));

            }

     

            /// <summary>

            /// Shorthand for <see cref="LogManager.GetLogger(string)"/>.

            /// </summary>

            /// <remarks>

            /// Get the logger for the fully qualified name of the type specified.

            /// </remarks>

            /// <param name="type">The full name of <paramref name="type"/> will

            /// be used as the name of the logger to retrieve.</param>

            /// <returns>the logger with the name specified</returns>

            public static IMyLog GetLogger(Type type)

            {

                return GetLogger(Assembly.GetCallingAssembly(), type.FullName);

            }

     

            /// <summary>

            /// Shorthand for <see cref="LogManager.GetLogger(string)"/>.

            /// </summary>

            /// <remarks>

            /// Get the logger for the fully qualified name of the type specified.

            /// </remarks>

            /// <param name="domain">the domain to lookup in</param>

            /// <param name="type">The full name of <paramref name="type"/> will

            /// be used as the name of the logger to retrieve.</param>

            /// <returns>the logger with the name specified</returns>

            public static IMyLog GetLogger(string domain, Type type)

            {

                return WrapLogger(LoggerManager.GetLogger(domain, type));

            }

     

            /// <summary>

            /// Shorthand for <see cref="LogManager.GetLogger(string)"/>.

            /// </summary>

            /// <remarks>

            /// Get the logger for the fully qualified name of the type specified.

            /// </remarks>

            /// <param name="assembly">the assembly to use to lookup the domain</param>

            /// <param name="type">The full name of <paramref name="type"/> will

            /// be used as the name of the logger to retrieve.</param>

            /// <returns>the logger with the name specified</returns>

            public static IMyLog GetLogger(Assembly assembly, Type type)

            {

                return WrapLogger(LoggerManager.GetLogger(assembly, type));

            }

     

            #endregion

     

            #region Extension Handlers

     

            /// <summary>

            /// Lookup the wrapper object for the logger specified

            /// </summary>

            /// <param name="logger">the logger to get the wrapper for</param>

            /// <returns>the wrapper for the logger specified</returns>

            private static IMyLog WrapLogger(ILogger logger)

            {

                return (IMyLog)s_wrapperMap.GetWrapper(logger);

            }

     

            /// <summary>

            /// Lookup the wrapper objects for the loggers specified

            /// </summary>

            /// <param name="loggers">the loggers to get the wrappers for</param>

            /// <returns>Lookup the wrapper objects for the loggers specified</returns>

            private static IMyLog[] WrapLoggers(ILogger[] loggers)

            {

                IMyLog[] results = new IMyLog[loggers.Length];

                for (int i = 0; i < loggers.Length; i++)

                {

                    results[i] = WrapLogger(loggers[i]);

                }

                return results;

            }

     

            /// <summary>

            /// Method to create the <see cref="ILoggerWrapper"/> objects used by

            /// this manager.

            /// </summary>

            /// <param name="logger">The logger to wrap</param>

            /// <returns>The wrapper for the logger specified</returns>

            private static ILoggerWrapper WrapperCreationHandler(ILogger logger)

            {

                return new MyLogImpl(logger);

            }

            #endregion

        }

    }

    8.5 IMyLog类代码

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using log4net;

     

    namespace TGLog.ExpandILog

    {

        public interface IMyLog : ILog

        {

            void Debug(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName);

            void Debug(int operatorID, string operand, int actionType,object message,

    string ip, string browser, string machineName, Exception t);

     

            void Info(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName);

            void Info(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName, Exception t);

     

            void Warn(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName);

            void Warn(int operatorID, string operand, int actionType, object message,

     string ip, string browser, string machineName, Exception t);

     

            void Error(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName);

            void Error(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName, Exception t);

     

            void Fatal(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName);

            void Fatal(int operatorID, string operand, int actionType, object message,

    string ip, string browser, string machineName, Exception t);

        }

    }

    8.6附件

    使用log4net记录日志

    8.7参考

    1、http://peibing211.blog.163.com/blog/static/37116360200992811595469/

    2、http://www.cnblogs.com/qiangzi/archive/2009/09/10/1541023.html

    3、http://blog.chinaunix.net/u/23701/showart_1414206.html

    4、http://itrust.cnblogs.com/archive/2005/01/25/97225.html

    5、http://www.cnitblog.com/seeyeah/archive/2009/09/20/61491.aspx

    6、http://www.cnblogs.com/zhmore/archive/2009/03/19/1416707.html

    7、http://blog.shinylife.net/blog/article.asp?id=948

    8、http://www.cnblogs.com/manhoo/archive/2009/06/25/1511066.html

    展开全文
  • .NET版开源日志框架Log4Net详解

    千次阅读 2018-09-25 11:24:49
    来源:Yaopengfei链接:http://www.cnblogs.com/yaopengfei/p/9428206.html一、Log4Net简介Log4net是从J...
        

    来源:Yaopengfei

    链接:http://www.cnblogs.com/yaopengfei/p/9428206.html


    一、Log4Net简介


    Log4net是从Java中的Log4j迁移过来的一个.Net版的开源日志框架,它的功能很强大,可以将日志分为不同的等级,以不同的格式输出到不同的存储介质中,比如:数据库、txt文件、内存缓冲区、邮件、控制台、ANSI终端、远程接收端等等,我们这里主要介绍最常用的两种:txt文件和数据库。


    (PS:其它的存储介质详见 http://logging.apache.org/log4net/release/config-examples.html)


    Log4net将日志分为五个级别,分别是: FATAL(致命错误) > ERROR(一般错误) > WARN(警告) > INFO(一般信息) > DEBUG(调试信息),每个级别都对应着一组重载方法进行调用。


    官网地址:http://logging.apache.org/log4net/index.html

    Nuget地址:https://www.nuget.org/packages/log4net/

    Nuget安装:Install-Package log4net

    最新版本:2.0.8 (2018-08-09)


    本节主要围绕两个主要的存储介质:【txt文件】和【SQLServer数据库】展开,涵盖的知识点有:


    ①. 基本的使用步骤。

    ②. 初始化关联配置文件的几种形式。

    ③. 代码调用详解。

    ④. 配置文件详解。

    ⑤. 简单的封装和在MVC框架中的调用。 


    二、基本使用步骤


    我们先以控制台程序为例,简单介绍Log4net存储日志到txt文本文档中,后面在做代码的详解。


    1、新建01-SimpleDemo控制台程序,通过指令 【Install-Package log4net】安装相应程序集。


    640?wx_fmt=png


    2、在默认配置文件中App.config(B/S程序则为web.config)中进行配置,主要分两块:


    A. 在<configuration></configuration>节点下新增节点下新增(要在其最顶部):


    <configSections>

     <section name = "log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />

    </configSections>


    B. 在<configuration></configuration>根节点下,配置log4net的核心配置代码, 主要节点如下:


    <log4net> <appender> </appender> <root></root> </log4net>


    详细代码如下:


    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

      <!-- 1. 添加log4net的节点声明配置代码-->

      <configSections>

        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />

      </configSections>

      <!--2. log4net的核心配置代码-->

      <log4net>   

        <!--把日志信息输出到以日期命名的文件里-->

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

          <!--文件夹的位置-->

          <file value="D:MyLog1" />

          <appendToFile value="true" />

          <!--动态生成文件名-->

          <param name="StaticLogFileName" value="false" />

          <!--以日期命名-->

          <param name="DatePattern" value="yyyyMMdd&quot;.log&quot;" />

          <rollingStyle value="Date" />

          <!--日志在日志文件中的布局方式-->

          <layout type="log4net.Layout.PatternLayout">

            <conversionPattern value="%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别:  %-5level %n出错类:%logger property: [%property{NDC}] - %n错误描述:%message%newline %n"/>

          </layout>

          <!--使用最小锁定模型(minimal locking model),以允许多个进程可以写入同一个文件 -->

          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

        </appender> 

        <root>

          <level value="ALL"></level>

          <appender-ref ref="RollingFileAppender"></appender-ref>

        </root> 

      </log4net>

      <startup>

        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />

      </startup>

    </configuration>


    3、代码调用


    log4net.Config.XmlConfigurator.Configure();

    ILog log = LogManager.GetLogger("test");

    log.Debug("调试信息");


    4、运行结果


    截止此处,日志保存成功。


    640?wx_fmt=png


    三、初始化配置文件


    前面提到在默认配置文件中App.config(B/S程序则为web.config)中进行配置,可以通过代码  log4net.Config.XmlConfigurator.Configure(); 来初始化配置,或者还可以通过 [assembly: log4net.Config.XmlConfigurator()]  反射的形式进行初始化配置,二者可以达到同样的效果,代表了两种初始化配置文件的形式。


    PS: [assembly: log4net.Config.XmlConfigurator()]  可以加在 当前使用文件的 namespace上作用于当前文件,或者加在Properties/AssemblyInfo.cs中,则该项目全局都无须再初始化了。


    640?wx_fmt=png

     

    在实际项目中,默认的配置文件里可能包含很多框架的信息,这个时候把 log4net的配置代码再放入进去,就会显得有点杂乱,或者有些“奇葩”的人把默认配置文件改名了,这个时候使用上述默认的两种方式就不好用了,那么这种情况怎么处理呢?


    这里重点介绍 通过 log4net.Config.XmlConfigurator.Configure(); 来关联配置文件。


    情况一: 使用默认配置文件的情况


    1、代码配置:log4net.Config.XmlConfigurator.Configure();

    2、反射配置:[assembly: log4net.Config.XmlConfigurator()] 


    情况二:修改默认配置文件的名称为:App1.config (这里只是举例,很少有修改默认配置文件名称的)


    1、代码配置: 首先将App1.config文件的属性中的“生成操作”改为“ 嵌入的资源”,然后通过以下代码进行配置。


    Assembly assembly = Assembly.GetExecutingAssembly();

    var xml = assembly.GetManifestResourceStream("_01_SimpleDemo.App1.config");

    log4net.Config.XmlConfigurator.Configure(xml);


    注:代码中的 _01_SimpleDemo 为命名空间名。


    2、反射配置:[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.xml")]     


    注:用这种方式属性中的:复制到输出目录需要改为:始终复制,生成操作不需要配置,使用默认:无  即可


    640?wx_fmt=png

     

    情况三:新建单独xml文件,进行log4net的配置 (推荐采用这种方式,和原配置文件区分开,单独配置方便,处理方式和情况二是一致的)


    1、代码配置:首先将log4net.xml文件的属性中的“生成操作”改为“ 嵌入的资源”,然后通过以下代码进行配置。


    Assembly assembly = Assembly.GetExecutingAssembly();

    var xml = assembly.GetManifestResourceStream("_01_SimpleDemo.log4net.xml");

    log4net.Config.XmlConfigurator.Configure(xml);


    注:代码中的 _01_SimpleDemo 为命名空间名。


    情况四:无论是修改默认配置文件的名称为 或者 新建单独的xml作为配置文件 → 可以通过绝对路径的方式进行处理 【不推荐这种方式】


    1、直接写绝对路径 (注意这种方式【不需要】配置文件属性为 “嵌入的资源”)


    log4net.Config.XmlConfigurator.Configure(new FileInfo(@"D:-我的开发之路DotNet体系-DotNet框架篇-Log4net详解Code-SimpleDemolog4net.xml"));


    2 通过代码获取绝对路径 (注意这种方式【不需要】配置文件属性的“生成操作”改为 “嵌入的资源”,但需要改为“始终复制”,确保输出到bin文件下)


    string assemblyFilePath = Assembly.GetExecutingAssembly().Location;

    string assemblyDirPath = Path.GetDirectoryName(assemblyFilePath);

    string configFilePath = assemblyDirPath + " //log4net.xml";

    log4net.Config.XmlConfigurator.Configure(new FileInfo(configFilePath));


    PS:B/S程序下通过  log4net.Config.XmlConfigurator.Configure(new FileInfo(Server.MapPath("~") + @"/log4net.xml")); 来配置。


    四、代码调用详解


    Log4net允许多个ILog对象同时存在,通过代码:ILog log = LogManager.GetLogger("xxx"); 来创建。


    A: 日志级别由高到低分别为:FATAL(致命错误) > ERROR(一般错误) > WARN(警告) > INFO(一般信息) > DEBUG(调试信息),另外还有 OFF和 ALL 。


    几点说明:OFF表示所有信息都不写入,ALL表示所有信息都写入,我们也可以通过:<root><level value = "WARN" ></ level ></root>这样配置,表示WARN级别以及高于WARN以上的级别才会被写入日志。


    B: 写入日志的方法有:Debug、Error、Fatal、Info、Warn五个方法,每个方法都有两个重载,如下图:


    640?wx_fmt=png


    分享在使用配置文件为log4net.xml的情况下的调用代码:


    Assembly assembly = Assembly.GetExecutingAssembly();

    var xml = assembly.GetManifestResourceStream("_01_SimpleDemo.log4net.xml");

    log4net.Config.XmlConfigurator.Configure(xml);

    ILog log = LogManager.GetLogger("test");

    log.Debug("调试信息");

    log.Info("一般信息");

    log.Warn("警告");

    try

    {

       int.Parse("ddd");

    }

    catch (Exception ex)

    {

        log.Error("一般错误", ex);

    }

    log.Fatal("致命错误");


    五、配置文件详解


    Log4net的配置文件主要分为两大部分:分别是 【自定义配置节点】和 

    【核心代码配置】,自定义配置节点代码固定,如下图,核心代码配置主要位于:<log4net></log4net>节点中,里面包括<appender></appender>节点配置日日志输出途径 和 <root></root>节点,用于设置记录日志的级别和启用哪些输出途径。  


    640?wx_fmt=png


    几点说明:


    1、自定义配置节点  <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> 代码固定,直接复制即可。


    2、<root></root> 节点主要用来: 配置日志的的输出级别和加载日志的输出途径。


    A: level中的value值表示该值及其以上的日志级别才会输出,日志级别包括:OFF > FATAL(致命错误) > ERROR(一般错误) > WARN(警告) > INFO(一般信息) > DEBUG(调试信息) > ALL ,比如:


    <level value="INFO"></level> 表示只有INFO及其以上的日志级别才会被保存。

    PS:OFF表示所有信息都不写入,ALL表示所有信息都写入。


    B: <appender-ref></appender-ref>标签用于加载日志的输出途径代码,通过ref和appender标签的中name属性相关联,比如:


    <appender-ref ref="RollingFileAppender"></appender-ref>  表示开启txt文档保存日志的方式。


    3、<appender></appender>节点,用来配置日志的输出途径的,本节主要介绍了输出到 【txt文本文档】中 和 【数据库】。


    A:分享一下数据库的表结构,详细配置见下面的代码分享,需要注意字段类型相匹配,并且要显式指定其长度。


    640?wx_fmt=png

     

    B:关于txt文本文档的命名,可以存放到一个文件夹里,也可以按照时间来区分文件夹,并且命名可以 动态+指定命名的方式。


    640?wx_fmt=png


    C:关于日志文件大小的说明和文件个数的说明,主要需要三个节点配合使用(实际开发中,如果一个txt特别大,打开的时候会非常的慢,卡顿,所以该步骤有必要配置一下)。


    PS:首先要配置 RollingStyle 节点为Size模式或者Composite模式,然后配置 maximumFileSize 节点设置每个文件的大小,最后配置 MaxSizeRollBackups 节点,设置日志文件的个数。超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。


    用下面的代码简单测试一下:


    <param name="RollingStyle" value="Composite" />

    <param name="maximumFileSize" value="10KB" />

    <param name="MaxSizeRollBackups" value="5" />


    640?wx_fmt=png


    详细代码如下:


    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

      <!-- 一. 添加log4net的自定义配置节点-->

      <configSections>

        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />

      </configSections>

      <!--二. log4net的核心配置代码-->

      <log4net>

        <!--(一) 配置日志的输出途径-->

        <!--1. 输出途径(一) 将日志以回滚文件的形式写到文件中-->

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

          <!--1.1 文件夹的位置(也可以写相对路径)-->

          <param name="File"  value="D:MyLog1" />

          <!--相对路径  C/S程序生成在Debug目录下-->

          <!--<param name="File"  value="/Logs/" />-->

          <!--1.2 是否追加到文件-->

          <param name="AppendToFile" value="true" />

          <!--1.3 使用最小锁定模型(minimal locking model),以允许多个进程可以写入同一个文件 -->

          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

          <!--1.4 配置Unicode编码-->

          <Encoding value="UTF-8" />

          <!--1.5 是否只写到一个文件里-->

          <param name="StaticLogFileName" value="false" />

          <!--1.6 配置按照何种方式产生多个日志文件 (Date:日期、Size:文件大小、Composite:日期和文件大小的混合方式)-->

          <param name="RollingStyle" value="Composite" />

          <!--1.7 介绍多种日志的的命名和存放在磁盘的形式-->

          <!--1.7.1 在根目录下直接以日期命名txt文件 注意&quot;的位置,去空格 -->

          <param name="DatePattern" value="yyyy-MM-dd&quot;.log&quot;" />

          <!--1.7.2 在根目录下按日期产生文件夹,文件名固定 test.log  -->

          <!--<param name="DatePattern" value="yyyy-MM-dd/&quot;test.log&quot;"  />-->

          <!--1.7.3 在根目录下按日期产生文件夹,这是按日期产生文件夹,并在文件名前也加上日期  -->

          <!--<param name="DatePattern" value="yyyyMMdd/yyyyMMdd&quot;-test.log&quot;"  />-->

          <!--1.7.4 在根目录下按日期产生文件夹,这再形成下一级固定的文件夹  -->

          <!--<param name="DatePattern" value="yyyyMMdd/&quot;OrderInfor/test.log&quot;"  />-->

          <!--1.8 配置每个日志的大小。【只在1.6 RollingStyle 选择混合方式与文件大小方式下才起作用!!!】可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志,

          超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。-->

          <param name="maximumFileSize" value="10MB" />

          <!--1.9 最多产生的日志文件个数,超过则保留最新的n个 将value的值设置-1,则不限文件个数 【只在1.6 RollingStyle 选择混合方式与文件大小方式下才起作用!!!】

            与1.8中maximumFileSize文件大小是配合使用的-->

          <param name="MaxSizeRollBackups" value="5" />

          <!--1.10 配置文件文件的布局格式,使用PatternLayout,自定义布局-->

          <layout type="log4net.Layout.PatternLayout">

            <conversionPattern value="记录时间:%date %n线程ID:[%thread] %n日志级别:%-5level %n出错类:%logger property: [%property{NDC}] - %n错误描述:%message%newline %n%newline"/>

          </layout>

        </appender>


        <!--2. 输出途径(二) 记录日志到数据库-->

        <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">

          <!--2.1 设置缓冲区大小,只有日志记录超设定值才会一块写入到数据库-->

          <param name="BufferSize" value="1" />

          <!--2.2 引用-->

          <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

          <!--2.3 数据库连接字符串-->

          <connectionString value="data source=localhost;initial catalog=LogDB;integrated security=false;persist security info=True;User ID=sa;Password=123456" />

          <!--2.4 SQL语句插入到指定表-->

          <commandText value="INSERT INTO LogInfor ([threadId],[log_level],[log_name],[log_msg],[log_exception],[log_time]) VALUES (@threadId, @log_level, @log_name, @log_msg, @log_exception,@log_time)" />

          <!--2.5 数据库字段匹配-->

          <!-- 线程号-->

          <parameter>

            <parameterName value="@threadId" />

            <dbType value="String" />

            <size value="100" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%thread" />

            </layout>

          </parameter>

          <!--日志级别-->

          <parameter>

            <parameterName value="@log_level" />

            <dbType value="String" />

            <size value="100" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%level" />

            </layout>

          </parameter>

          <!--日志记录类名称-->

          <parameter>

            <parameterName value="@log_name" />

            <dbType value="String" />

            <size value="100" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%logger" />

            </layout>

          </parameter>

          <!--日志信息-->

          <parameter>

            <parameterName value="@log_msg" />

            <dbType value="String" />

            <size value="5000" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%message" />

            </layout>

          </parameter>

          <!--异常信息  指的是如Infor 方法的第二个参数的值-->

          <parameter>

            <parameterName value="@log_exception" />

            <dbType value="String" />

            <size value="2000" />

            <layout type="log4net.Layout.ExceptionLayout" />

          </parameter>

          <!-- 日志记录时间-->

          <parameter>

            <parameterName value="@log_time" />

            <dbType value="DateTime" />

            <layout type="log4net.Layout.RawTimeStampLayout" />

          </parameter>

        </appender>

        <!--(二). 配置日志的的输出级别和加载日志的输出途径-->

        <root>

          <!--1. level中的value值表示该值及其以上的日志级别才会输出-->

          <!--OFF > FATAL(致命错误) > ERROR(一般错误) > WARN(警告) > INFO(一般信息) > DEBUG(调试信息)  > ALL  -->

          <!--OFF表示所有信息都不写入,ALL表示所有信息都写入-->

          <level value="ALL"></level>

          <!--2. append-ref标签表示要加载前面的日志输出途径代码  通过ref和appender标签的中name属性相关联-->

          <appender-ref ref="RollingFileAppender"></appender-ref>

          <appender-ref ref="AdoNetAppender"></appender-ref>

        </root>

      </log4net>

    </configuration>


    六、简单的封装及完整代码分享


    这里模拟在系统框架中对Log4net进行简单的封装,然后在MVC框架中调用,并分享全部代码。


    步骤一:新建Ypf.Utils类库,作为工具类库,引入log4net程序集,并将前面用到的log4net.xml 复制进来,改属性为嵌入资源,然后新建LogUtils类(不要起名为LogHelp),对Log4net的方法进行简单的封装,主要包括:初始化代码、ILog实例创建、五类日志级别的封装。


    640?wx_fmt=png


     log4net.xml文件代码如下:


     <?xml version="1.0" encoding="utf-8" ?>

     <configuration>

       <!-- 一. 添加log4net的自定义配置节点-->

       <configSections>

         <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />

       </configSections>

       <!--二. log4net的核心配置代码-->

       <log4net>

         <!--(一) 配置日志的输出途径-->

         <!--1. 输出途径(一) 将日志以回滚文件的形式写到文件中-->

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

           <!--1.1 文件夹的位置(也可以写相对路径)-->

           <param name="File"  value="D:MyLog1" />

           <!--相对路径-->

           <!--<param name="File"  value="Logs/" />-->

           <!--1.2 是否追加到文件-->

           <param name="AppendToFile" value="true" />

           <!--1.3 使用最小锁定模型(minimal locking model),以允许多个进程可以写入同一个文件 -->

           <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

           <!--1.4 配置Unicode编码-->

           <Encoding value="UTF-8" />

           <!--1.5 是否只写到一个文件里-->

           <param name="StaticLogFileName" value="false" />

           <!--1.6 配置按照何种方式产生多个日志文件 (Date:日期、Size:文件大小、Composite:日期和文件大小的混合方式)-->

           <param name="RollingStyle" value="Composite" />

           <!--1.7 介绍多种日志的的命名和存放在磁盘的形式-->

           <!--1.7.1 在根目录下直接以日期命名txt文件 注意&quot;的位置,去空格 -->

           <param name="DatePattern" value="yyyy-MM-dd&quot;.log&quot;" />

           <!--1.7.2 在根目录下按日期产生文件夹,文件名固定 test.log  -->

           <!--<param name="DatePattern" value="yyyy-MM-dd/&quot;test.log&quot;"  />-->

           <!--1.7.3 在根目录下按日期产生文件夹,这是按日期产生文件夹,并在文件名前也加上日期  -->

           <!--<param name="DatePattern" value="yyyyMMdd/yyyyMMdd&quot;-test.log&quot;"  />-->

           <!--1.7.4 在根目录下按日期产生文件夹,这再形成下一级固定的文件夹  -->

           <!--<param name="DatePattern" value="yyyyMMdd/&quot;OrderInfor/test.log&quot;"  />-->

           <!--1.8 配置每个日志的大小。【只在1.6 RollingStyle 选择混合方式与文件大小方式下才起作用!!!】可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志,

           超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。-->

           <param name="maximumFileSize" value="10MB" />

           <!--1.9 最多产生的日志文件个数,超过则保留最新的n个 将value的值设置-1,则不限文件个数 【只在1.6 RollingStyle 选择混合方式与文件大小方式下才起作用!!!】

             与1.8中maximumFileSize文件大小是配合使用的-->

           <param name="MaxSizeRollBackups" value="5" />

           <!--1.10 配置文件文件的布局格式,使用PatternLayout,自定义布局-->

           <layout type="log4net.Layout.PatternLayout">

             <conversionPattern value="记录时间:%date %n线程ID:[%thread] %n日志级别:%-5level %n出错类:%logger property: [%property{NDC}] - %n错误描述:%message%newline %n%newline"/>

           </layout>

         </appender>

     

         <!--2. 输出途径(二) 记录日志到数据库-->

         <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">

           <!--2.1 设置缓冲区大小,只有日志记录超设定值才会一块写入到数据库-->

           <param name="BufferSize" value="1" />

           <!--2.2 引用-->

           <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

           <!--2.3 数据库连接字符串-->

           <connectionString value="data source=localhost;initial catalog=LogDB;integrated security=false;persist security info=True;User ID=sa;Password=123456" />

           <!--2.4 SQL语句插入到指定表-->

           <commandText value="INSERT INTO LogInfor ([threadId],[log_level],[log_name],[log_msg],[log_exception],[log_time]) VALUES (@threadId, @log_level, @log_name, @log_msg, @log_exception,@log_time)" />

          <!--2.5 数据库字段匹配-->

          <!-- 线程号-->

          <parameter>

            <parameterName value="@threadId" />

            <dbType value="String" />

            <size value="100" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%thread" />

            </layout>

          </parameter>

          <!--日志级别-->

          <parameter>

            <parameterName value="@log_level" />

            <dbType value="String" />

            <size value="100" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%level" />

            </layout>

          </parameter>

          <!--日志记录类名称-->

          <parameter>

            <parameterName value="@log_name" />

            <dbType value="String" />

            <size value="100" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%logger" />

            </layout>

          </parameter>

          <!--日志信息-->

          <parameter>

            <parameterName value="@log_msg" />

            <dbType value="String" />

            <size value="5000" />

            <layout type="log4net.Layout.PatternLayout">

              <conversionPattern value="%message" />

            </layout>

          </parameter>

          <!--异常信息  指的是如Infor 方法的第二个参数的值-->

          <parameter>

            <parameterName value="@log_exception" />

            <dbType value="String" />

            <size value="2000" />

            <layout type="log4net.Layout.ExceptionLayout" />

          </parameter>

          <!-- 日志记录时间-->

          <parameter>

            <parameterName value="@log_time" />

            <dbType value="DateTime" />

            <layout type="log4net.Layout.RawTimeStampLayout" />

          </parameter>

        </appender>

        <!--(二). 配置日志的的输出级别和加载日志的输出途径-->

        <root>

          <!--1. level中的value值表示该值及其以上的日志级别才会输出-->

          <!--OFF > FATAL(致命错误) > ERROR(一般错误) > WARN(警告) > INFO(一般信息) > DEBUG(调试信息)  > ALL  -->

          <!--OFF表示所有信息都不写入,ALL表示所有信息都写入-->

          <level value="ALL"></level>

          <!--2. append-ref标签表示要加载前面的日志输出途径代码  通过ref和appender标签的中name属性相关联-->

          <appender-ref ref="RollingFileAppender"></appender-ref>

          <appender-ref ref="AdoNetAppender"></appender-ref>

        </root>

      </log4net>

    </configuration>


    LogUtils类代码如下:


    using log4net;

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Reflection;

    using System.Text;

    using System.Threading.Tasks;


    namespace Ypf.Utils

    {

        public class LogUtils

        {

            //可以声明多个日志对象

            public static ILog log = LogManager.GetLogger(typeof(LogUtils));


            #region 01-初始化Log4net的配置

            /// <summary>

            /// 初始化Log4net的配置

            /// xml文件一定要改为嵌入的资源

            /// </summary>

            public static void InitLog4Net()

            {

                Assembly assembly = Assembly.GetExecutingAssembly();

                var xml = assembly.GetManifestResourceStream("Ypf.Utils.log4net.xml");

                log4net.Config.XmlConfigurator.Configure(xml);

            }

            #endregion





            /************************* 五种不同日志级别 *******************************/

            //FATAL(致命错误) > ERROR(一般错误) > WARN(警告) > INFO(一般信息) > DEBUG(调试信息)


            #region 01-DEBUG(调试信息)

            /// <summary>

            /// Debug

            /// </summary>

            /// <param name="msg">日志信息</param>

            public static void Debug(string msg)

            {

                log.Debug(msg);

            }

            /// <summary>

            /// Debug

            /// </summary>

            /// <param name="msg">日志信息</param>

            /// <param name="exception">错误信息</param>

            public static void Debug(string msg, Exception exception)

            {

                log.Debug(msg, exception);

            }


            #endregion


            #region 02-INFO(一般信息)

            /// <summary>

            /// Info

            /// </summary>

            /// <param name="msg">日志信息</param>

            public static void Info(string msg)

            {

                log.Info(msg);

            }

            /// <summary>

            /// Info

            /// </summary>

            /// <param name="msg">日志信息</param>

            /// <param name="exception">错误信息</param>

            public static void Info(string msg, Exception exception)

            {

                log.Info(msg, exception);

            }

            #endregion


            #region 03-WARN(警告)

            /// <summary>

            /// Warn

            /// </summary>

            /// <param name="msg">日志信息</param>

            public static void Warn(string msg)

            {

                log.Warn(msg);

            }

            /// <summary>

            /// Warn

            /// </summary>

            /// <param name="msg">日志信息</param>

            /// <param name="exception">错误信息</param>

            public static void Warn(string msg, Exception exception)

            {

                log.Warn(msg, exception);

            }

            #endregion


            #region 04-ERROR(一般错误)

            /// <summary>

            /// Error

            /// </summary>

            /// <param name="msg">日志信息</param>

            public static void Error(string msg)

            {

                log.Error(msg);

            }

            /// <summary>

            /// Error

            /// </summary>

            /// <param name="msg">日志信息</param>

            /// <param name="exception">错误信息</param>

            public static void Error(string msg, Exception exception)

            {

                log.Error(msg, exception);

            }

            #endregion


            #region 05-FATAL(致命错误)

            /// <summary>

            /// Fatal

            /// </summary>

            /// <param name="msg">日志信息</param>

            public static void Fatal(string msg)

            {

                log.Fatal(msg);

            }

            /// <summary>

            /// Fatal

            /// </summary>

            /// <param name="msg">日志信息</param>

            /// <param name="exception">错误信息</param>

            public static void Fatal(string msg, Exception exception)

            {

                log.Fatal(msg, exception);

            }


            #endregion

        }

    }


    步骤二:新建名Ypf.MVC的MVC5框架,添加对Ypf.Utils类库的引用,在Global.asax全局文件中添加对 对Log4net进行初始化。


    640?wx_fmt=png


    然后就可以愉快的进行调用测试了哦。


    /// <summary>

    /// 测试log4net

    /// 首先需要再Global中初始化log4net

    /// </summary>

    /// <returns></returns>

    public ActionResult Index()

    {

        //FATAL(致命错误) > ERROR(一般错误) > WARN(警告) > INFO(一般信息) > DEBUG(调试信息)

        LogUtils.Debug("出错了");

        try

        {

            int.Parse("ddf");

        }

        catch (Exception ex)

        {

            LogUtils.Debug("出错了",ex);

        }


        LogUtils.Info("出错了");

        try

        {

            int.Parse("ddf");

        }

        catch (Exception ex)

        {

            LogUtils.Info("出错了", ex);

        }


        LogUtils.Warn("出错了");

        try

        {

            int.Parse("ddf");

        }

        catch (Exception ex)

        {

            LogUtils.Warn("出错了", ex);

        }


        LogUtils.Error("出错了");

        try

        {

            int.Parse("ddf");

        }

        catch (Exception ex)

        {

            LogUtils.Error("出错了", ex);

        }


        LogUtils.Fatal("出错了");

        try

        {

            int.Parse("ddf");

        }

        catch (Exception ex)

        {

            LogUtils.Fatal("出错了", ex);

        }

        return View();

    }


    看完本文有收获?请转发分享给更多人~



    展开全文
  • .NET日志框架Log4Net小结

    万次阅读 2018-03-22 14:06:25
    Log4net强大的地方就是它的多目标输出,可以输出到控制台、文件、数据库、系统事件、Email等,几乎无所不能。然后它可以通过配置让日志系统实时生效,比如说在服务运行的过程中修改配置改变输出目标,改变日志等级等...
  • Log4net简介 前言 项目开发中,记录项目日志是必须的,如果非要说日志的重要性(日志可看做,飞机的黑匣子,或者汽车的行车记录仪),根据等级进行记录,方便我们排查相关问题,以后项目运维中,也方便很多。基本上...
  • log4net使用详解

    万次阅读 多人点赞 2017-04-25 08:56:36
    说明:本程序演示如何利用log4net记录程序日志信息。log4net是一个功能著名的开源日志记录组件。利用log4net可以方便地将日志信息记录到文件、控制台、Windows事件日志和数据库(包括MS SQL Server, Access, Oracle...
  • 前言:记录系统中的日志,是一个好的项目产品必备的一个环节。每一个产品最终的目的都是要交予客户使用,因为程序员代码的开发水平参差不齐,Bug就成为了项目运维成本最大的因素之一。如何降低项目...
  • C#使用Log4net输出日志

    万次阅读 2018-11-16 10:09:31
    apache下载地址:https://logging.apache.org/log4net/download_log4net.cgi 将下载后的文件解压,在bin\net目录下找到程序所需的对应版本 将该版本中的“log4net.dll”引用到程序中 并在所需要记录日志的命名...
  • 一分钟学会 log4net(c#) 配置及使用

    万次阅读 多人点赞 2014-05-15 09:46:56
    初次由java转做c#项目,研究了一下log4net的使用。 1. 首先从apache网站下载log4net, http://logging.apache.org/log4net/download_log4net.cgi 。我下的是最新版本 log4net-1.2.11-bin-newkey 2. 将 \bin\...
  • C#日志系统 Log4net使用总结

    万次阅读 2017-08-11 20:22:22
    .net 日志系统官网:https://logging.apache.org/有了log4j2的基础,log4net使用也类似,很容易让JAVA程序员上手。1.通过NuGet下载依赖包 log4net 2.0.82.创建配置文件 log4net.config,放置到源代码src下,要运行起来...
  • mybatis结合log4j打印SQL日志

    万次阅读 热门讨论 2017-01-18 17:45:42
    mybatis结合log4j打印SQL日志 默认的mybatis不能打印出SQL日志,不便于查看调试,需要结合log4jdbc-log4j2就可以完整的输入SQL的调试信息。pom.xml 配置maven,注意以下3个都需要 org.bgee.log4jdbc-log4j2 log4...
  • log4net不输出日志的原因及解决方案

    万次阅读 2018-10-12 08:58:02
    log4net不输出日志文件主要有以下几个原因: 1 没有在AssemblyInfo文件中添加下面的代码: [assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)] 2 运行程序目录下...
  • 问题: 调用log4net写日志  程序正常运行无报错,但是发现没有log日志 尝试方案:[assembly: log4net.Config.XmlConfigurator(Watch = true)] (无效) 解决方案: 1.确保正确引用log4net文件夹 2...
  • log4net 配置文件相对路径配置

    万次阅读 2016-01-08 15:52:51
    log4net 配置文件相对路径配置本写主要方向为对配置文件放在相对位置,并非程序(项目)根目录下的的配置方法。
  • 引言: 在项目中使用了MyBatis,一个比较苦恼的问题是无法看到执行的SQL的具体情况,所以,就找到了Log4jdbc-log4j2。这个是一个基于jdbc层面的监听工具,可以监听对于数据库的主要操作,从而完美的查看到其中执行的...
  • log4j生成有日期的日志文件名

    万次阅读 热门讨论 2009-06-25 11:17:00
    log4j生成日志,担心天长日久如果生成到一个文件里面有...解决方法很简单:log4j.appender.file=org.apache.log4j.DailyRollingFileAppender#log4j.appender.file.File=hibernate.loglog4j.appender.file.File=../we
  • log4net自动删除日志文件【实现】

    万次阅读 2017-10-24 14:06:52
    根据上一篇的思路,简单完成了根据时间设置,自动删除过期的日志文件,测试...直接在log4net的配置文件中添加一个属性,用来设置过期时间长度(单位:天),见下图: 我这里测试,设置过期时间是5天,效果如下图:
  • log4net(c#) 配置及使用

    万次阅读 2018-08-16 10:25:24
    1.引入库log4net.dll ...展开项目文件下的Properties文件夹,打开AssemblyInfo.cs并在AssemblyInfo.cs中添加一行:在AssemblyInfo.cs中添加一行:(其中log4net.config对应配置文件名) [a...
1 2 3 4 5 ... 20
收藏数 186,908
精华内容 74,763
关键字:

log4net