zoukankan      html  css  js  c++  java
  • 基于log4net日志组件的使用

    一、前言

      应用程序在生产环境运行中产生的错误信息、告警信息、特定调试信息或者接口对接信息如何让开发者进行查找?这时候可以使用日志来回溯系统执行的全过程查找系统问题,帮助开发者解决线上问题等。一般都会选择一个日志组件并且希望其是代码侵入少,使用便捷,写入性能高,比如开源的log4net。

    二、使用

      在项目引用中引入log4net组件,然后对日志配置文件进行配置,配置信息涉及到文件夹位置、文件名称格式、文件最大大小、文件的内容格式、日志级别等信息,比如Log4Net.config,通过这个日志文件定义基本信息,可以在打印日志生成想要的日志文件。

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
      </configSections>
      <log4net>
        <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="[%p %t] [%date{yyyy-MM-dd HH:mm:ss,fff}] %-5l - %m%n"/>
          </layout>
        </appender>
        <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
          <!--日志路径-->
          <param name= "File" value= "logs\Info\log_"/>
          <!--是否是向文件中追加日志-->
          <param name= "AppendToFile" value= "true"/>
          <!--log保留天数-->
          <param name= "MaxSizeRollBackups" value= "10"/>
          <!--日志文件名是否是固定不变的-->
          <param name= "StaticLogFileName" value= "false"/>
          <!--日志文件名格式为-->
          <param name= "DatePattern" value= "yyyy-MM-dd&quot;.log&quot;"/>
          <!--日志根据日期滚动-->
          <param name= "RollingStyle" value= "Date"/>
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="记录时间:%date 线程ID:[%thread] 日志级别:  %-5level 类:%logger  - 描述:%message %n"/>
          </layout>
          <filter type="log4net.Filter.LevelRangeFilter">
            <param name="LevelMin" value="Info" />
            <param name="LevelMax" value="WARN" />
          </filter>
        </appender>
        <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
          <param name= "File" value= "logs\Error\Log_"/>
          <param name= "AppendToFile" value= "true"/>
          <param name= "MaxSizeRollBackups" value= "10"/>
          <param name= "StaticLogFileName" value= "false"/>
          <param name= "DatePattern" value= "yyyy-MM-dd&quot;.log&quot;"/>
          <param name= "RollingStyle" value= "Date"/>
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="记录时间:%date 线程ID:[%thread] 日志级别:  %-5level 类:%logger  - 描述:%message %n"/>
          </layout>
          <filter type="log4net.Filter.LevelRangeFilter">
            <param name="LevelMin" value="ERROR" />
            <param name="LevelMax" value="FATAL" />
          </filter>
        </appender>
        <root>
          <!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
          <level value="ALL" />
          <appender-ref ref="RollingLogFileAppender" />
          <appender-ref ref="RollingFile" />
        </root>
      </log4net>
    </configuration>

      定义一个日志接口(主要是不同层级的写入方法),实现接口通过log4net组件来实现文件形式记录日志信息,使用组件读取配置文件、获取日志对象写入文件日志,还可以使用数据库方式实现接口写入日志。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace TQF.Logger.Logger
    {
        /// <summary>
        /// 定义日志接口类
        /// </summary>
        public interface ILogger
        {
            /// <summary>
            /// 调试日志输出
            /// </summary>
            /// <param name="msg">输出内容</param>
            void Debug(string msg);
    
            /// <summary>
            /// 调试日志输出
            /// </summary>
            /// <param name="msg">输出内容</param>
            /// <param name="ex">输出异常</param>
            void Debug(string msg, Exception ex);
    
            /// <summary>
            /// 信息日志输出
            /// </summary>
            /// <param name="msg">输出内容</param>
            void Info(string msg);
    
            /// <summary>
            /// 信息日志输出
            /// </summary>
            /// <param name="msg">输出内容</param>
            /// <param name="ex">输出异常</param>
            void Info(string msg, Exception ex);
    
            /// <summary>
            /// 警告日志输出
            /// </summary>
            /// <param name="msg">输出内容</param>
            void Warn(string msg);
    /// <summary> /// 警告日志输出 /// </summary> /// <param name="msg">输出内容</param> /// <param name="ex">输出异常</param> void Warn(string msg, Exception ex); /// <summary> /// 错误日志输出 /// </summary> /// <param name="msg">输出内容</param> void Error(string msg); /// <summary> /// 错误日志输出 /// </summary> /// <param name="msg">输出内容</param> /// <param name="ex">输出异常</param> void Error(string msg, Exception ex); /// <summary> /// 致命日志输出 /// </summary> /// <param name="msg">输出内容</param> void Fatal(string msg); /// <summary> /// 致命日志输出 /// </summary> /// <param name="msg">输出内容</param> /// <param name="ex">输出异常</param> void Fatal(string msg, Exception ex); } }
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using log4net;
    using log4net.Appender;
    using log4net.Config;
    
    namespace TQF.Logger.Logger
    {
        /// <summary>
        /// 日志接口实现类
        /// </summary>
        public class Log4Helper : ILogger
        {
            /// <summary>
            /// 考虑使用线程安全的字典
            /// </summary>
            private Dictionary<string, ILog> LogDic = new Dictionary<string, ILog>();
            
            /// <summary>
            /// 定义锁对象
            /// </summary>
            private object _islock = new object();
    
            /// <summary>
            /// 定义文件名
            /// </summary>
            private string fileName = string.Empty;
    /// <summary> /// 使用构造函数日志调用初始化 /// </summary> /// <param name="fileSavePath">日志文件保存路径[若路径为空,则默认程序根目录Logger文件夹;]</param> /// <param name="fileName">日志文件名[若文件名为空,则默认文件名:Default]</param> public Log4Helper(string fileSavePath, string fileName, string logSuffix = ".log") { try { Init(); if (string.IsNullOrEmpty(fileSavePath)) fileSavePath = "Logger"; if (string.IsNullOrEmpty(fileName)) fileName = "Default"; this.fileName = fileName; var repository = LogManager.GetRepository(); var appenders = repository.GetAppenders(); if (appenders.Length == 0) return; var targetApder = appenders.First(p => p.Name == "FileInfoAppender") as RollingFileAppender; targetApder.File = Path.Combine(fileSavePath, this.fileName + logSuffix); targetApder.ActivateOptions(); } catch (Exception ex) { } } /// <summary> /// 缓存日志对象(通过日志文件名缓存日志对象,减少日志对象的创建工作) /// </summary> /// <param name="name"></param> /// <returns></returns> private ILog GetLog(string name) { try { if (LogDic == null) { LogDic = new Dictionary<string, ILog>(); } lock (_islock) { if (!LogDic.ContainsKey(name)) { LogDic.Add(name, LogManager.GetLogger(name)); } } return LogDic[name]; } catch { return LogManager.GetLogger("Default"); } } /// <summary> /// 日志记录初始化 /// </summary> private void Init() { // 获取日志配置文件 var file = new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log4net.config")); // 检测配置文件是否存在 if (file.Exists) { //加载配置文件 XmlConfigurator.Configure(file); } else { new Exception("找不到日志配置文件!"); } } /// <summary> /// 调试日志输出 /// </summary> /// <param name="msg">内容</param> public void Debug(string msg) { var log = GetLog(this.fileName); if (log == null) { return; } log.Debug(msg); } /// <summary> /// 调试日志输出 /// </summary> /// <param name="msg">输出内容</param> /// <param name="ex">输出异常</param> public void Debug(string msg, Exception ex) { var log = GetLog(this.fileName); if (log == null) { return; } log.Debug(msg, ex); } /// <summary> /// 错误日志输出 /// </summary> /// <param name="msg">输出内容</param> public void Error(string msg) { var log = GetLog(this.fileName); if (log == null) { return; } log.Error(msg); } /// <summary> /// 错误日志输出 /// </summary> /// <param name="msg">输出内容</param> /// <param name="ex">输出异常</param> public void Error(string msg, Exception ex) { var log = GetLog(this.fileName); if (log == null) { return; } log.Error(msg, ex); } /// <summary> /// 致命日志输出 /// </summary> /// <param name="msg">输出内容</param> public void Fatal(string msg) { var log = GetLog(this.fileName); if (log == null) { return; } log.Fatal(msg); } /// <summary> /// 致命日志输出 /// </summary> /// <param name="msg">输出内容</param> /// <param name="ex">输出异常</param> public void Fatal(string msg, Exception ex) { var log = GetLog(this.fileName); if (log == null) { return; } log.Fatal(msg, ex); } /// <summary> /// 信息日志输出 /// </summary> /// <param name="msg">输出内容</param> public void Info(string msg) { var log = GetLog(this.fileName); if (log == null) { return; } log.Info(msg); } /// <summary> /// 信息日志输出 /// </summary> /// <param name="msg">输出内容</param> /// <param name="ex">输出异常</param> public void Info(string msg, Exception ex) { var log = GetLog(this.fileName); if (log == null) { return; } log.Info(msg, ex); } /// <summary> /// 警告日志输出 /// </summary> /// <param name="msg">输出内容</param> public void Warn(string msg) { var log = GetLog(this.fileName); if (log == null) { return; } log.Warn(msg); } /// <summary> /// 警告日志输出 /// </summary> /// <param name="msg">输出内容</param> /// <param name="ex">输出异常</param> public void Warn(string msg, Exception ex) { var log = GetLog(this.fileName); if (log == null) { return; } log.Warn(msg, ex); } } }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using TQF.Logger.Logger;
    
    namespace TQF.Logger
    {
        /// <summary>
        /// 配置文件如果不设置属性“复制到输出目录”不会在debug文件中存在
        /// </summary>
        class Program
        {
            static void Main(string[] args)
            {
                var log4Helper = new Log4Helper(string.Empty, "program");
                log4Helper.Info("info");
            }
        }
    }

      按照配置文件格式定义的文件夹、文件名称、文件内容格式,相对标准化,但是要特殊的记录日志信息比如不确定文件夹名称、不确定的文件名称等,就要开发者自定义,通过在写入日志的时候,传入文件夹和文件名称形式来存储,对于特殊的日志信息可以通过该方法达到特定要求,如下所示。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections.Concurrent;
    using System.Configuration;
    
    using log4net;
    using log4net.Appender;
    using log4net.Core;
    using log4net.Layout;
    using log4net.Repository;
    using log4net.Repository.Hierarchy;
    
    [assembly: log4net.Config.XmlConfigurator(Watch = true)]
    namespace DataPullAPI.Utility
    {
        /// <summary>
        /// log4net 自定义日志类
        /// </summary>
        public static class LogCustomHelper
        {
            /// <summary>
            /// 类型安全的字典对象
            /// </summary>
            private static readonly ConcurrentDictionary<string, ILog> loggerContainer = new ConcurrentDictionary<string, ILog>();
    
            //默认配置 
            private const int MAX_SIZE_ROLL_BACKUPS = 20;
            private const string LAYOUT_PATTERN = "%message";
            private const string DATE_PATTERN = "yyyyMMdd";
            private const string MAXIMUM_FILE_SIZE = "10MB";
            private const string LEVEL = "ALL";
    
            /// <summary>
            /// 获取日志对象
            /// </summary>
            /// <param name="loggerName"></param>
            /// <param name="category"></param>
            /// <param name="additivity"></param>
            /// <returns></returns>
            public static ILog GetCustomLogger(string loggerName, string category = null, bool additivity = false)
            {
                return loggerContainer.GetOrAdd(loggerName, delegate (string name)
                {
                    RollingFileAppender newAppender = GetNewFileApender(loggerName, GetFile(category, loggerName), MAX_SIZE_ROLL_BACKUPS, true, true, MAXIMUM_FILE_SIZE, RollingFileAppender.RollingMode.Composite,
                        DATE_PATTERN, LAYOUT_PATTERN);
    
                    Hierarchy repository = (Hierarchy)LogManager.GetRepository();
                    Logger logger = repository.LoggerFactory.CreateLogger(repository, loggerName);
                    logger.Hierarchy = repository;
                    logger.Parent = repository.Root;
                    logger.Level = GetLoggerLevel(LEVEL);
                    logger.Additivity = additivity;
                    logger.AddAppender(newAppender);
                    logger.Repository.Configured = true;
                    return new LogImpl(logger);
                });
            }
    
            /// <summary>
            /// 自定日志文件夹和文件路径
            /// </summary>
            /// <param name="category"></param>
            /// <param name="loggerName"></param>
            /// <returns></returns>
            private static string GetFile(string category, string loggerName)
            {
                if (string.IsNullOrEmpty(category))
                {
                    return string.Format(@"Logs\{0}\{1}.txt", DateTime.Now.ToString("yyyy-MM-dd"), loggerName);
                }
                else
                {
                    return string.Format(@"Logs\{0}\{1}\{2}.txt", category,DateTime.Now.ToString("yyyy-MM-dd"), loggerName);
                }
            }
    
            /// <summary>
            /// 获取日志级别
            /// </summary>
            /// <param name="level"></param>
            /// <returns></returns>
            private static Level GetLoggerLevel(string level)
            {
                if (!string.IsNullOrEmpty(level))
                {
                    switch (level.ToLower().Trim())
                    {
                        case "debug":
                            return Level.Debug;
    
                        case "info":
                            return Level.Info;
    
                        case "warn":
                            return Level.Warn;
    
                        case "error":
                            return Level.Error;
    
                        case "fatal":
                            return Level.Fatal;
                    }
                }
                return Level.Debug;
            }
    
            /// <summary>
            /// 获取配置信息
            /// </summary>
            /// <param name="appenderName"></param>
            /// <param name="file"></param>
            /// <param name="maxSizeRollBackups"></param>
            /// <param name="appendToFile"></param>
            /// <param name="staticLogFileName"></param>
            /// <param name="maximumFileSize"></param>
            /// <param name="rollingMode"></param>
            /// <param name="datePattern"></param>
            /// <param name="layoutPattern"></param>
            /// <returns></returns>
            private static RollingFileAppender GetNewFileApender(string appenderName, string file, int maxSizeRollBackups, bool appendToFile = true, bool staticLogFileName = false, string maximumFileSize = "2MB", RollingFileAppender.RollingMode rollingMode = RollingFileAppender.RollingMode.Size, string datePattern = "yyyyMMdd\".txt\"", string layoutPattern = "%d [%t] %-5p %c  - %m%n")
            {
                RollingFileAppender appender = new RollingFileAppender
                {
                    LockingModel = new FileAppender.MinimalLock(),
                    Name = appenderName,
                    File = file,
                    AppendToFile = appendToFile,
                    MaxSizeRollBackups = maxSizeRollBackups,
                    MaximumFileSize = maximumFileSize,
                    StaticLogFileName = staticLogFileName,
                    RollingStyle = rollingMode,
                    DatePattern = datePattern
                };
                PatternLayout layout = new PatternLayout(layoutPattern);
                appender.Layout = layout;
                layout.ActivateOptions();
                appender.ActivateOptions();
                return appender;
            }
    
            /// <summary>
            /// 写入日志信息
            /// </summary>
            /// <param name="folderName">文件夹名称</param>
            /// <param name="fileName">文件名称</param>
            /// <param name="message">日志信息</param>
            public static void Info(string folderName, string fileName,string message)
            {
                ILog logger = GetCustomLogger(fileName, folderName);
                logger.Info(message);
            }
        }
    }

    三、总结

      在生产环境记录日志可以帮助用户定位问题,解决问题,对系统执行过程中可能出现异常错误进行捕获,对执行全过程进行回溯查看等;在存储方式上不仅可以使用文本文件方式保存,还可以使用数据库保存(关系型数据,非关系型数据库mongodb);在分布式系统中日志的聚集,整合,可视化,统一管理的考量与实践。

  • 相关阅读:
    C语言 sprintf 函数 C语言零基础入门教程
    C语言 printf 函数 C语言零基础入门教程
    C语言 文件读写 fgets 函数 C语言零基础入门教程
    C语言 文件读写 fputs 函数 C语言零基础入门教程
    C语言 fprintf 函数 C语言零基础入门教程
    C语言 文件读写 fgetc 函数 C语言零基础入门教程
    C语言 文件读写 fputc 函数 C语言零基础入门教程
    C语言 strlen 函数 C语言零基础入门教程
    Brad Abrams关于Naming Conventions的演讲中涉及到的生词集解
    适配器模式
  • 原文地址:https://www.cnblogs.com/tuqunfu/p/15594455.html
Copyright © 2011-2022 走看看