Use of log component based on log4net

1, Foreword

When the system is running, files need to be used in production to record some logs during system operation, such as system docking log, error information, warning information or specific debugging information. By tracing the recorded information back to the system execution process, find system problems and help developers solve online problems. This system uses log components, and generally has corresponding open source components, such as log4net.

2, Use

1. The log4net component is introduced into the project reference, and then the log configuration file is configured. The configuration information involves folder location, file name format, maximum file size, file content format, log level and other information, such as 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">
      <!--Log path-->
      <param name= "File" value= "logs\Info\log_"/>
      <!--Whether to append log to file-->
      <param name= "AppendToFile" value= "true"/>
      <!--log Retention days-->
      <param name= "MaxSizeRollBackups" value= "10"/>
      <!--Is the log file name fixed-->
      <param name= "StaticLogFileName" value= "false"/>
      <!--The format of log file name is-->
      <param name= "DatePattern" value= "yyyy-MM-dd&quot;.log&quot;"/>
      <!--The log scrolls by date-->
      <param name= "RollingStyle" value= "Date"/>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="Recording time:%date thread  ID:[%thread] Log level:  %-5level Class:%logger  - Description:%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="Recording time:%date thread  ID:[%thread] Log level:  %-5level Class:%logger  - Description:%message %n"/>
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="ERROR" />
        <param name="LevelMax" value="FATAL" />
      </filter>
    </appender>
    <root>
      <!--(high) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (low) -->
      <level value="ALL" />
      <appender-ref ref="RollingLogFileAppender" />
      <appender-ref ref="RollingFile" />
    </root>
  </log4net>
</configuration>

Through this log file definition basic information, you can generate the desired log file in the print log.

