• C# 使用Log4net记录日志


    1.Log4net.config详解

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
      </configSections>
      <log4net>
        <!-- ConversionPattern 解释
    %m(message):输出的日志消息,如ILog.Debug(…)输出的一条消息
    %n(new line):換行
    %d(datetime):输出当前语句运行的时刻 
    %r(run time):输出程序从运行到执行到当前语句时消耗的毫秒数 
    %t(thread id):当前语句所在的线程ID
    %p(priority): 日志的当前优先级别,即DEBUG、INFO、WARN…等
    %c(class):当前日志对象的名称
    %L:输出语句所在的行号
    %F:输出语句所在的文件名
    %-数字:表示该项的最小长度,如果不够,则用空格填充
    -->
    
        <root>
          <!--控制级别,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF-->
          <!--比如定义级别为INFO,则INFO级别向下的级别,比如DEBUG日志将不会被记录-->
          <!--如果没有定义LEVEL的值,则缺省为DEBUG-->
          <level value="ALL"/>
          <appender-ref ref="AppLogAppender"/>
        </root>
        <!--定义输出到控制台命令行中-->
        <logger name="SysLogger">
          <level value="ALL"/>
          <appender-ref ref="TextAppender" />
        </logger>
        
        <logger name="AppLogger">
          <level value="ALL"/>
          <appender-ref ref="AppLogAppender" />
        </logger>
        
        <!--定义输出到控制台命令行中-->
        <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
          <layout type="RMFramework.Common.Logger.MyLayout">
            <param name="ConversionPattern" value="日志时间:%d %n日志级别:%-5p %n用 户 ID:%Property{UserID} %n用户姓名:%Property{UserName} %n日志信息:%Property{Message} %n异常信息:%exception %n%n" />
          </layout>
        </appender>
    
        <!--定义输出到windows事件中-->
        <appender name="WindowsAppender" type="log4net.Appender.EventLogAppender">
          <layout type="RMFramework.Common.Logger.MyLayout">
            <param name="ConversionPattern" value="日志时间:%d %n日志级别:%-5p %n用 户 ID:%Property{UserID} %n用户姓名:%Property{UserName} %n日志信息:%Property{Message} %n异常信息:%exception %n%n" />
          </layout>
        </appender>
    
        <!--定义输出到文件中 用于记录系统级-->
        <appender name="TextAppender" type="log4net.Appender.RollingFileAppender">
          <param name="File" value="Logs\SysLog\" />
          <param name="AppendToFile" value="true" />
          <param name="MaxFileSize" value="10240" />
          <param name="MaxSizeRollBackups" value="100" />
          <param name="StaticLogFileName" value="false" />
          <param name="DatePattern" value="yyyyMMdd&quot;.log&quot;" />
          <param name="RollingStyle" value="Date" />
          <layout type="RMFramework.Common.Logger.MyLayout">
            <param name="ConversionPattern" value="日志时间:%d %n日志级别:%-5p %n用 户 ID:%Property{UserID} %n用户姓名:%Property{UserName} %n日志信息:%Property{Message} %n异常信息:%exception %n%n" />
          </layout>
        </appender>
        <!--定义输出文本,用于记录业务级-->
        <appender name="AppLogAppender" type="log4net.Appender.RollingFileAppender">
          <file value="Logs/AppLog/" />
          <appendToFile value="true" />
          <rollingStyle value="Date" />
          <staticLogFileName value="false" />
          <datePattern value="yyyyMMdd&quot;.log&quot;" />
          <layout type="log4net.Layout.PatternLayout">
            <!--输出格式-->
            <conversionPattern value="%date %-5level %message%newline" />
          </layout>
          <!--<filter type="log4net.Filter.LoggerMatchFilter">
            <loggerToMatch value="SystemLog" />
          </filter>-->
        </appender>
        
        <!--定义输出到数据库-->
        <appender name="DataBaseAppender" type="log4net.Appender.AdoNetAppender">
          <!--日志缓存写入条数-->
          <bufferSize value="1" />
          <!--日志数据库连接串-->
          <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
          <connectionString value="data source=.SQL2008;initial catalog=Demo;integrated security=false;persist security info=True;User ID=sa;Password=1qaz" />
          <!--日志数据库脚本-->
          <commandText value="INSERT INTO LogInfo ([LogDate],[LogLevel],[UserId],[UserName],[Message],[Exception]) VALUES (@LogDate, @LogLevel,@UserId,@UserName, @Message, @Exception)" />
          <!--日志时间LogDate -->
          <parameter>
            <parameterName value="@LogDate" />
            <dbType value="String" />
            <size value="30" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%date{yyyy-MM-dd HH:mm:ss}" />
            </layout>
          </parameter>
          <!--日志类型LogLevel -->
          <parameter>
            <parameterName value="@LogLevel" />
            <dbType value="String" />
            <size value="10" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%level" />
            </layout>
          </parameter>
          <!--自定义UserId -->
          <parameter>
            <parameterName value="@UserId" />
            <dbType value="String" />
            <size value="20" />
            <layout type="RMFramework.Common.Logger.MyLayout">
              <conversionPattern value="%Property{UserID}" />
            </layout>
          </parameter>
          <!--自定义UserName -->
          <parameter>
            <parameterName value="@UserName" />
            <dbType value="String" />
            <size value="50" />
            <layout type="RMFramework.Common.Logger.MyLayout">
              <conversionPattern value="%Property{UserName}" />
            </layout>
          </parameter>
          <!--自定义Message -->
          <parameter>
            <parameterName value="@Message" />
            <dbType value="String" />
            <size value="200" />
            <layout type="RMFramework.Common.Logger.MyLayout">
              <conversionPattern value="%Property{Message}" />
            </layout>
          </parameter>
          <!--异常信息Exception -->
          <parameter>
            <parameterName value="@Exception" />
            <dbType value="String" />
            <size value="4000" />
            <layout type="log4net.Layout.ExceptionLayout" />
          </parameter>
        </appender>
      </log4net>
    </configuration>
    View Code

     2.使用前准备工作

      使用nuget引入Log4net; 

      在引入类库中的AssemblyInfo.cs加入

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

    3.调用方法

      3.1 原始调用

    public static readonly log4net.ILog loginfo = log4net.LogManager.GetLogger("AppLogger");
    

      实例化ILog后,即可进行调用。LogManager.GetLogger传入参数与log4net.config内的Logger要匹配。

      当只有一个配置时,也可以使用如下代码。若多个logger配置时,仅读取第一个输出配置。

    LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

      完整代码如下:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using log4net;
    
    namespace RMFramework.Common.Logger
    {
        public class Log4System
        {
            public static readonly log4net.ILog loginfo = log4net.LogManager.GetLogger("AppLogger");
    
            /// <summary>
            /// 业务日志记录
            /// </summary>
            /// <param name="info"></param>
            public void WriteLog(string info)
            {
                if (loginfo.IsInfoEnabled)
                {
                    loginfo.Info(info);
                }
            }
    
            /// <summary>
            /// 报错日志记录
            /// </summary>
            /// <param name="info"></param>
            /// <param name="ex"></param>
            public void WriteLog(string info, Exception ex)
            {
                if (loginfo.IsErrorEnabled)
                {
                    loginfo.Error(info, ex);
                }
            }
    
            /// <summary>
            /// 调试日志记录
            /// </summary>
            /// <param name="info"></param>
            /// <param name="values"></param>
            public void WriteLog(string info, params object[] values)
            {
                if (loginfo.IsDebugEnabled)
                {
                    loginfo.Debug(string.Format(info, values));
                }
    
            }
        }
    }
    View Code

       3.2 自定义输出

      自定义输出对象,映射到配置文件内的layout标签

      支持输出到控制台,支持输出到文本,支持输出到数据库。

    using log4net;
    using log4net.Config;
    using log4net.Core;
    using log4net.Layout;
    using log4net.Layout.Pattern;
    using System;
    using System.IO;
    using System.Reflection;
    
    namespace RMFramework.Common.Logger
    {
        public class LogHelper
        {
            /// <summary>
            /// LoggerName
            /// </summary>
            public static string LoggerName = string.Empty;
            /// <summary>
            /// 用户ID
            /// </summary>
            public static string UserID = string.Empty;
            /// <summary>
            /// 用户名称
            /// </summary>
            public static string UserName = string.Empty;
    
            private static ILog iLog;
            private static LogEntity logEntity;
    
            /// <summary>
            /// 接口
            /// </summary>
            private static ILog log
            {
                get
                {
                    var configFile = new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config"));
                    if (!configFile.Exists)
                    {
                        throw new Exception("未配置log4net配置文件!");
                    }
    
                    // 设置日志配置文件路径
                    XmlConfigurator.Configure(configFile);
    
                    //string path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + @"Log4Net.config";//AppDomain.CurrentDomain.BaseDirectory
                    //XmlConfigurator.Configure(new FileInfo(path));
    
                    if (iLog == null)
                    {
                        iLog = LogManager.GetLogger(LoggerName);
                    }
                    else
                    {
                        if (iLog.Logger.Name != LoggerName)
                        {
                            iLog = LogManager.GetLogger(LoggerName);
                        }
                    }
    
                    return iLog;
                }
            }
    
            /// <summary>
            /// 构造消息实体
            /// </summary>
            /// <param name="message"></param>
            /// <returns></returns>
            private static LogEntity BuildMessageMode(string message)
            {
                if (logEntity == null)
                {
                    logEntity = new LogEntity();
                    logEntity.UserID = UserID;
                    logEntity.UserName = UserName;
                    logEntity.Message = message;
                }
                else
                    logEntity.Message = message;
    
                return logEntity;
            }
    
            /// <summary>
            /// 调试
            /// </summary>
            /// <param name="message">消息</param>
            public static void Debug(string message)
            {
                if (log.IsDebugEnabled)
                    log.Debug(BuildMessageMode(message));
            }
    
            /// <summary>
            /// 调试
            /// </summary>
            /// <param name="message">消息</param>
            /// <param name="exception">异常</param>
            public static void Debug(string message, Exception ex)
            {
                if (log.IsDebugEnabled)
                    log.Debug(BuildMessageMode(message), ex);
            }
    
            /// <summary>
            /// 信息
            /// </summary>
            /// <param name="message">消息</param>
            public static void Info(string message)
            {
                if (log.IsInfoEnabled)
                    log.Info(BuildMessageMode(message));
            }
    
            /// <summary>
            /// 信息
            /// </summary>
            /// <param name="message">消息</param>
            /// <param name="exception">异常</param>
            public static void Info(string message, Exception ex)
            {
                if (log.IsInfoEnabled)
                    log.Info(BuildMessageMode(message), ex);
            }
    
            /// <summary>
            /// 一般错误
            /// </summary>
            /// <param name="message">消息</param>
            public static void Error(string message)
            {
                if (log.IsErrorEnabled)
                    log.Error(BuildMessageMode(message));
            }
    
            /// <summary>
            /// 一般错误
            /// </summary>
            /// <param name="message">消息</param>
            /// <param name="exception">异常</param>
            public static void Error(string message, Exception exception)
            {
                if (log.IsErrorEnabled)
                    log.Error(BuildMessageMode(message), exception);
            }
    
            /// <summary>
            /// 警告
            /// </summary>
            /// <param name="message">消息</param>
            public static void Warn(string message)
            {
                if (log.IsWarnEnabled)
                    log.Warn(BuildMessageMode(message));
            }
    
            /// <summary>
            /// 警告
            /// </summary>
            /// <param name="message">消息</param>
            /// <param name="exception">异常</param>
            public static void Warn(string message, Exception ex)
            {
                if (log.IsWarnEnabled)
                    log.Warn(BuildMessageMode(message), ex);
            }
    
            /// <summary>
            /// 严重
            /// </summary>
            /// <param name="message">消息</param>
            public static void Fatal(string message)
            {
                if (log.IsFatalEnabled)
                    log.Fatal(BuildMessageMode(message));
            }
    
            /// <summary>
            /// 严重
            /// </summary>
            /// <param name="message">消息</param>
            /// <param name="exception">异常</param>
            public static void Fatal(string message, Exception ex)
            {
                if (log.IsFatalEnabled)
                    log.Fatal(BuildMessageMode(message), ex);
            }
        }
    
        public class MyLayout : PatternLayout
        {
            public MyLayout()
            {
                this.AddConverter("Property", typeof(MyPatternConverter));
            }
        }
    
        public class LogEntity
        {
            public string UserID { get; set; }
    
            public string UserName { get; set; }
    
            public string Message { get; set; }
    
            public Exception Exception { get; set; }
    
        }
    
        public class MyPatternConverter : 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>
            /// <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;
            }
        }
    }
    View Code

       3.3 队列输出

       将日志添加到队列,队列输出到磁盘,效率高。

    using log4net;
    using log4net.Config;
    using System;
    using System.Collections.Concurrent;
    using System.IO;
    using System.Threading;
    
    namespace RMFramework.Common.Logger
    {
        public sealed class FlashLogger
        {
            /// <summary>
            /// 记录消息Queue
            /// </summary>
            private readonly ConcurrentQueue<FlashLogMessage> _que;
    
            /// <summary>
            /// 信号
            /// </summary>
            private readonly ManualResetEvent _mre;
    
            /// <summary>
            /// 日志
            /// </summary>
            private readonly ILog _log;
    
            /// <summary>
            /// 日志
            /// </summary>
            private static FlashLogger _flashLog = new FlashLogger();
    
    
            private FlashLogger()
            {
                var configFile = new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config"));
                if (!configFile.Exists)
                {
                    throw new Exception("未配置log4net配置文件!");
                }
    
                // 设置日志配置文件路径
                XmlConfigurator.Configure(configFile);
    
                _que = new ConcurrentQueue<FlashLogMessage>();
                _mre = new ManualResetEvent(false);
                _log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
            }
    
            /// <summary>
            /// 实现单例
            /// </summary>
            /// <returns></returns>
            public static FlashLogger Instance()
            {
                return _flashLog;
            }
    
            /// <summary>
            /// 另一个线程记录日志,只在程序初始化时调用一次
            /// </summary>
            public void Register()
            {
                Thread t = new Thread(new ThreadStart(WriteLog));
                t.IsBackground = false;
                t.Start();
            }
    
            /// <summary>
            /// 从队列中写日志至磁盘
            /// </summary>
            private void WriteLog()
            {
                while (true)
                {
                    // 等待信号通知
                    _mre.WaitOne();
    
                    FlashLogMessage msg;
                    // 判断是否有内容需要如磁盘 从列队中获取内容,并删除列队中的内容
                    while (_que.Count > 0 && _que.TryDequeue(out msg))
                    {
                        // 判断日志等级,然后写日志
                        switch (msg.Level)
                        {
                            case FlashLogLevel.Debug:
                                _log.Debug(msg.Message, msg.Exception);
                                break;
                            case FlashLogLevel.Info:
                                _log.Info(msg.Message, msg.Exception);
                                break;
                            case FlashLogLevel.Error:
                                _log.Error(msg.Message, msg.Exception);
                                break;
                            case FlashLogLevel.Warn:
                                _log.Warn(msg.Message, msg.Exception);
                                break;
                            case FlashLogLevel.Fatal:
                                _log.Fatal(msg.Message, msg.Exception);
                                break;
                        }
                    }
    
                    // 重新设置信号
                    _mre.Reset();
                    Thread.Sleep(1);
                }
            }
    
    
            /// <summary>
            /// 写日志
            /// </summary>
            /// <param name="message">日志文本</param>
            /// <param name="level">等级</param>
            /// <param name="ex">Exception</param>
            public void EnqueueMessage(string message, FlashLogLevel level, Exception ex = null)
            {
                if ((level == FlashLogLevel.Debug && _log.IsDebugEnabled)
                 || (level == FlashLogLevel.Error && _log.IsErrorEnabled)
                 || (level == FlashLogLevel.Fatal && _log.IsFatalEnabled)
                 || (level == FlashLogLevel.Info && _log.IsInfoEnabled)
                 || (level == FlashLogLevel.Warn && _log.IsWarnEnabled))
                {
                    _que.Enqueue(new FlashLogMessage
                    {
                        Message = "[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff") + "]
    " + message,
                        Level = level,
                        Exception = ex
                    });
    
                    // 通知线程往磁盘中写日志
                    _mre.Set();
                }
            }
    
            public static void Debug(string msg, Exception ex = null)
            {
                Instance().EnqueueMessage(msg, FlashLogLevel.Debug, ex);
            }
    
            public static void Error(string msg, Exception ex = null)
            {
                Instance().EnqueueMessage(msg, FlashLogLevel.Error, ex);
            }
    
            public static void Fatal(string msg, Exception ex = null)
            {
                Instance().EnqueueMessage(msg, FlashLogLevel.Fatal, ex);
            }
    
            public static void Info(string msg, Exception ex = null)
            {
                Instance().EnqueueMessage(msg, FlashLogLevel.Info, ex);
            }
    
            public static void Warn(string msg, Exception ex = null)
            {
                Instance().EnqueueMessage(msg, FlashLogLevel.Warn, ex);
            }
    
        }
    
        /// <summary>
        /// 日志等级
        /// </summary>
        public enum FlashLogLevel
        {
            Debug,
            Info,
            Error,
            Warn,
            Fatal
        }
    
    
        /// <summary>
        /// 日志内容
        /// </summary>
        public class FlashLogMessage
        {
            public string Message { get; set; }
            public FlashLogLevel Level { get; set; }
            public Exception Exception { get; set; }
    
        }
    
    }
    View Code

     4.需要注意的地方

    • 实例化后的日志是被独占的,日志类库应集中管理,否则会导致输出为空
  • 相关阅读:
    深入解析Hibernate核心接口
    Hibernate基本原理
    深入hibernate的三种状态
    Hibernate commit() 和flush() 的区别
    Hibernate中的merge使用详情解说
    Record is locked by another user
    Vue路由router-link的使用
    Vue-router的基本使用
    Vue把父组件的方法传递给子组件调用(评论列表例子)
    Vue中子组件调用父组件的方法
  • 原文地址:https://www.cnblogs.com/xuexian/p/10906261.html
Copyright © 2020-2023  润新知