如何使用Log4Net实现日志文件的自动归档

本文关键字:文件 何使用 Log4Net 实现 日志 | 更新日期: 2023-09-27 18:26:00

我想以这样一种方式配置log4net,即前一天的所有日志都应该自动存档。是否有可能在Log4Net中自动存档以前的日志。我只想使用配置来完成这项工作,而不需要使用任何第三方库(如sharplibzip)来编写任何代码来创建归档。

还有一点需要补充,归档我的意思是将文件压缩为zip/rar格式以节省磁盘空间。

如何使用Log4Net实现日志文件的自动归档

如果不编写代码,就无法归档文件,抱歉。然而,代码不会很复杂。

您可以创建一个从RollingFileAppender继承的自定义appender,并覆盖AdjustFileBeforeAppend方法,以便将行为添加到文件滚动中。以下是为RollingFileAppender滚动文件的现有方法,您可以覆盖该方法以添加存档。

使用File属性查找文件名进程it

// log4net.Appender.RollingFileAppender
protected virtual void AdjustFileBeforeAppend()
{
    var fileToZip = File; // save the current file
    if (this.m_rollDate)
    {
        DateTime now = this.m_dateTime.Now;
        if (now >= this.m_nextCheck)
        {
            this.m_now = now;
            this.m_nextCheck = this.NextCheckDate(this.m_now, this.m_rollPoint);
            this.RollOverTime(true);
            // zip the file if roll occurs here
        }
    }
    if (this.m_rollSize)
    {
        if (this.File != null && ((CountingQuietTextWriter)base.QuietWriter).Count >= this.m_maxFileSize)
        {
            this.RollOverSize();
            // zip the file if roll occurs here
        }
    }
}

或者,你可以找到一个现有的appender来做你想做的事情,但我不知道有。


我冒昧地将@stuartd的评论作为答案,因为他的建议相当优雅。您可以通过以下方式简单地覆盖AdjustFileBeforeAppend

