使用log4net记录本地日志及自定义扩展输出

简单介绍一下log4net的主要组成,详细说明可以参考https://blog.csdn.net/binnygoal/article/details/79557746

1.Logger

Logger是直接和应用程序交互的组件,是负责日志的记录者,可以同时存在多个Logger,然后由它引用的Appender记录到指定的媒介,并由Layout控制输出格式。

2.Appender

Appender用来定义日志的输出方式,即提供记录介质,如记录到数据库,记录到本地文件,输出到控制台等等。

3.Layout

Layout用于控制Appender的输出格式(格式化记录数据),可以是线性的也可以是XML。

4.Filter

Filter负责记录筛选,可以过滤掉Appender输出的内容。

总体流程:Logger发出记录信息,Appender接到信息,根据内部的Layout配置对记录信息格式化,然后根据Filter对记录信息进行筛选,最后将其记录到指定介质中。

简单配置log4net

第一步:在项目中添加log4net.dll的引用;

第二步:配置log4net.config文件;

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <log4net>
    <logger name="ErrorLogger">
      <level value="WARN" />
      <appender-ref ref="ErrorAppender" />
    </logger>
    <logger name="DebugLogger">
      <level value="DEBUG" />
      <appender-ref ref="DebugAppender" />      
    </logger>    
    <logger name="InfoLogger">
      <level value="INFO" />
      <appender-ref ref="InfoAppender" />
    </logger>    
    <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
      <!--日志文件路径,文件夹不存在则新建 -->
      <file value="D://THS//logs//" />
      <!--是否追加到文件-->
      <appendToFile value="true" />
      <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <!--最多产生的日志文件数,超过则只保留最新的n+1个-->
      <maxSizeRollBackups value="1" />
      <!--每个文件的大小,只在混合方式与文件大小方式下使用,超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入,没带数字最晚写入-->
      <maximumFileSize value="256MB" />
      <!--是否只写到一个文件中-->
      <staticLogFileName value="false"/>
      <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
      <rollingStyle value="Composite" />
      <!--是否保存日志文件的扩展名-->
      <preserveLogFileNameExtension value="true" />
      <!--按日期产生文件夹,文件名固定。注意&quot; 的位置-->      
      <datePattern value="yyyy-MM-dd/&quot;SysInfo.log&quot;" />
      <!--记录的格式。一般用log4net.Layout.PatternLayout布局-->
      <!--此处用继承了log4net.Layout.PatternLayout的自定义布局,LogTest.Log为命名空间。%Property{LineLocation}、%Property{Method}等是自定义的输出-->
      <layout type="LogTest.Log.Z_PatternLayout">
        <conversionPattern value="日志时间:%Property{Time} %n记录方法:[%thread]%Property{Method} Line:%Property{LineLocation} %n日志信息:%Property{Message} %n%n" />
      </layout>
      <!--过滤设置,LevelRangeFilter为使用的过滤器。-->
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="INFO" />
        <param name="LevelMax" value="INFO" />
      </filter>      
    </appender>    
    <appender name="DebugAppender" type="log4net.Appender.RollingFileAppender">
      <file value="D://THS//logs//" />
      <appendToFile value="true" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <maxSizeRollBackups value="30" />
      <staticLogFileName value="false"/>
      <rollingStyle value="Date" />
      <preserveLogFileNameExtension value="true" />
      <datePattern value="yyyy-MM-dd/&quot;SysDebug.log&quot;" />
      <layout type="LogTest.Log.Z_PatternLayout">
        <conversionPattern value="日志时间:%Property{Time} %n记录方法:[%thread]%Property{Method} Line:%Property{LineLocation} %n日志信息:%Property{Message} %n%n" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="DEBUG" />
        <param name="LevelMax" value="DEBUG" />
      </filter>
    </appender>   
    <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
      <file value="D://THS//logs//" />
      <appendToFile value="true" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <maxSizeRollBackups value="30" />
      <staticLogFileName value="false"/>
      <rollingStyle value="Date" />
      <preserveLogFileNameExtension value="true" />
      <datePattern value="yyyy-MM-dd/&quot;SysError.log&quot;" />
      <layout type="LogTest.Log.Z_PatternLayout">
        <conversionPattern value="日志时间:%Property{Time} %n日志级别:%-5level %n记录方法:[%thread]%Property{Method} Line:%Property{LineLocation} %n日志信息:%Property{Message} %n异常信息:%exception %n%n" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="WARN" />
        <param name="LevelMax" value="FATAL" />
      </filter>
    </appender>  
  </log4net>
</configuration>

 注意,注意,注意:修改log4net.config文件属性“复制到输出目录”为“始终复制”,否则不会生成日志文件夹;

第三步:如果是使用自动以配置文件,则在AssemblyInfo.cs中添加关联配置文件代码

// 使用配置文件log4net.config,监视改变
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]

如果是在默认App.config文件中配置log4net,则可以直接在Program.cs中的Main方法中添加:

log4net.Config.XmlConfigurator.Configure();

第四步:自定义扩展输出,通过继承log4net.Layout.PatternLayout类,使用log4net.Core.LoggingEvent类的方法得到了要输出的LogEntity类的名称,然后通过反射得到各个属性的值,使用PatternLayout类AddConverter方法传入得到的值。注意Appender中的Layout type要引用用到的类的命名空间以及类名。

1.创建LogEntity实体类(自定义输出属性)

