首页 > 解决方案 > 创建基于日期的 Log4net 滚动文件

问题描述

我需要为 45 个不同的位置(例如:波士顿、伦敦等)创建文件。这些文件名必须基于日期。我还可以提供滚动文件的最大文件大小和滚动文件的最大数量。

基本上文件名必须如下所示:Info_Boston_(2019.02.25).txt

到目前为止,我已经想出了下面的代码来获取日期。但我无法将文件大小限制为 1MB。该文件超过 1MB,并且不会创建新的滚动文件。请协助

    <appender name="MyAppenderInfo" type="log4net.Appender.RollingFileAppender">
  <param name="File" value="C:\\ProgramData\\Service\\Org\\Info"/>
  <param name="RollingStyle" value="Date"/>
  <param name="DatePattern" value="_(yyyy.MM.dd).\tx\t"/>
  <param name="StaticLogFileName" value="false"/>
  <maxSizeRollBackups value="10" />
  <maximumFileSize value="1MB" />
  <appendToFile value="true" />
  <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date %message%n" />
  </layout>
  <filter type="log4net.Filter.LevelRangeFilter">
    <levelMin value="DEBUG" />
    <levelMax value="INFO" />
  </filter>
</appender>

标签: datedynamiclog4net

解决方案


为了解决您的特定帖子,我不会使用基于配置的方法来执行此操作,因为我认为管理起来会相当麻烦。一种更加程序化的方法是动态生成日志实例。

编辑:我删除了原件以发布基于此 SO post log4net 的重做示例:运行时不同文件附加程序上的不同日志

EDIT-2:我不得不再次返工,因为我意识到我遗漏了一些必需的部分,并且在返工后出现了一些问题。这是经过测试和工作的。但是,有几点需要注意,您需要在控制器上为您创建的日志记录类提供 using 语句。接下来,您将需要像我所做的那样 DI 您的日志目录,或者想出另一种提供日志文件输出列表的方法。

这将允许您非常干净地动态生成尽可能多的日志记录实例,以及您想要的尽可能多的独立位置。我从我做的一个项目中提取了这个示例,并对其进行了一些修改以满足您的需求。如果您有任何问题,请告诉我。

创建一个继承自层次结构中的基本记录器的动态记录器类:

using log4net;
using log4net.Repository.Hierarchy;

public sealed class DynamicLogger : Logger
{
    private const string REPOSITORY_NAME = "somename";
    internal DynamicLogger(string name) : base(name)
    {
        try
        {
            // try and find an existing repository
            base.Hierarchy = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository(REPOSITORY_NAME);
        }   // try
        catch
        {
            // it doesnt exist, make it.
            base.Hierarchy = (log4net.Repository.Hierarchy.Hierarchy)LogManager.CreateRepository(REPOSITORY_NAME);
        }   // catch
    }   // ctor(string)
}   // DynamicLogger

然后,构建一个类来管理日志实例,并构建新的记录器:

using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Core;
using log4net.Filter;
using log4net.Layout;
using log4net.Repository;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Linq;

public class LogFactory
{
    private static List<ILog> _Loggers = new List<ILog>();
    private static LoggingConfig _Settings;
    private static ILoggerRepository _Repository;

    public LogFactory(IOptions<LoggingConfig> configuration)
    {
        _Settings = configuration.Value;
        ConfigureRepository(REPOSITORY_NAME);
    }   // ctor(IOptions<LoggingConfig>)

    /// <summary>
    /// Configures the primary logging repository.
    /// </summary>
    /// <param name="repositoryName">The name of the repository.</param>
    private void ConfigureRepository(string repositoryName)
    {
        if(_Repository == null)
        {
            try
            {
                _Repository = LogManager.CreateRepository(repositoryName);
            }
            catch
            {
                // repository already exists.
                _Repository = LogManager.GetRepository(repositoryName);
            }   // catch
        }   // if
    }   // ConfigureRepository(string)

