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}
我们每个方法都有登录入口的做法:
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}