当前位置: 首页 > news >正文

ASP.NET MVC会计教学管理端项目系列--Log4Net日志组件

02: ASP.NET MVC会计教学管理端项目系列–三层+MVVM搭建

03: ASP.NET MVC会计教学管理端项目系列–autofac批量注入

文章目录

  • Log4Net
    • logger节点配置详解
    • 日志级别等级
    • ILog对象说明
    • 简单使用
    • 自定义配置扩展
    • ES 扩展

Log4Net

log4net库是Apache log4j框架在Microsoft .NET平台的实现,是一个帮助程序员将日志信息输出到各种目标(控制台、文件、数据库等)的工具

logger节点配置详解

logger节点支持的属性:name、additivity。

name 必须的,logger的名称,在代码中得到ILog对象时用到。
additivity 可选,取值是true或false,默认值是true。设置为false时将阻止父logger中的appender。

logger支持的子元素:level、appender-ref、param。

level 最多一个。在这个级别或之上的才会被记录。OFF、FATAL、ERROR、WARN 、INFO、DEBUG、ALL

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

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

日志级别等级

高到底分别为:OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL

ILog对象说明

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

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

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

还有一个布尔属性:

bool IsDebugEnabled { get; }

如果使用Debug(object message, Exception exception)则无论Layout如何配置,日志都会输出Exception信息,包括Exception的Message和Trace。如果使用Debug(object message),则无论Layout如何配置是不会输出Exception信息的。

在代码中可以使用LogManager类来得到Logger配置下的相应的ILog对象,LogManager类用来管理所应得Logger,它的GetLogger静态方法,可以获得配置文件中相应的Logger,代码如下:

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

简单使用

1、在web站点中的Web.config中根节点 configuration添加如下配置

<!--此处是log4net的配置-->
  <log4net>
    <!--错误日志类-->
    <logger name="logerror">
      <!--日志类的名字-->
      <level value="ALL" />
      <!--定义记录的日志级别-->
      <appender-ref ref="ErrorAppender" />
      <!--记录到哪个介质中去-->
    </logger>
    <root>
      <level value="WARN" />
      <appender-ref ref="LogFileAppender" />
      <appender-ref ref="ConsoleAppender" />
    </root>
    <!--异常日志→name的值要对应你LogHelper的log4net.LogManager.GetLogger("logerror");不区分大小写-->
    <logger name="LogError">
      <level value="ALL" />
      <appender-ref ref="InfoAppender" />
    </logger>
    <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
      <!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
      <param name="File" value="App_Data\\LogError\\" />
      <!--日志输出到exe程序这个相对目录下-->
      <param name="AppendToFile" value="true" />
      <!--输出的日志不会覆盖以前的信息-->
      <param name="MaxSizeRollBackups" value="100" />
      <!--备份文件的个数-->
      <param name="MaxFileSize" value="10240" />
      <!--当个日志文件的最大大小-->
      <param name="StaticLogFileName" value="false" />
      <!--是否使用静态文件名-->
      <param name="DatePattern" value="yyyyMMdd&quot;.txt&quot;" />
      <!--日志文件名-->
      <param name="RollingStyle" value="Date" />
      <!--文件创建的方式,这里是以Date方式创建-->
      <!--错误日志布局-->
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="&lt;HR COLOR=red&gt;%n异常时间:%d [%t] &lt;BR&gt;%n异常级别:%-5p &lt;BR&gt;%n异 常 类:%c [%x] &lt;BR&gt;%n%m &lt;BR&gt;%n &lt;HR Size=1&gt;" />
      </layout>
    </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>

2、Web站点安装Nuget包
在这里插入图片描述
3、在Global.asax中Application_Start方法添加如下代码:

log4net.Config.XmlConfigurator.Configure();

