NLog Zip 压缩 日志

使用NLog作为我开发的项目的日志引擎已经好几年了,前一段,某个系统需要大量的输出日志,每天大约20MB,所以打算把每天生成的日志文件压缩一下,然后只保存2个月的。

可是NLog提供的archive不提供压缩功能,所以,自己动手,丰衣足食。

0 下载源代码,准备压缩library

NLog的源代码在这里

https://github.com/jkowalski/NLog/archives/master

下载 .zip,解压缩。 我下载的版本是2.0.0.2007。

 然后使用的压缩library 是DotNetZip Library

在这里下载 http://dotnetzip.codeplex.com/ ,我使用的版本是 1.9.1.8

1 扩展?

 最初的想法是继承FileTarget类,写一个FileExTarget类实现压缩功能,可是尝试了一下,FileTarget没有为扩展提供函数,这种方式几乎不可能实现,所以放弃了。

2 改造

本次改造只涉及文件日志,所以目标文件只有一个:FileTarget.cs

添加下面的函数到 类的末尾

复制代码
  1 #if !SILVERLIGHT  && !NET_CF
  2         private void CompressFile(string fileSource, string fileDest)
  3         {
  4 
  5             try
  6             {
  7                 Type type = Type.GetType("Ionic.Zip.ZipFile,Ionic.Zip");
  8                 if (type != null)
  9                 {
 10                     object obj2 = Activator.CreateInstance(type);
 11                     Type[] types = new Type[] { typeof(string), typeof(string) };
 12                     type.GetMethod("AddFile", types).Invoke(obj2, new object[] { fileSource, "" });
 13                     types = new Type[] { typeof(string) };
 14                     type.GetMethod("Save", types).Invoke(obj2, new object[] { fileDest });
 15                     File.Delete(fileSource);
 16                 }
 17                 else
 18                 {
 19                     File.Move(fileSource, fileDest);
 20                 }
 21             }
 22             catch
 23             {
 24                 File.Move(fileSource, fileDest);
 25             }
 26         }
 27 
 28         private string ReplaceSeq(string pattern, object value)
 29         {
 30             int firstPart = pattern.IndexOf("{#");
 31             int lastPart = pattern.IndexOf("#}") + 2;
 32             int numDigits = lastPart - firstPart - 2;
 33 
 34             if (value is int)
 35             {
 36                 return pattern.Substring(0, firstPart) + Convert.ToString((int)value, 10).PadLeft(numDigits, '0') + pattern.Substring(lastPart);
 37             }
 38             else
 39             {
 40                 return pattern.Substring(0, firstPart) + value.ToString() + pattern.Substring(lastPart);
 41             }
 42         }
 43 
 44         private DateTime GetArchiveDateTime(int value)
 45         {
 46             switch (this.ArchiveEvery)
 47             {
 48                 case FileArchivePeriod.Year:
 49                     return DateTime.Now.AddYears(-1 * value);
 50                 case FileArchivePeriod.Month:
 51                     return DateTime.Now.AddMonths(-1 * value);
 52                 case FileArchivePeriod.Day:
 53                     return DateTime.Now.AddDays(-1 * value);
 54                 case FileArchivePeriod.Hour:
 55                     return DateTime.Now.AddHours(-1 * value);
 56                 case FileArchivePeriod.Minute:
 57                     return DateTime.Now.AddMinutes(-1 * value);
 58                 default:
 59                     return DateTime.MinValue;
 60             }
 61         }
 62 
 63         private string GetDateTimeFormat()
 64         {
 65             switch (this.ArchiveEvery)
 66             {
 67                 case FileArchivePeriod.Year:
 68                     return "yyyy";
 69                 case FileArchivePeriod.Month:
 70                     return "yyyyMM";
 71                 case FileArchivePeriod.Day:
 72                     return "yyyyMMdd";
 73                 case FileArchivePeriod.Hour:
 74                     return "yyyyMMddHH";
 75                 case FileArchivePeriod.Minute:
 76                     return "yyyyMMddHHmm";
 77                 default:
 78                     return string.Empty;
 79             }
 80         }
 81 
 82 
 83         private void DatetimeArchive(string fileName, string pattern)
 84         {
 85             string baseNamePattern = Path.GetFileName(pattern);
 86 
 87             int firstPart = baseNamePattern.IndexOf("{#", StringComparison.Ordinal);
 88             int lastPart = baseNamePattern.IndexOf("#}", StringComparison.Ordinal) + 2;
 89             int trailerLength = baseNamePattern.Length - lastPart;
 90 
 91             string fileNameMask = baseNamePattern.Substring(0, firstPart) + "*" + baseNamePattern.Substring(lastPart);
 92 
 93             string dirName = Path.GetDirectoryName(Path.GetFullPath(pattern));
 94             DateTime archiveTime = this.GetArchiveDateTime(1);
 95             DateTime checkTime = this.GetArchiveDateTime(this.MaxArchiveFiles);
 96             string dateFormat = this.GetDateTimeFormat();
 97 
 98             var file2Delete = new List<string>();
 99 
100             try
101             {
102 
103 
104                 foreach (string s in Directory.GetFiles(dirName, fileNameMask))
105                 {
106                     string baseName = Path.GetFileName(s);
107                     string strFileTime = baseName.Substring(firstPart, baseName.Length - trailerLength - firstPart);
108                     DateTime fileDate;
109 
110                     try
111                     {
112                         fileDate = DateTime.ParseExact(strFileTime, dateFormat, null);
113                     }
114                     catch (FormatException)
115                     {
116                         continue;
117                     }
118 
119                     if (fileDate < checkTime)
120                     {
121                         file2Delete.Add(s);
122                     }
123                 }
124             }
125             catch (DirectoryNotFoundException)
126             {
127                 Directory.CreateDirectory(dirName);
128             }
129 
130             if (file2Delete.Count > 0)
131             {
132                 foreach (string file in file2Delete)
133                 {
134                     File.Delete(file);
135                 }
136             }
137 
138             string newFileName = this.ReplaceSeq(pattern, archiveTime.ToString(dateFormat));
139             this.CompressFile(fileName, newFileName);
140         }
141 #endif
复制代码

