Override/wrap log4net 序列化对象

Override/wrap log4net to serialize objects

我们每个方法都有登录入口的做法:

public void DoSomething(string someWords, bool definitely)
{
  Logger.Log.Debug(new { someWords, definitely });
  // DoSomething
}

这是有效的,因为我们围绕调用的默认日志构建了一个包装器:

Logger.Log.Debug(JsonConvert.SerializeObject(message));

不幸的是,它破坏了日志记录,因为我们没有获取 Logger.Log.Debug() 的 class/method/line 编号等,而是获取包装器的 class/method/line!

我们的一个想法是创建一个简单的扩展方法:

using Newtonsoft.Json;

namespace System
{
    public static class ExtensionMethods
    {
        public static string S<T>(this T o)
        {
            return JsonConvert.SerializeObject(o);
        }
    }
}

所以我们可以 Logger.Log.Debug(new { someWords, definitely }.S()); 但我不太热衷。

有没有更好的方法来完成这个?

谢谢!

您可以设置自定义 Log4net IObjectRenderer,它负责呈现要记录的 object/消息到 string.

这样做,您可以使用常规的日志记录方法 - 而不是 helper/extension 方法 - 确保预期的 class、方法、行号等出现在输出中。

请注意,在记录 Exception 时也会使用 IObjectRenderer
根据您的用例,您可能不希望它采用 JSON 格式。

namespace PFX
{
    public class CustomObjectRenderer : IObjectRenderer
    {
        public CustomObjectRenderer()
        { }

        public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer)
        { 
            if (obj is Exception)
            {
                rendererMap.DefaultRenderer.RenderObject(rendererMap, obj, writer);
            }
            else
            {
                writer.Write(JsonConvert.SerializeObject(obj));
            }
        }
    }
}

您在 Log4net 配置中注册 IObjectRenderer,如下所示,
其中 PFX.CustomObjectRenderer 是命名空间 + 渲染器的名称 class,MyAssembly 是程序集的名称。
您可以注册多个渲染器;这里使用同一个对象将每个对象渲染为 JSON.

<renderer renderingClass="PFX.CustomObjectRenderer, MyAssembly" renderedClass="System.Object" />

一个完整的配置示例

<log4net>
  <renderer renderingClass="PFX.CustomObjectRenderer, MyAssembly" renderedClass="System.Object" />
  <appender name="FileAppender" type="log4net.Appender.FileAppender">
        <file value="log.txt" />
        <appendToFile value="true" />
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date %-5level %logger %message%newline" />
        </layout>
    </appender>
    <root>
        <appender-ref ref="FileAppender" />
    </root>
</log4net>

下面调用

log.Info(new { someWords, definitely });

会输出

2022-03-24 22:48:22,865 INFO Log {"someWords":"words","definitely":true}