namespace LogTest.Log
{
    public class Z_LogEntity
    {
        /// <summary>
        /// 引发日志事件的行号
        /// </summary>
        public string LineLocation { get; set; }

        /// <summary>
        /// 应用程序提供给日志事件的消息
        /// </summary>
        public string Message { get; set; }

        /// <summary>
        /// 引发日志事件的方法(包括类名和方法名)
        /// </summary>
        public string Method { get; set; }

        /// <summary>
        /// 引发日志事件的时间(格式化)
        /// </summary>
        public string Time { get; set; }
    }
}

2.继承PatternLayoutConvert重写转换器

using log4net.Core;
using log4net.Layout.Pattern;
using System.IO;
using System.Reflection;

namespace LogTest.Log
{
    public class Z_PatternConvert : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
        {
            if (Option != null)
                // 写入指定键的值
                WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent));
            else
                // 写入所有关键值对
                WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties());
        }

        /// <summary>
        /// 通过反射获取传入的日志对象的某个属性
        /// </summary>
        private object LookupProperty(string property, LoggingEvent loggingEvent)
        {
            object propertyValue = string.Empty;
            PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property);

            if (propertyInfo != null)
                propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null);

            return propertyValue;
        }
    }
}

3.继承PatternLayout,添加转换器到实例中

using log4net.Layout;

namespace LogTest.Log
{
    public class Z_PatternLayout : PatternLayout
    {
        public Z_PatternLayout()
        {
            this.AddConverter("Property", typeof(Z_PatternConvert));
        }
    }
}

第五步:编写LogHelper类

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace LogTest.Log
{
    public class LogHelper
    {
        /// <summary>
        ///  静态只读实例化对象DebugLogger
        /// </summary>
        public static readonly log4net.ILog DebugLog = log4net.LogManager.GetLogger("DebugLogger");

        /// <summary>
        ///  静态只读实例化对象ErrorLogger
        /// </summary>
        public static readonly log4net.ILog ErrorLog = log4net.LogManager.GetLogger("ErrorLogger");

        /// <summary>
        /// 静态只读实例化对象InfoLogger
        /// </summary>
        public static readonly log4net.ILog InfoLog = log4net.LogManager.GetLogger("InfoLogger");

        private static Z_LogEntity logEntity = new Z_LogEntity();

        public static Z_LogEntity BuildLogEntity(string message, [CallerLineNumber] int lineNum = 0, [CallerMemberName] string method = "")
        {
            logEntity.Time = DateTime.Now.ToString("HH:mm:ss:fff");
            logEntity.Message = message;
            logEntity.LineLocation = lineNum.ToString();
            logEntity.Method = (new StackTrace()).GetFrame(1).GetMethod().ReflectedType.Name + "." + method;
            return logEntity;
        }

        public static void WriteInfo(Z_LogEntity logEntity)
        {
            try
            {
                if (InfoLog.IsInfoEnabled)
                {
                    InfoLog.Info(logEntity);
                }
            }
            catch { }
        }

        public static void WriteDebug(Z_LogEntity logEntity)
        {
            try
            {
                if (DebugLog.IsDebugEnabled)
                {
                    DebugLog.Debug(logEntity);
                }
            }
            catch { }
        }

        public static void WriteWarn(Z_LogEntity logEntity)
        {
            try
            {
                if (ErrorLog.IsWarnEnabled)
                {
                    ErrorLog.Warn(logEntity);
                }
            }
            catch { }
        }

        public static void WriteWarn(Z_LogEntity logEntity, Exception ex)
        {
            try
            {
                if (ErrorLog.IsWarnEnabled)
                {
                    ErrorLog.Warn(logEntity, ex);
                }
            }
            catch { }
        }

        public static void WriteError(Z_LogEntity logEntity)
        {
            try
            {
                if (ErrorLog.IsErrorEnabled)
                {
                    ErrorLog.Error(logEntity);
                }
            }
            catch { }
        }

        public static void WriteError(Z_LogEntity logEntity, Exception ex)
        {
            try
            {
                if (ErrorLog.IsErrorEnabled)
                {
                    ErrorLog.Error(logEntity, ex);
                }
            }
            catch { }
        }

        public static void WriteFatal(Z_LogEntity logEntity)
        {
            try
            {
                if (ErrorLog.IsFatalEnabled)
                {
                    ErrorLog.Fatal(logEntity);
                }
            }
            catch { }
        }

        public static void WriteFatal(Z_LogEntity logEntity, Exception ex)
        {
            try
            {
                if (ErrorLog.IsFatalEnabled)
                {
                    ErrorLog.Fatal(logEntity, ex);
                }
            }
            catch { }
        }
    }
}

第六步:程序中使用

// 记录Info级别数据
LogHelper.WriteInfo(LogHelper.BuildLogEntity("程序运行记录写入!"));

// 记录Debug级别数据
LogHelper.WriteDebug(LogHelper.BuildLogEntity("调试信息数据写入!"));

// 记录Warn级别数据
LogHelper.WriteWarn(LogHelper.BuildLogEntity("警告数据写入!"),new Exception("对应的错误信息!"));

// 记录Error级别数据
 LogHelper.WriteError(LogHelper.BuildLogEntity("一般错误数据写入!"), new Exception("对应的错误信息!"));

// 记录Fatal级别数据
LogHelper.WriteFatal(LogHelper.BuildLogEntity("致命错误数据写入!"), new Exception("对应的错误信息!"));
原文地址:https://www.cnblogs.com/zhengzc/p/11138566.html