protected override void AdjustFileBeforeAppend() {
    var previousFile = File;
    base.AdjustFileBeforeAppend();
    if (File != previousFile) { // zip the file }
}

这是一种非常巧妙的方法,但你可能希望能够区分这两种面包卷(即日期和大小)。例如,为了将某个日期范围的文件放在一起,只对日期滚动进行压缩。

log4net不包含任何压缩日志文件的功能。然而,压缩是在.Net框架中进行的(自4.5起),或者您可以使用WindowsShellneneneba API来压缩文件,因此您可以使用定期获取所有不是当前日志文件的日志文件并将其压缩的代码:

-- assuming you don't have more that one appender
appender = LogManager.GetRepository().GetAppenders()
                     .OfType<RollingFileAppender>().FirstOrDefault();
if (appender == null) return; // no appenders found
var currentFile = appender.File;
-- dropping to pseudocode:
var files = Get_all_files_in_log_directory_which_match_log_file_pattern 
         but_aren't_the_current_file(current file);
if (ZipFiles(files...))
    (DeleteFiles(files); // presumably

这是我使用DotNetZip精简的解决方案。

public class CustomRollingFileAppender : RollingFileAppender
    {
        protected override void AdjustFileBeforeAppend()
        {
            var currentFile = File;
            FileInfo fa = new System.IO.FileInfo(currentFile);
            if (fa.Length >= 10000000)
            {
                using (ZipFile zip = new ZipFile(File + ".zip"))
                {
                    string newFile =  DateTime.Now.ToString("HHmmss") + fa.Name;
                    zip.AddFile(File).FileName = newFile;
                    zip.Save(File + ".zip");
                }
            }
            base.AdjustFileBeforeAppend();
        }
    }

我想指出,正确实现这一点的唯一方法是完全复制RollingFileAppender源代码,并从中创建FileAppender的子类。在这段代码中,您可以在adjustFileBeforeAppend()中添加压缩部分。

上面萨米的建议不起作用

  1. 因为第一个代码片段使用私有成员(不能在子类中访问)
  2. 因为第二个代码片段假设当前日志文件名包含日期左右。但实际上,日期模式只适用于所有旧文件,而不适用于当前文件。因此,您无法确定文件是否按照代码段中显示的方式滚动

这里有一个建议。这是一个工作代码。它还避免在每次日志附加时读取文件信息。相反,它将在第一个文件滚动时工作。基于时间或基于大小。二者都一旦它正在压缩当前文件。它也会gzip退出旧文件。这是在应用程序停止后留下的。它不需要重新编码所有RollingFileAppender类。

public class CustomRollingFileAppender : RollingFileAppender
{
   
    override protected void AdjustFileBeforeAppend()
    {
        var currentFile = this.File;
        base.AdjustFileBeforeAppend();
        if (!currentFile.Equals(this.File))
        {
            CompressFileGzip(currentFile);
            var dirName = Path.GetDirectoryName(this.File);
            var files = Directory.GetFiles(dirName);
            var fileExtension = Path.GetExtension(this.File);
            foreach (var file in files)
            {
                if (!file.EndsWith(this.File) && file.EndsWith(fileExtension))
                {
                    CompressFileGzip(file.ToString());
                }
            }
        }
    }
    private void CompressFileGzip(string fileToGzip)
    {
        if (!FileExists(fileToGzip))
        {
            return;
        }
        FileInfo fileToBeGZipped = new FileInfo(fileToGzip);
        FileInfo gzipFileName = new FileInfo(string.Concat(fileToBeGZipped.FullName, ".gz"));
        using (FileStream fileToBeZippedAsStream = fileToBeGZipped.OpenRead())
        {
            using (FileStream gzipTargetAsStream = gzipFileName.Create())
            {
                using (GZipStream gzipStream = new GZipStream(gzipTargetAsStream, CompressionMode.Compress))
                {
                    fileToBeZippedAsStream.CopyTo(gzipStream);
                }
            }
        }
        System.IO.File.Delete(fileToGzip);
    }
}

我修改了Masood的实现,但我没有使用File属性(似乎没有更改),而是读取了;移动[自]->[至]";事件

在gz中添加了一个filetime以避免多个";myLog.xml.1.gz";冲突不想对文件名进行更好的清理。

public class CompressedRollingFileAppender : RollingFileAppender {
        private readonly Regex _moveRegex;
        private string _moveToFile = null;
        public CompressedRollingFileAppender() : base() {
            LogLog.LogReceived += LogReceived;
            _moveRegex = new Regex(@"^Moving '[(.+)'] -> '[(.+)']$");
        }
        private void LogReceived(object source, LogReceivedEventArgs e) {
            var match = _moveRegex.Match(e.LogLog.Message);
            if (match.Groups[1].Value == this.File) {
                _moveToFile = match.Groups[2].Value;
            }
        }
        protected override void AdjustFileBeforeAppend() {
            var currentFile = this.File;
            base.AdjustFileBeforeAppend();
            if (_moveToFile != null) {
                CompressFileGzip(_moveToFile);
                _moveToFile = null;
            }
        }
        private void CompressFileGzip(string fileToGzip) {
            if (!FileExists(fileToGzip)) {
                return;
            }
            FileInfo fileToBeGZipped = new FileInfo(fileToGzip);
            // filetime 
            var filetime = DateTime.Now.ToFileTimeUtc().ToString(System.Globalization.CultureInfo.InvariantCulture);
            FileInfo gzipFileName = new FileInfo(string.Concat(fileToBeGZipped.FullName, "." + filetime + ".gz"));
            using (FileStream fileToBeZippedAsStream = fileToBeGZipped.OpenRead())
            using (FileStream gzipTargetAsStream = gzipFileName.Create())
            using (GZipStream gzipStream = new GZipStream(gzipTargetAsStream, CompressionMode.Compress))
                fileToBeZippedAsStream.CopyTo(gzipStream);
            System.IO.File.Delete(fileToGzip);
        }
    }