在这里插入图片描述
4、新建基础类库同样安装log4net包,添加日志记录帮助类:

    public class LogHelper
    {
        public static readonly log4net.ILog loginfo = log4net.LogManager.GetLogger("loginfo");
        public static readonly log4net.ILog logerror = log4net.LogManager.GetLogger("logerror");

        /// <summary>
        /// 操作日志
        /// </summary>
        /// <param name="info"></param>
        public static void Info(string info)
        {
            if (loginfo.IsInfoEnabled)
            {
                loginfo.Info(info);
            }
        }

        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ex"></param>
        public static void Error(string info, Exception ex)
        {
            if (logerror.IsErrorEnabled)
            {
                logerror.Error(info, ex);
            }
        }

        /// <summary>
        /// 警告日志
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ex"></param>
        public static void Warn(string info, Exception ex)
        {
            if (logerror.IsWarnEnabled)
            {
                logerror.Warn(info, ex);
            }
        }

        /// <summary>
        /// 调试日志
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ex"></param>
        public static void Debug(string info, Exception ex)
        {
            if (logerror.IsDebugEnabled)
            {
                logerror.Debug(info, ex);
            }
        }
    }

自定义配置扩展

1、WebConfig 中添加默认日志路径:

<!--默认文本日志路径-->
<add key="TxtLogPath" value="D:\Log\\"/>
<!--自定义日志文件路径,如果没配置走文本日志路径-->
<add key="Log4NetConfigPath" value="D:\\Log4Net.Config"/>

2、自定义扩展并支持日志分卷

 /// <summary>
 /// Log4文件上限分卷日志组件
 /// </summary>
 public static class Logger
 {
     //是否使用组件默认配置
     public static bool IsDefaultConfig;
     static Logger()
     {
         try
         {
             var log4NetConfigPath = ConfigManager.AppSetting("Log4NetConfigPath"); 
             if (log4NetConfigPath == null)
             {
                 IsDefaultConfig = true;
                 return;
             }
             XmlConfigurator.Configure(new System.IO.FileInfo(log4NetConfigPath));
         }
         catch
         {
             IsDefaultConfig = true;
         }
     }
     #region 日志静态实现方法,不可被重写

     /// <summary>
     /// 提示信息
     /// </summary>
     /// <param name="logPath">日志记录的自定义路径(D://Log//),如果是业务路径,则自动忽略</param>
     /// <param name="msg"></param>
     /// <param name="isDefaultlogPath"></param>
     public static void Info(string msg, string logPath = "", bool isDefaultlogPath = true)
     {
         logPath = GetLogPath(isDefaultlogPath, logPath);
         Logging.LogInfo(logPath, msg);
     }

     /// <summary>
     /// 告警信息
     /// </summary>
     /// <param name="logPath">日志记录的自定义路径(D://Log//),如果是业务路径,则自动忽略</param>
     /// <param name="msg"></param>
     /// <param name="isDefaultlogPath"></param>
     public static void Warn(string msg, string logPath = "", bool isDefaultlogPath = true)
     {
         logPath = GetLogPath(isDefaultlogPath, logPath);
         Logging.LogInfo(logPath, msg);
     }

     /// <summary>
     /// 记录错误日志
     /// </summary>
     /// <param name="logPath">日志记录的自定义路径(D://Log//),如果是业务路径,则自动忽略</param>
     /// <param name="msg"></param>
     /// <param name="ex"></param>
     /// <param name="isDefaultlogPath"></param>
     public static void Error(string msg, Exception ex = null, string logPath = "", bool isDefaultlogPath = true)
     {
         logPath = GetLogPath(isDefaultlogPath, logPath);
         Logging.LogError(logPath, msg, ex);
     }


     private static string GetLogPath(bool isDefaultlogPath, string logPath = "")
     {
         try
         {
             //如果不是默认路径,则根据跟目录获取相关域名
             if (!isDefaultlogPath || !IsDefaultConfig)
             {
                 return logPath;
             }
             logPath = ConfigManager.AppSetting("TxtLogPath");
             if (logPath == null)
             {
                 throw new Exception($"初始化日志配置文件出错,请检查【TxtLogPath】是否配置,且路径完全正确");
             }
             return logPath;
         }
         catch (Exception ex)
         {
             throw new Exception($"初始化日志配置文件出错,请检查【TxtLogPath】是否配置,且路径完全正确,异常信息:{ex}");
         }
     }
     #endregion
 }

