首页 > 解决方案 > NLog中的顺序文件名

问题描述

我希望动态更改我的文件名并包含一个序列号。每次归档过程/日志轮换时,应更改文件名(增加数字)。归档文件时,归档文件名应与带序号的文件名相同(递增前)。

从文件名“file.log.1”开始,归档时归档文件名将是“file.log.1”,文件名将更改为“file.log.2”。下一个存档文件名将是“file.log.2”等等...

可以使用 NLog 吗?在网络或 NLog 源代码中没有找到任何线索。

标签: c#loggingnlog

解决方案


所以我实现了一个自定义 FileTarget 来满足我的需求:

internal sealed class CustomFileTarget : NLog.Targets.FileTarget
{
    private const int _maxOldFilesToKeep = 10;

    private readonly string _directory;
    private readonly long _fileMaxSize = (long)10.Megabytes().Bytes;
    private readonly string _fileNamePrefix;

    private int _sequential;

    private string FullFileName => $"{Path.Combine(_directory, _fileNamePrefix)}.{_sequential}.log";

    public CustomFileTarget(string directory, string fileNamePrefix)
    {
        _directory = directory;
        _fileNamePrefix = fileNamePrefix;
        _sequential = GetLatestSequence() ?? 0;

        ConcurrentWrites = false;
        FileName = FullFileName;
        KeepFileOpen = false;
    }

    protected override void Write(IList<AsyncLogEventInfo> logEvents)
    {
        base.Write(logEvents);

        if (GetFileSize() >= _fileMaxSize)
        {
            ChangeName();
            DeleteOld();
        }
    }

    private long GetFileSize() =>
        new FileInfo(FullFileName).Length;

    private void ChangeName()
    {
        _sequential++;
        FileName = FullFileName;
        LogManager.ReconfigExistingLoggers();
    }

    private void DeleteOld()
    {
        var fileNamesAndSequences = GetFileNamesAndSequences();
        if (fileNamesAndSequences.Count() > _maxOldFilesToKeep + 1)
        {
            fileNamesAndSequences.Take(
                fileNamesAndSequences.Count() - _maxOldFilesToKeep + 1)
                .ForEach(
                    _ => Directory.Delete(Path.Combine(_directory, _.FileName)));
        }
    }

    private int? GetLatestSequence()
    {
        var fileNamesAndSequences = GetFileNamesAndSequences();
        return fileNamesAndSequences.Any()
            ? fileNamesAndSequences.Last().Sequence
            : (int?)null;
    }

    private IEnumerable<(string FileName, int Sequence)> GetFileNamesAndSequences() =>
        Directory.GetFiles(_directory, $"{_fileNamePrefix}*.log").
            Select(
                _ =>
                {
                    var fileNameParts = _.Split('.');
                    return (_, Sequence: int.Parse(fileNameParts[fileNameParts.Length - 2]));
                }).
            OrderBy(_ => _.Sequence);
}

推荐阅读