它可以实现,但不只是通过配置。
习惯
RollingFileAppender
必须在中创建和引用
Log4net
配置如下所示,其中
PFX.RollingFileAppender
从程序集加载
PFX.Lib
.
设置
staticLogFileName
确保最新的文件始终命名为
Log.txt
(按配置)。
我们使用
datePattern
在日志文件名中配置日期部分的选项。
(出于性能原因,
countDirection
设置为值0以减少滚动次数;最新/最后一个备份文件将是数字最大的文件。)
<log4net>
<appender name="RollingFileAppender" type="PFX.CustomRollingFileAppender, PFX.Lib" >
<datePattern value="yyyy-MM-dd" />
<staticLogFileName value="true" />
<countDirection value="0" />
<file value="${LOCALAPPDATA}\foobar\Log.txt" />
<encoding value="utf-8" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maximumFileSize value="1MB" />
<maxSizeRollBackups value="1000" />
<preserveLogFileNameExtension value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level [%thread] %type.%method - %message%n" />
</layout>
</appender>
<root>
<level value="All" />
<appender-ref ref="RollingFileAppender" />
</root>
</log4net>
要求中最具挑战性的部分是排除文件名中的索引/计数器后缀;如Log-2018-07-16。
一
TXT
由于log4net内部跟踪并使用此计数器号来处理备份文件删除等问题。
因此,我们必须自己管理清理工作。
log4net的实现
滚动文件
不是很开放;要重写的方法很少
并且无法访问当前的计数器编号跟踪。
如果您不能或不想包括和修改原始代码的完整源代码
滚动文件
在你自己的项目中,
您可以从原始文件继承,以便尽可能少地进行更改,如下所示。
如果发生基于文件大小的汇总,我们将检查当前日志文件(与当前日期匹配;请参见要求)是否已存在。
如果是,则不会发生汇总;只有来自
日志.txt
移动到今天的日志文件。
如果今天的日志文件不存在,则会发生开箱即用的滚动。这将创建一个名称中带有索引/计数器后缀的文件;然后立即重命名该文件以匹配配置的日期模式。
因为创建了一个新文件,所以会删除任何未经处理的日志文件(超过配置的主动变更)。
(为了简洁起见,下面的代码不包含异常处理。)
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using log4net.Appender;
using log4net.Util;
namespace PFX
{
public class CustomRollingFileAppender : RollingFileAppender
{
private String _baseFileExtension;
private String _baseFileNameWithoutExtension;
private String _fileDeletePattern;
private String _folder;
private String _backupSearchPattern;
public CustomRollingFileAppender()
{}
public override void ActivateOptions()
{
base.ActivateOptions();
this._baseFileNameWithoutExtension = Path.GetFileNameWithoutExtension(this.File);
this._baseFileExtension = Path.GetExtension(this.File);
this._folder = Path.GetDirectoryName(this.File);
this._fileDeletePattern = $"{this._baseFileNameWithoutExtension}*{this._baseFileExtension}";
this._backupSearchPattern = $"{this._baseFileNameWithoutExtension}.*{this._baseFileExtension}";
}
protected override void AdjustFileBeforeAppend()
{
if ((RollingMode.Size == this.RollingStyle)
&& (this.File != null)
&& (((CountingQuietTextWriter)base.QuietWriter).Count >= this.MaxFileSize)
)
{
DateTime now = DateTime.Now;
String todayFileSuffix = now.ToString(this.DatePattern, CultureInfo.InvariantCulture);
String todayFileName = $"{this._baseFileNameWithoutExtension}{todayFileSuffix}{this._baseFileExtension}";
String todayFile = Path.Combine(this._folder, todayFileName);
if (base.FileExists(todayFile))
{
base.CloseFile();
this.moveContentToTodaysFile(todayFile);
base.DeleteFile(this.File);
base.OpenFile(this.File, false);
}
else
{
base.RollOverSize();
using (base.SecurityContext.Impersonate(this))
{
this.deleteDepricatedBackupFiles();
this.renameBackupFiles(todayFile);
}
}
}
else
{
base.AdjustFileBeforeAppend();
}
}
private void moveContentToTodaysFile(String todayFile)
{
using (FileStream logFile = new FileStream(this.File, FileMode.Open, FileAccess.Read, FileShare.Read))
using (StreamReader reader = new StreamReader(logFile))
using (FileStream backupFile = new FileStream(todayFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
using (StreamWriter writer = new StreamWriter(backupFile))
{
const Int32 BUFFER_SIZE = 1024;
Char[] buffer = new Char[BUFFER_SIZE];
while (true)
{
Int32 nrOfCharsRead = reader.Read(buffer, 0, BUFFER_SIZE);
if (nrOfCharsRead <= 0) { break; }
writer.Write(buffer, 0, nrOfCharsRead);
}
}
}
private void renameBackupFiles(String todayFile)
{
IEnumerable<String> backupFiles = Directory.EnumerateFiles(this._folder, this._backupSearchPattern, SearchOption.TopDirectoryOnly);
foreach (String backupFile in backupFiles)
{
base.RollFile(backupFile, todayFile);
}
}
private void deleteDepricatedBackupFiles()
{
DirectoryInfo folder = new DirectoryInfo(this._folder);
IEnumerable<FileInfo> filesToDelete =
folder
.EnumerateFiles(this._fileDeletePattern, SearchOption.TopDirectoryOnly)
.OrderByDescending(o => o.LastWriteTime)
.Skip(this.MaxSizeRollBackups + 1)
;
foreach (FileSystemInfo fileToDelete in filesToDelete)
{
base.DeleteFile(fileToDelete.FullName);
}
}
}
}