ES 扩展

【本次项目暂不使用ES,这里只做示范】

1、安装包log4stash,log4stash是日志记录es的一个组件
在这里插入图片描述
2、配置es

<!--ES日志管理,本次项目暂不使用ES-->
<add key="ElasticSearchService" value="10.1.21.1|9200|eadminlog"/>

3、调用

/// <summary>
/// 日志记录工具类
/// </summary>
public static class Logging
{
   private static readonly object MLock = new object();
   private const string Maxfilesize = "LogMaxFileSize";
   private const string Maxsizerollbackups = "LogMaxSizeRollBackups";
   public static string[] Configs;
   public static ConcurrentDictionary<string, object> Dic = new ConcurrentDictionary<string, object>();

   static Logging()
   {
       BasicConfigurator.Configure();
       var elasticSearch = ConfigManager.AppSetting("ElasticSearchService"); 
       if (elasticSearch == null)
       {
           return;
       }
       Configs = elasticSearch.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
       if (Configs.Length != 3)
       {
           throw new Exception($"初始化日志配置文件出错,请检查【ElasticSearchService】是否配置,正确格式如下:10.1.21.1|9200|efinancelog");
       }
   }

   #region Info

   /// <summary>
   /// 日志目录地址(绝对路径)
   /// </summary>
   /// <param name="logpath"></param>
   /// <param name="info"></param>
   public static void LogInfo(string logpath, string info)
   {
       var logFile = GetLog("loginfo", logpath);
       if (!logFile.IsInfoEnabled) return;
       logFile.Info(info);
   }

   #endregion

   #region error

   /// <summary>
   /// A private method that really do the work of logging
   /// </summary>
   /// <param name="message"></param>
   /// <param name="ex"></param>
   /// <param name="logPath"></param>
   public static void LogError(string logPath, string message, Exception ex)
   {
       var logFile = GetLog("logerror", logPath);
       if (!logFile.IsErrorEnabled) return;
       logFile.Error(message, ex);
   }

   #endregion

   #region commom

   public static ILog GetLog(string name, string logpath = "")
   {
       try
       {
           var log = LogManager.GetLogger(name);

           if (((log4net.Repository.Hierarchy.Logger)log.Logger).GetAppender(name) != null) return log;
           lock (MLock)
           {
               ((log4net.Repository.Hierarchy.Logger)log.Logger).AddAppender(new NRollingFileAppender(logpath, name));
               if (Configs?.Length == 3)
               {
                   ((log4net.Repository.Hierarchy.Logger)log.Logger).AddAppender(new NElasticSearchAppender("ElasticSearch"));
               }
           }
           return log;
       }
       catch
       {
           return LogManager.GetLogger("logFile");
       }

   }
   internal static bool IsPhysicsPath(string path)
   {
       var regex = new Regex(@"^([a-zA-Z]:\\)?[^\/\:\*\?\""\<\>\|\,]*$");
       return regex.IsMatch(path);
   }
   #endregion

   #region config

   /// <summary>
   /// 构建日志RollingFileAppender
   /// </summary>
   private sealed class NRollingFileAppender : RollingFileAppender
   {
       public NRollingFileAppender(string logPath, string logName)
       {
           File = Path.Combine(logPath, $"{logName}\\");
           Name = logName;
           Layout = new PatternLayout("%n记录时间:%date 线程ID:[%thread] 日志级别:%-5level  %n日志描述:%message %n");
           ImmediateFlush = true;
           MaxFileSize = GetMaxFileSize();
           DatePattern = "yyyy-MM-dd-HH.'txt'";
           MaxSizeRollBackups = GetMaxSizeRollBackups();
           RollingStyle = RollingMode.Composite;
           AppendToFile = true;
           StaticLogFileName = false;
           LockingModel = new MinimalLock();
           base.ActivateOptions();
       }

