Log4Net: 使用滚动日期设置 RollingFileAppender 上的最大备份文件

我有以下配置,但我找不到任何文档说明如何设置日期滚动风格的最大备份文件。我知道您可以通过使用 maxSizeRollBackups 来实现大小滚动样式。

<appender name="AppLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="mylog.log" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<rollingStyle value="Date" />
<datePattern value=".yyMMdd.'log'" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d %-5p %c - %m%n"  />
</layout>
</appender>
75910 次浏览

不确定你需要什么,下面是我的 lo4net.config 文件的摘录:

  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<param name="File" value="App_Data\log"/>
<param name="DatePattern" value=".yyyy-MM-dd-tt&quot;.log&quot;"/>
<param name="AppendToFile" value="true"/>
<param name="RollingStyle" value="Date"/>
<param name="StaticLogFileName" value="false"/>
<param name="maxSizeRollBackups" value="60" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%r %d [%t] %-5p %c - %m%n"/>
</layout>
</appender>

你不能。

来自 Log4net SDK 参考
RollingFileAppender 类

注意

不支持按日期/时间边界滚动时备份文件的最大数量。

几个月前我花了点时间调查这件事。10版不支持基于滚动日期删除旧的日志文件。它在下一个版本的任务列表中。我自己编写了源代码并添加了这个功能,如果其他人感兴趣,我就把它发布给他们。问题和补丁可以在 https://issues.apache.org/jira/browse/LOG4NET-27找到。

尽管它不支持,下面是我处理这种情况的方法:

这是我的配置:

    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:\logs\LoggingTest\logfile.txt" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<datePattern value="yyyyMMdd" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1MB" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date  - %message%newline" />
</layout>
</appender>

在申请启动时,我会这样做:

 XmlConfigurator.Configure();
var date = DateTime.Now.AddDays(-10);
var task = new LogFileCleanupTask();
task.CleanUp(date);

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;


using log4net;
using log4net.Appender;
using log4net.Config;


public class LogFileCleanupTask
{
#region - Constructor -
public LogFileCleanupTask()
{
}
#endregion


#region - Methods -
/// <summary>
/// Cleans up. Auto configures the cleanup based on the log4net configuration
/// </summary>
/// <param name="date">Anything prior will not be kept.</param>
public void CleanUp(DateTime date)
{
string directory = string.Empty;
string filePrefix = string.Empty;


var repo = LogManager.GetAllRepositories().FirstOrDefault(); ;
if (repo == null)
throw new NotSupportedException("Log4Net has not been configured yet.");


var app = repo.GetAppenders().Where(x => x.GetType() == typeof(RollingFileAppender)).FirstOrDefault();
if (app != null)
{
var appender = app as RollingFileAppender;


directory = Path.GetDirectoryName(appender.File);
filePrefix = Path.GetFileName(appender.File);


CleanUp(directory, filePrefix, date);
}
}


/// <summary>
/// Cleans up.
/// </summary>
/// <param name="logDirectory">The log directory.</param>
/// <param name="logPrefix">The log prefix. Example: logfile dont include the file extension.</param>
/// <param name="date">Anything prior will not be kept.</param>
public void CleanUp(string logDirectory, string logPrefix, DateTime date)
{
if (string.IsNullOrEmpty(logDirectory))
throw new ArgumentException("logDirectory is missing");


if (string.IsNullOrEmpty(logPrefix))
throw new ArgumentException("logPrefix is missing");


var dirInfo = new DirectoryInfo(logDirectory);
if (!dirInfo.Exists)
return;


var fileInfos = dirInfo.GetFiles("{0}*.*".Sub(logPrefix));
if (fileInfos.Length == 0)
return;


foreach (var info in fileInfos)
{
if (info.CreationTime < date)
{
info.Delete();
}
}


}
#endregion
}

Sub Method 是一个扩展方法,它基本上是这样包装 string.format 的:

