【发布时间】:2015-08-17 20:47:52
【问题描述】:
我正在使用 log4net,以及一个与 log4net.ILog 几乎相同的自定义 logg 外观来访问它。 我想登录到一个简单的文本文件,但也使用自定义 XML appender 将内容写入 XML。
现在问题来了。说我正在做类似的事情
interface IMyILogFacade
{
// An implementation of this interface will eventually route this call to
// log4net.ILogger.Trace
void Trace(string format, params object[] args);
}
class Test
{
IMyILogFacade log; // assume this is given (injected)
public void testMethod(Assembly assembly)
{
string msg = "Entering Method 'testMethod'. Method Parameter 0 (assembly): {0}";
log.Trace(msg, assembly);
}
}
默认情况下,当以任何转换模式访问 %message 或显式访问 RenderedMessage 时,log4net 将使用简单的 String.Format(msg, assembly) 呈现消息。
这种行为适用于我的文本文件日志。但是对于我的 XML 日志,我希望它以不同的方式呈现。简而言之,然后我想反思参数(程序集)的运行时类型并将其所有公共成员及其公共成员的公共成员等等......转储到嵌套的 XML 结构中。因此,我需要使用其他东西,而不是使用 String.Format(msg, assembly) 进行渲染,比如 String.Format(msg, MyXmlDumper.Dump(assembly))。
我还没有找到任何根据 Appender 类型进行渲染的好方法。
我当前的方法是让我的记录器外观将所有对 Trace、Debug 等的调用转换为 LogMessage 类型的对象。
public class LogMessage
{
public string message { get; protected set; }
public object[] @params { get; protected set; }
public LogMessage(string message, params object[] @params)
{
this.message = message;
this.@params = @params;
}
}
然后我会使用一个实现 IObjectRenderer 的类来渲染它。这将是一个简单的类似 ToString 的函数
public class LogMessageStringRenderer : IObjectRenderer
{
public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer)
{
LogMessage logMessage = obj as LogMessage;
if(logMessage == null)
{
throw new InvalidOperationException("LogMessageStringRenderer can only render objects of type LogMessage");
} else
{
writer.Write(
String.Format(logMessage.message, logMessage.@params)
);
}
}
}
当然,为创建我的 Xml 转储创建相同的内容也很简单。
不过,这似乎不是一个非常理想的解决方案。首先,这些渲染(据我所知)只能附加到 log4net 存储库。通过代码,或在配置文件中作为根元素,如
<renderer renderedClass="LogMessage" RenderingClass="LogMessageStringRenderer"/>
但这意味着我必须在我的应用程序中创建两个日志存储库;一个用于文本文件 appender,另一个用于 xml appender,并相应地设置它们的渲染对象。
不过,这似乎非常复杂且不必要(更不用说我目前不知道如何最好地使用日志存储库)。
这个问题有没有更好的解决方案?也许是一种以附加程序为基础而不是整个存储库以某种方式选择渲染器的方法。或者一些我从未想过的概念上完全不同的解决方案。
任何指针将不胜感激。
谢谢
【问题讨论】: