log4net - 根据附加程序呈现(对象)消息

Posted

技术标签:

【中文标题】log4net - 根据附加程序呈现(对象)消息【英文标题】:log4net - Rendering an (object) message depending on the appender 【发布时间】: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,并相应地设置它们的渲染对象。

不过,这似乎非常复杂且不必要(更不用说我目前不知道如何最好地使用日志存储库)。

这个问题有没有更好的解决方案?也许是一种以附加程序为基础而不是整个存储库以某种方式选择渲染器的方法。或者一些我从未想过的概念上完全不同的解决方案。

任何指针将不胜感激。

谢谢

【问题讨论】:

【参考方案1】:

经典,花了一整天的时间在这里发布后,我确实找到了解决方案......

我会将我的消息包装在上面发布的 LogMessage 类中。然后我将从 PatternLayoutConverter 创建一个转换后的派生并将其应用于消息参数:

<param name="ConversionPattern" value="%date&#9;-&#9;%thread&#9;-&#9;%level&#9;-&#9;%-80logger&#9;-&#9;%-40method&#9;-&#9;%message%newline" />
  <footer value="&#13;&#10;&#13;&#10;&#13;&#10;"/>
  <converter>
    <name value="message" />
    <type value="MyMessageConverter"/>
  </converter>

如果我很懒,我可能会创建两个转换器,一个用于 ToString 实现,一个用于基于 Xml 的转储。 如果我更有野心,我可以创建一个转换器,允许在 log4net.config 中应用自定义 IObjectRenderer 并使用它来呈现消息。然后,我的 IObjcetRenderer 实现可以按照我的第一篇文章中的描述转换 LogMessage。

这两者应该都能很好地工作;将在下周实施,如果将来有人在寻找具体实施,请给我留言。

【讨论】:

以上是关于log4net - 根据附加程序呈现(对象)消息的主要内容,如果未能解决你的问题,请参考以下文章

如何追踪 log4net 问题

Log4net 不将日志写入日志文件

如何在 log4net 中过滤自定义级别?

未找到log4net .netcore 3.1方法

扩展 log4net - 向每个日志添加额外数据

如何在 WPF 应用程序中使用 App.config 进行 log4net 配置