/// <summary>
/// Extension helper methods for strings
/// </summary>
[DebuggerStepThrough, DebuggerNonUserCode]
public static class StringExtensions
{
/// <summary>
/// Formats a string using the <paramref name="format"/> and <paramref name="args"/>.
/// </summary>
/// <param name="format">The format.</param>
/// <param name="args">The args.</param>
/// <returns>A string with the format placeholders replaced by the args.</returns>
public static string Sub(this string format, params object[] args)
{
return string.Format(format, args);
}
}

从 log4net appender 继承并添加您自己的重写方法(执行文件清理)是相当容易的。我重写了 OpenFile 来做这件事。下面是一个自定义 log4net 追加器的示例,可以帮助您入门: https://stackoverflow.com/a/2385874/74585

我最近在尝试清理基于传递到我的服务中的 maxAgeInDays 配置值的日志时遇到了这种需求... ... 就像我之前遇到的许多人一样,我开始使用 NTFS 的“特性”隧道,这使得使用 FileInfo。CreationDate 有问题(尽管我后来也解决了这个问题) ..。

因为我有一个模式去关闭,我决定只是滚动我自己的清除方法... 我的日志记录器是编程配置,所以我只是调用后,我的日志记录器设置已经完成..。

    //.........................
//Log Config Stuff Above...


log4net.Config.BasicConfigurator.Configure(fileAppender);
if(logConfig.DaysToKeep > 0)
CleanupLogs(logConfig.LogFilePath, logConfig.DaysToKeep);
}


static void CleanupLogs(string logPath, int maxAgeInDays)
{
if (File.Exists(logPath))
{
var datePattern = "yyyy.MM.dd";
List<string> logPatternsToKeep = new List<string>();
for (var i = 0; i <= maxAgeInDays; i++)
{
logPatternsToKeep.Add(DateTime.Now.AddDays(-i).ToString(datePattern));
}


FileInfo fi = new FileInfo(logPath);


var logFiles = fi.Directory.GetFiles(fi.Name + "*")
.Where(x => logPatternsToKeep.All(y => !x.Name.Contains(y) && x.Name != fi.Name));


foreach (var log in logFiles)
{
if (File.Exists(log.FullName)) File.Delete(log.FullName);
}
}
}

可能不是最好的方法,但对我们的目的来说效果不错..。

为了限制日志的数量,不要在 datePattern 中包含年或月,例如 datePattern value = “ _ dd’. log’”

这将每天创建一个新的日志,下个月它将被覆盖。

NLog ,其设置方式与 Log4Net (& 是积极维护的-甚至支持。NET 核心) ,支持基于日期的滚动日志。

不再担心更复杂的 x 每日期,只是指定和任意的文件计数,只是把这一个放在一起。小心 [安全行动. 要求]

public string LogPath { get; set; }
public int MaxFileCount { get; set; } = 10;


private FileSystemWatcher _fileSystemWatcher;


[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public async Task StartAsync()
{
await Task.Yield();


if (!Directory.Exists(LogPath))
{ Directory.CreateDirectory(LogPath); }


_fileSystemWatcher = new FileSystemWatcher
{
Filter = "*.*",
Path = LogPath,
EnableRaisingEvents = true,
NotifyFilter = NotifyFilters.FileName
| NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.Security
| NotifyFilters.Size
};


_fileSystemWatcher.Created += OnCreated;
}


public async Task StopAsync()
{
await Task.Yield();


_fileSystemWatcher.Created -= OnCreated; // prevents a resource / memory leak.
_fileSystemWatcher = null; // not using dispose allows us to re-start if necessary.
}


private void OnCreated(object sender, FileSystemEventArgs e)
{
var fileInfos = Directory
.GetFiles(LogPath)
.Select(filePath => new FileInfo(filePath))
.OrderBy(fileInfo => fileInfo.LastWriteTime)
.ToArray();


if (fileInfos.Length <= MaxFileCount)
{ return; }


// For every file (over MaxFileCount) delete, starting with the oldest file.
for (var i = 0; i < fileInfos.Length - MaxFileCount; i++)
{
try
{
fileInfos[i].Delete();
}
catch (Exception ex)
{
/* Handle */
}
}
}