FileAppender / RollingFileAppender 被广泛使用, 但它们的缺点是没法将跨不同应用域的Log信息集中控制在一个文件之中。
RemotingAppender, 不仅降低了代码的改动,更为重要的是,所有来自不同域的Log信息,全部汇入一体。
正所谓,涓涓细流,汇入大海。
........ 前言
一个没有配备完整而强大Log功能的系统,最终会尝到苦果。
首先尝到苦果的是系统开发维护人员,但他们有时会对此隐忍之。
原因是,对一个已经处于运营中的项目,提出的改良,通常会被认为与风险等价。
我现在面对的问题,就是如何在一个成熟的项目中引入Log机制,而又要将代码的改动(Risk)控制在最小范围。
........ FileAppender(FA)/RollingFileAppender(RFA) 的缺点
Log4net 是我们在.net 系统中引入Log机制的首选,和 Log Application Block 相比, 它功能强大而不显臃肿。
FileAppender / RollingFileAppender 被广泛使用的原因在于, 本地I/O 操作和其他 Appender操作相比,代价最低。
FA/RFA 的缺点是没法将跨域的Log集中控制在一个文件之中。
此话一出,一定又会被N多人鄙视+嘲讽,或许是因为我使用不当,抑或是理解不深,才得出此种错误结论。
如果果真如此,还请各位同仁不吝指出,并权当看看 RemotingAppender 的使用吧。
........ 看 FA/RFA 的缺点
一个Solution 中,有 A, B 两个Web Applications.
1). 纳入 log4net.config
Code
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<!-- log4net -->
<log4net debug="true">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="c:\Log\trace.txt"></file>
<appendToFile value="true"></appendToFile>
<rollingStyle value="Size"></rollingStyle>
<maxSizeRollBackups value="10"></maxSizeRollBackups>
<maximumFileSize value="10MB"></maximumFileSize>
<staticLogFileName value="true"></staticLogFileName>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n"></conversionPattern>
</layout>
</appender>
<root>
<level value="DEBUG"></level>
<appender-ref ref="RollingLogFileAppender"></appender-ref>
</root>
</log4net>
</configuration>
2). 修改 Global.asax.cs
protected void Application_Start(object sender, EventArgs e)
{
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(Server.MapPath("~/log4net.config")));
}
此时,如果你将A, B 两项目中的Logfile 配置成同一个文件。
恐怕你会苦恼于,一个项目中的Log信息OK, 另一个项目为何没能输出。
........ log4net 中的 RemotingAppender
使用RemotingAppender, 所有项目不用更改 Global.asax.cs, 只需在log4net.config 中配置 RemotingAppender.
这不是减少了因为代码改动,而带来可能的风险吗?
Code
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<!-- log4net -->
<log4net debug="true">
<!--Remoting Appender-->
<appender name="Log4netRemotingAppender" type="log4net.Appender.RemotingAppender">
<param name="Sink" value="tcp://localhost:8089/Server.log4net.RemotingAppenderSink" />
<param name="Lossy" value="false" />
<param name="BufferSize" value="0" />
<param name="OnlyFixPartialEventData" value="true" />
</appender>
<root>
<level value="DEBUG"></level>
<appender-ref ref="Log4netRemotingAppender"></appender-ref>
</root>
</log4net>
</configuration>
在启动Remoting 的地方载入:
Code
private void ConfigLog4net() {
Log4netRemotingAppender remoteAppender = new Log4netRemotingAppender();
Log4netRemotingAppenderEventHandler remoteAppenderHandler = new Log4netRemotingAppenderEventHandler(HandleLog4netRemotingAppenderEvent);
RemotingServices.Marshal(remoteAppender,
"Server.log4net.RemotingAppenderSink",
typeof(log4net.Appender.RemotingAppender.IRemoteLoggingSink));
remoteAppender.Log4netRemoteEvent += remoteAppenderHandler;
string strLog4netConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config");
System.Console.WriteLine("Configurating Log4net");
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(strLog4netConfigurationPath));
System.Console.WriteLine("Log4net configuration complete");
logger.Debug("Log4net is on the fly now.");
}
private void HandleLog4netRemotingAppenderEvent(object sender, Log4netRemotingAppenderEventArgs args)
{
//All of the log information will flow into here.
//thus, we can handle them in one place.
//
// Do Something with the event arguments here,
//Specially, check log level, then beep up contactors.
FileInfo traceFileInfo = new FileInfo(string.Format(@"C:\Log\Trace.{0}.txt", DateTime.Now.ToString("MMddyyyy")));
if (!(traceFileInfo.Exists))
File.Create(traceFileInfo.FullName).Close();
string strLogSourceMsg = string.Format("{0} {1} {2}",
DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff"),
args.LogLevel,
args.Context);
if (traceFileInfo.Exists)
{
using (StreamWriter traceWriter = new StreamWriter(traceFileInfo.FullName, true, Encoding.ASCII)){
traceWriter.WriteLine("=============== BEGIN ===============");
traceWriter.WriteLine(strLogSourceMsg);
traceWriter.WriteLine(args.LocationFullInfo);
traceWriter.WriteLine(args.Message);
traceWriter.WriteLine("=============== END ===============");
traceWriter.Flush();
}
}
}
好了,开心调用 “ConfigLog4net” 吧。
........ 总结
RemotingAppender, 不仅降低了代码的改动,更为重要的是,所有来自不同域的Log信息,全部汇入一体。
正所谓,涓涓细流,汇入大海。
希望能为想使用RemotingAppender 的同仁提供些许帮助,就是我最大的开心了。
祝大家工作开心!