而不是標準的I/O設施,我使用log4net這種事情。我將log4net配置爲使用ConsoleAppender和FileAppender或RollingFileAppender同時登錄到控制檯和日誌文件。
好的是您可以設置日誌消息模板來捕獲各種有用的信息(時間,線程/進程ID,機器名稱等),除了記錄的消息。
您還可以登錄到SQL Server,事件日誌或遠程接收器。
簡單!
這裏是一個樣本的TextWriter實現的路由一切通過log4net的:
using System;
using System.IO;
using System.Text;
using log4net ;
namespace ConsoleApplication22
{
public class Log4NetTextWriter : TextWriter, IDisposable
{
private static ILog log = log4net.LogManager.GetLogger(typeof(Log4NetTextWriter)) ;
#region properties
private StringBuilder buffer { get ; set ; }
public override Encoding Encoding
{
get
{
// since this TextWrite is writing to log4net, we have no idea what the final encoding might be.
// It all depends on the log4net configuration: tthe appender or appenders that wind up handling the logged message
// determine the final encoding.
//
// Might make more sense to return Encoding.UTF8 though, just to return something.
throw new NotImplementedException() ;
}
}
#endregion properties ;
public override void Flush()
{
if (this.buffer != null && this.buffer.Length > 0)
{
this.WriteLine() ;
}
return ;
}
public override void Close()
{
base.Close();
}
protected override void Dispose(bool disposing)
{
this.Flush() ;
base.Dispose(disposing);
}
#region public constructors
public Log4NetTextWriter() : this(null)
{
return ;
}
public Log4NetTextWriter(IFormatProvider formatProvider) : base(formatProvider)
{
this.buffer = new StringBuilder() ;
}
#endregion public constructors
#region public Write() overloads
public override void Write(bool value)
{
this.buffer.Append(value) ;
return ;
}
public override void Write(char value)
{
this.buffer.Append(value) ;
return ;
}
public override void Write(char[] buffer)
{
this.buffer.Append(buffer) ;
return ;
}
public override void Write(char[] buffer , int index , int count)
{
this.buffer.Append(buffer , index , count) ;
return ;
}
public override void Write(decimal value)
{
this.buffer.Append(value) ;
return ;
}
public override void Write(double value)
{
this.buffer.Append(value) ;
return ;
}
public override void Write(float value)
{
this.buffer.Append(value) ;
return ;
}
public override void Write(int value)
{
this.buffer.Append(value) ;
return ;
}
public override void Write(long value)
{
this.buffer.Append(value) ;
return ;
}
public override void Write(object value)
{
this.buffer.Append(value) ;
return ;
}
public override void Write(string format , object arg0)
{
this.buffer.AppendFormat(this.FormatProvider , format , arg0) ;
return ;
}
public override void Write(string format , object arg0 , object arg1)
{
this.buffer.AppendFormat(this.FormatProvider , format , arg0 , arg1) ;
return ;
}
public override void Write(string format , object arg0 , object arg1 , object arg2)
{
this.buffer.AppendFormat(this.FormatProvider , format , arg0 , arg1 , arg2);
return ;
}
public override void Write(string format , params object[] arg)
{
this.buffer.AppendFormat(this.FormatProvider , format , arg) ;
return ;
}
public override void Write(string value)
{
this.buffer.Append(value);
return ;
}
public override void Write(uint value)
{
this.buffer.Append(value);
return ;
}
public override void Write(ulong value)
{
this.buffer.Append(value);
return ;
}
public override void WriteLine()
{
string logMessage = this.buffer.ToString() ;
this.buffer.Length = 0 ;
log.Info(logMessage) ;
return ;
}
#endregion public Write() overloads
#region public WriteLine() overloads
public override void WriteLine(bool value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(char value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(char[] buffer)
{
this.Write(buffer) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(char[] buffer , int index , int count)
{
this.Write(buffer , index , count) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(decimal value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(double value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(float value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(int value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(long value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(object value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(string format , object arg0)
{
this.Write(format , arg0) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(string format , object arg0 , object arg1)
{
this.Write(format , arg0 , arg1) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(string format , object arg0 , object arg1 , object arg2)
{
this.Write(format , arg0 , arg1 , arg2) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(string format , params object[] arg)
{
this.Write(format , arg) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(string value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(uint value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
public override void WriteLine(ulong value)
{
this.Write(value) ;
this.WriteLine() ;
return ;
}
#endregion public WriteLine() overloads
}
}
下面是一個示例log4net的配置文件。這一個日誌記錄到控制檯和日誌文件,並根據大小自動翻轉(它也可以基於日期/時間或每執行一次)。
<log4net>
<!-- Log to the console -->
<appender name="Console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<!-- Pattern to output the caller's file name and line number -->
<conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
</layout>
</appender>
<!-- Log to a log file. This particular setup should log to a static file name 'log.txt' -->
<!-- When it hits 100KB in size, it rolls, keeping up to 10 archived files. The archived -->
<!-- files are named 'log.text.1', 'log.txt.2', ... , 'log.txt.10' -->
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="log.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="100KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="Console" />
<appender-ref ref="RollingFile" />
</root>
</log4net>
要配置log4net的,最簡單的方法是把一個XmlConfigurator屬性在AssemblyInfo.cs中,這樣的:
// Configure log4net using the .log4net file
[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension="log4net",Watch=true)]
// This will cause log4net to look for a configuration file
// called TestApp.exe.log4net in the application base
// directory (i.e. the directory containing TestApp.exe)
// The config file will be watched for changes.
當你的程序正在運行,您可以打開或關閉日誌記錄,或改變其配置只需編輯和保存配置文件即可。 log4net監視配置文件的變化並在運行中自行重新配置。
好吧,用這種方法,我假設我的DistributingTextWriter會持有對控制檯TextWriter和StreamWriter的引用。那麼我是否必須重寫每個Write和WriteLine方法以將這些調用「分配」給所有TextWriters? – Nitax 2012-01-11 18:52:34
恐怕是這樣的:如果你想保持與TextWriter類的接口的兼容性,你將不得不重新實現所有這些方法。但是,您可以從System.IO.StreamWriter的實現中複製大部分代碼。谷歌的「SSCLI」和/或「轉子」來找到它。 – 2012-01-11 19:03:36