       /// <summary>
       /// 当日志文件达到MaxFileSize大小,就自动创建备份文件。备份文件的多少由MaxSizeRollBackups决定
       /// </summary>
       /// <returns></returns>
       private static int GetMaxSizeRollBackups()
       {
           var config = ConfigManager.AppSetting(Maxsizerollbackups);

           if (string.IsNullOrEmpty(config))
               config = "-1";
           int i;
           int.TryParse(config, out i);

           return i != 0 ? i : -1;

       }

       /// <summary>
       /// 获取每个日志文件最大容量
       /// </summary>
       /// <returns></returns>
       private static long GetMaxFileSize()
       {
           var config = ConfigManager.AppSetting(Maxfilesize); 
           double rate = 1024;
           string unit = "m";

           if (string.IsNullOrEmpty(config))
               config = "20M";

           config = config.ToLower();

           if (config.EndsWith("m"))
           {
               rate = Math.Pow(rate, 2);
           }
           else if (config.EndsWith("g"))
           {
               rate = Math.Pow(rate, 3);
               unit = "g";
           }

           int i = config.IndexOf(unit, StringComparison.Ordinal);
           int quota = 0;

           if (i > 0)
           {
               var data = config.Substring(0, i);
               int.TryParse(data, out quota);
           }

           quota = quota == 0 ? 20 : quota;

           return (long)(quota * rate);
       }
   }

   private sealed class NElasticSearchAppender : ElasticSearchAppender
   {
       public NElasticSearchAppender(string logName)
       {
           Server = Configs[0];
           Port = Convert.ToInt32(Configs[1]);
           IndexName = $"{Configs[2]}_{DateTime.Now.ToString("yyyy-MM-dd")}";
           IndexType = "LogEvent";
           Name = logName;
           Layout = new PatternLayout("%n记录时间:%date 线程ID:[%thread] 日志级别:%-5level  %n日志描述:%message %n");
           base.ActivateOptions();
       }

   }


   private sealed class SmtpAppenderAppender : SmtpAppender
   {
       public SmtpAppenderAppender(string logName)
       {
           Authentication=SmtpAuthentication.Basic;
           Port = Convert.ToInt32(Configs[1]);
           Name = logName;
           Layout = new PatternLayout("%n记录时间:%date 线程ID:[%thread] 日志级别:%-5level  %n日志描述:%message %n");
           base.ActivateOptions();
       }

   }
   #endregion
}

相关文章:

  • 【AI】安装web UI时总是报找不到yaml
  • 单链表的插入和删除
  • 国内IP切换软件:解锁网络世界的新钥匙
  • Linux---多线程(下)
  • 3.28C++
  • ES6—Module 的语法
  • 【QT】关于QSerialPort的错误处理 (Error Handling)及错误类型
  • Eureka简介与使用浅析
  • 四位院士领衔百余位行业权威专家,3月5-7日齐聚泉城
  • Charles授权码生成器
  • 在having、select子句中使用子查询
  • (undone) 如何计算 Hessian Matrix 海森矩阵 海塞矩阵
  • AD域帐户密码过期,终端802.1x认证自动重连导致AD账号被锁,员工无法上网、办公怎么办?
  • iOS小技能:跳转到地图APP(navForIOSMap)
  • Unreal Engine源代码下载方法
  • JavaScript简识
  • 【正点原子STM32连载】第五十一章 视频播放器实验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1
  • 下一个(全)排列
  • 读懂MEV链上套利操作
  • Mac 电脑下载 AppStore 中的 ipa 软件包详细流程
  • Pycharm Runtime Error R6034解决方法
  • LQ0100 人物相关性分析【文本处理】
  • 虚拟形象制作该如何进行?带你深入了解虚拟形象制作
  • 一文读懂TDengine3.0中的事务机制
  • Java入门刷题篇 基础语法->>基本数据类型->>Java1类型转换
  • 入门学python(三)
  • 湖北住建厅七大员报考条件和取证流程
  • 字节码指令 || JVM类加载与字节码技术
  • 哪个开源工作流引擎更好?Flowable or Camunda ?
  • 牛客网专项练习30天Pytnon篇第17天
  • 【Vue】Vue全家桶(九)Vue3
  • #php 递归获取下级元素#