2. Use the configuration file in the project code, provide the method of writing log, define a log interface (using file or database), and record log information in the form of file through log4net component.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TQF.Logger.Logger
{
    /// <summary>
    /// Define log interface class
    /// </summary>
    public interface ILogger
    {
        /// <summary>
        /// Debug log output
        /// </summary>
        /// <param name="msg">Output content</param>
        void Debug(string msg);

        /// <summary>
        /// Debug log output
        /// </summary>
        /// <param name="msg">Output content</param>
        /// <param name="ex">Output exception</param>
        void Debug(string msg, Exception ex);

        /// <summary>
        /// Information log output
        /// </summary>
        /// <param name="msg">Output content</param>
        void Info(string msg);

        /// <summary>
        /// Information log output
        /// </summary>
        /// <param name="msg">Output content</param>
        /// <param name="ex">Output exception</param>
        void Info(string msg, Exception ex);

        /// <summary>
        /// Warning log output
        /// </summary>
        /// <param name="msg">Output content</param>
        void Warn(string msg);

        /// <summary>
        /// Warning log output
        /// </summary>
        /// <param name="msg">Output content</param>
        /// <param name="ex">Output exception</param>
        void Warn(string msg, Exception ex);

        /// <summary>
        /// Error log output
        /// </summary>
        /// <param name="msg">Output content</param>
        void Error(string msg);

        /// <summary>
        /// Error log output
        /// </summary>
        /// <param name="msg">Output content</param>
        /// <param name="ex">Output exception</param>
        void Error(string msg, Exception ex);

        /// <summary>
        /// Fatal log output
        /// </summary>
        /// <param name="msg">Output content</param>
        void Fatal(string msg);

        /// <summary>
        /// Fatal log output
        /// </summary>
        /// <param name="msg">Output content</param>
        /// <param name="ex">Output exception</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>
    /// Log interface implementation class
    /// </summary>
    public class Log4Helper : ILogger
    {
        /// <summary>
        /// Consider using a thread safe dictionary
        /// </summary>
        private Dictionary<string, ILog> LogDic = new Dictionary<string, ILog>();
        
        /// <summary>
        /// Define lock object
        /// </summary>
        private object _islock = new object();

        /// <summary>
        /// Define file name
        /// </summary>
        private string fileName = string.Empty;

        
        /// <summary>
        /// Initialize with constructor log call
        /// </summary>
        /// <param name="fileSavePath">Log file save path[If the path is empty, the default is the program root directory Logger folder;]</param>
        /// <param name="fileName">Log file name[If the file name is empty, the default file name is: 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>
        /// Cache log objects (CACHE log objects through log file names to reduce the creation of log objects)
        /// </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>
        /// Logging initialization
        /// </summary>
        private void Init()
        {
            // Get log profile
            var file = new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log4net.config"));
            // Detect whether the configuration file exists
            if (file.Exists)
            {
                //Load profile
                XmlConfigurator.Configure(file);
            }
            else
            {
                new Exception("Log profile not found!");
            }
        }


        /// <summary>
        /// Debug log output
        /// </summary>
        /// <param name="msg">content</param>
        public void Debug(string msg)
        {
            var log = GetLog(this.fileName);
            if (log == null)
            {
                return;
            }
            log.Debug(msg);
        }

        /// <summary>
        /// Debug log output
        /// </summary>
        /// <param name="msg">Output content</param>
        /// <param name="ex">Output exception</param>
        public void Debug(string msg, Exception ex)
        {
            var log = GetLog(this.fileName);
            if (log == null)
            {
                return;
            }
            log.Debug(msg, ex);
        }

        /// <summary>
        /// Error log output
        /// </summary>
        /// <param name="msg">Output content</param>
        public void Error(string msg)
        {
            var log = GetLog(this.fileName);
            if (log == null)
            {
                return;
            }
            log.Error(msg);
        }

        /// <summary>
        /// Error log output
        /// </summary>
        /// <param name="msg">Output content</param>
        /// <param name="ex">Output exception</param>
        public void Error(string msg, Exception ex)
        {
            var log = GetLog(this.fileName);
            if (log == null)
            {
                return;
            }
            log.Error(msg, ex);
        }

        /// <summary>
        /// Fatal log output
        /// </summary>
        /// <param name="msg">Output content</param>
        public void Fatal(string msg)
        {
            var log = GetLog(this.fileName);
            if (log == null)
            {
                return;
            }
            log.Fatal(msg);
        }

        /// <summary>
        /// Fatal log output
        /// </summary>
        /// <param name="msg">Output content</param>
        /// <param name="ex">Output exception</param>
        public void Fatal(string msg, Exception ex)
        {
            var log = GetLog(this.fileName);
            if (log == null)
            {
                return;
            }
            log.Fatal(msg, ex);
        }

        /// <summary>
        /// Information log output
        /// </summary>
        /// <param name="msg">Output content</param>
        public void Info(string msg)
        {
            var log = GetLog(this.fileName);
            if (log == null)
            {
                return;
            }
            log.Info(msg);
        }

        /// <summary>
        /// Information log output
        /// </summary>
        /// <param name="msg">Output content</param>
        /// <param name="ex">Output exception</param>
        public void Info(string msg, Exception ex)
        {
            var log = GetLog(this.fileName);
            if (log == null)
            {
                return;
            }
            log.Info(msg, ex);
        }

        /// <summary>
        /// Warning log output
        /// </summary>
        /// <param name="msg">Output content</param>
        public void Warn(string msg)
        {
            var log = GetLog(this.fileName);
            if (log == null)
            {
                return;
            }
            log.Warn(msg);
        }

        /// <summary>
        /// Warning log output
        /// </summary>
        /// <param name="msg">Output content</param>
        /// <param name="ex">Output exception</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>
    /// If the configuration file does not set the property "copy to output directory", it will not be in the debug The file does not exist
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            var log4Helper = new Log4Helper(string.Empty, "program");
            log4Helper.Info("info");
        }
    }
}

Through the above code, define the log interface (write methods, write methods at different levels) and log help class implementation interface, and use components to read configuration files, obtain log objects and write logs.

3. The above is the folder, file name and file content format defined according to the configuration file format, which is relatively standardized. If the system wants to record a single log information, such as uncertain folder name and uncertain file name, it needs to be defined by the developer.

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 Custom log class
    /// </summary>
    public static class LogCustomHelper
    {
        /// <summary>
        /// Type safe dictionary object
        /// </summary>
        private static readonly ConcurrentDictionary<string, ILog> loggerContainer = new ConcurrentDictionary<string, ILog>();

        //Default configuration 
        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>
        /// Get log object
        /// </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>
        /// Custom log folder and file path
        /// </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>
        /// Get log level
        /// </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>
        /// Get configuration information
        /// </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>
        /// Write log information
        /// </summary>
        /// <param name="folderName">Folder name</param>
        /// <param name="fileName">File name</param>
        /// <param name="message">log information</param>
        public static void Info(string folderName, string fileName,string message)
        {
            ILog logger = GetCustomLogger(fileName, folderName);
            logger.Info(message);
        }
    }
}

The log storage is defined by passing in the folder and file name when writing the log. This method can meet the specific storage requirements for special log information.

summary

1. Recording logs in the system production environment can help users locate system problems, solve system problems, capture and record abnormal errors that may occur in the process of system execution, and backtrack the whole process of execution.

2. System logs can be stored not only in file mode, but also in database mode.

 

Posted on Tue, 23 Nov 2021 07:35:04 -0500 by sgboise