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
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=
}" 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协议。
标签: NLog Zip 压缩 日志
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息