然后修改DoAutoArchive函数
把 下面的代码

1                 case ArchiveNumberingMode.Sequence:
2                         this.SequentialArchive(fi.FullName, fileNamePattern);
3                     break;

改成

复制代码
                case ArchiveNumberingMode.Sequence:
#if !SILVERLIGHT  && !NET_CF
                    if (this.ArchiveEvery != FileArchivePeriod.None)
                    {
                        this.DatetimeArchive(fi.FullName, fileNamePattern);
                    }
                    else
                    {
#endif
                        this.SequentialArchive(fi.FullName, fileNamePattern);
#if !SILVERLIGHT  && !NET_CF
                    }
#endif
                    break;
复制代码

因为本次改造不对应sliverlight和net CF版,所以把编译器开关关掉。

退到上层目录,执行build.cmd, 编译成功,改造完成。

3 使用

首先把 Ionic.Zip.dll放到NLog.dll的同样目录下,然后在Nog的target 里指定archiveEvery,archiveFileName, maxArchiveFiles 属性就可以了。

 archiveEvery 是归档期间,可以是 Year,  Month,   Day,    Hour,   Minute

archiveFileName 是归档文件名的格式,基本是这样:{your log file path}/archive/log_{#}.zip

maxArchiveFiles ,归档文件数,如果超过了,会被删除。

最后典型的app.config里关于NLog的部分大约是这样的:

复制代码
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
  </configSections>
  <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <targets>

      <target name="file"
                            xsi:type="File"
                            layout="[${date:format=yyyyMMdd_HHmmss}]:${message} ${exception:format=message,stacktrace,innerException:separator=&#xD;&#xA;}"
                             archiveEvery="Minute"
                             archiveFileName ="./log/archive/log_{#}.zip"
                             maxArchiveFiles ="6"
                             lineEnding="CRLF"
                            concurrentWrites="false"
                            fileName="./log/log.txt" />
    </targets>

    <rules>
      <logger name="*" minlevel="Debug" writeTo="file" />
    </rules>
  </nlog>
</configuration>
复制代码

只有NLog的用法,很简单,有需要的话,回复一下,俺再给大家讲。

最后 俺修改后的FileTarget.cs 文件和编译后的dll,以及Ionic.Zip.dll在这里可以下载

本修改遵守新BSD协议。

 
 
原文地址:https://www.cnblogs.com/Leo_wl/p/2554971.html