    /// <summary>
    /// Gets a named logging instance, if it exists, and creates it if it doesnt.
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public ILog GetLogger(string name)
    {
        string filePath = string.Empty;

        switch (name)
        {
            case "core":
                filePath = _Settings.CoreLoggingDirectory;
                break;
            case "image":
                filePath = _Settings.ImageProcessorLoggingDirectory;
                break;
        }   // switch

        if (_Loggers.SingleOrDefault(a => a.Logger.Name == name) == null)
        {
            BuildLogger(name, filePath);
        }   // if

        return _Loggers.SingleOrDefault(a => a.Logger.Name == name);
    }   // GetLogger(string)

    /// <summary>
    /// Dynamically build a new logging instance.
    /// </summary>
    /// <param name="name">The name of the logger (Not file name)</param>
    /// <param name="filePath">The file path you want to log to.</param>
    /// <returns></returns>
    private ILog BuildLogger(string name, string filePath)
    {
        // Create a new filter to include all logging levels, debug, info, error, etc.
        var filter = new LevelMatchFilter();
        filter.LevelToMatch = Level.All;
        filter.ActivateOptions();

        // Create a new pattern layout to determine the format of the log entry.
        var pattern = new PatternLayout("%d %-5p %c %m%n");
        pattern.ActivateOptions();

        // Dynamic logger inherits from the hierarchy logger object, allowing us to create dynamically generated logging instances.
        var logger = new DynamicLogger(name);
        logger.Level = Level.All;

        // Create a new rolling file appender
        var rollingAppender = new RollingFileAppender();
        // ensures it will not create a new file each time it is called.
        rollingAppender.AppendToFile = true;
        rollingAppender.Name = name;
        rollingAppender.File = filePath;
        rollingAppender.Layout = pattern;
        rollingAppender.AddFilter(filter);
        // allows us to dynamically generate the file name, ie C:\temp\log_{date}.log
        rollingAppender.StaticLogFileName = false;
        // ensures that the file extension is not lost in the renaming for the rolling file
        rollingAppender.PreserveLogFileNameExtension = true;
        rollingAppender.DatePattern = "yyyy-MM-dd";
        rollingAppender.RollingStyle = RollingFileAppender.RollingMode.Date;
        // must be called on all attached objects before the logger can use it.
        rollingAppender.ActivateOptions();
        logger.AddAppender(rollingAppender);

        // Sets the logger to not inherit old appenders, or the core appender.
        logger.Additivity = false;
        // sets the loggers effective level, determining what level it will catch log requests for and log them appropriately.
        logger.Level = Level.Info;
        // ensures the new logger does not inherit the appenders of the previous loggers.
        logger.Additivity = false;

        // The very last thing that we need to do is tell the repository it is configured, so it can bind the values.
        _Repository.Configured = true;

        // bind the values.
        BasicConfigurator.Configure(_Repository, rollingAppender);

        LogImpl newLog = new LogImpl(logger);


        _Loggers.Add(newLog);

        return newLog;
    }   // BuildLogger(string, string)
}   // LogFactory

然后,在您的依赖注入中,您可以注入您的日志工厂。你可以这样做:

services.AddSingleton<LogFactory>();

然后在您的控制器或任何构造函数中,您可以执行以下操作:

    private LogFactory _LogFactory;

    public HomeController(LogFactory logFactory){
        _LogFactory = logFactory;
    }

    public async Task<IActionResult> Index()
    {
        ILog logger1 = _LogFactory.GetLogger("core");
        ILog logger2 = _LogFactory.GetLogger("image");
        logger1.Info("SomethingHappened on logger 1");
        logger2.Info("SomethingHappened on logger 2");
        return View();
    }

此示例将输出:

2019-03-07 10:41:21,338 INFO  core SomethingHappened on logger 1

在它自己的文件中称为Core_2019-03-07.log

并且:

2019-03-07 11:06:29,155 INFO  image SomethingHappened on logger 2

在它自己的文件中称为Image_2019-03-07

希望这更有意义!


推荐阅读