log4net复杂类型记录日志

3

我想在C#中记录复杂类型对象,并使用log4net进行记录。正确的方法是什么?我使用filelogappender,所以我想在日志中看到我的实体。我应该使用StringBuilder类将实体转换为字符串,还是将其序列化为JSON,或者是log4net可以做到这一点?

public class Person
{
Name {get;set;}
Surname{get;set;}
}

Person personobject=new Person("MyName","MySurname");
log4net.Log.Warn(personobject);

转换为JSON是最简单的方法。您可以使用NewtonSoft库将对象序列化为JSON。 - Chetan
这是一个建议:http://www.adamtuliper.com/2012/12/logging-complete-objects-with-log4net.html - Hintham
1
你也可以在Person类中重写ToString方法,以任何你想在日志中看到的格式返回对象的属性。 - Wheels73
在log4net中是否有现成的解决方案? - Bilgehan
4个回答

6

您无法记录复杂类型,原因很简单:

日志机制执行的工作已经足够艰巨 - 每次记录信息都必须打开流和关闭流。

您要流式传输的数据大多是文本,没有一种简单的方法将复杂对象解析为文本表示,因此您看到的是类型的“浅”文本表示:'Object object'

简单的解决方法是手动将对象序列化为JSON字符串,这样就可以了:

log4net.Log.Warn(Newtonsoft.Json.JsonConvert.SerializeObject(personobject));

这会将您的类型序列化为字符串,而不是对象,因此您将能够记录任何复杂类型。

2

如果您想要将复杂对象记录到文件或SQL中,最好的方法是使用Newtonsoft库(NuGet包)转换为JSON字符串。

这样,您可以随意包装和解包对象,或在运行时更改数据(JSON将为您节省大量时间和精力)。您还可以将其传回前端以进行控制台日志记录或调试,并查看刚刚记录的对象。


1
您可以创建一个自定义布局来格式化日志消息:
StructLayout
public class StructLayout : PatternLayout
{
    public override void Format(TextWriter writer, LoggingEvent loggingEvent)
    {
        LoggingEvent newLoggingEvent;
        var message = loggingEvent.MessageObject;

        if (MessageObjectBuilder.TryBuildMessageObject(message, out object newMessage))
        {
            var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
            var callerStackBoundaryDeclaringType = loggingEvent.GetType().GetField("m_callerStackBoundaryDeclaringType", bindingFlags)?.GetValue(loggingEvent);
            newLoggingEvent =
                new LoggingEvent(callerStackBoundaryDeclaringType as Type,
                    loggingEvent.Repository,
                    loggingEvent.LoggerName,
                    loggingEvent.Level,
                    newMessage as SystemStringFormat,
                    loggingEvent.ExceptionObject);
        }
        else
        {
            newLoggingEvent = loggingEvent;
        }

        base.Format(writer, newLoggingEvent);
    }
}
MessageObjectBuilder - 使用Newtonsoft格式化消息:
 public class MessageObjectBuilder
{
    public static bool TryBuildMessageObject(object messageObject, out object newMessage)
    {
        var message = messageObject;
        var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
        object[] args = message.GetType().GetField("m_args", bindingFlags)?.GetValue(message) as object[];

        if (args == null || args.Length == 0) // not a formatted message 
        {
            newMessage = message;
            return false;
        }

        var argsAsJson = SerializeArgs(args);
        var provider = message.GetType().GetField("m_provider", bindingFlags)?.GetValue(message);
        var format = message.GetType().GetField("m_format", bindingFlags)?.GetValue(message);

        newMessage = new SystemStringFormat(provider as IFormatProvider, format as string, argsAsJson);
        return true;
    }

    private static object[] SerializeArgs(object[] args)
    {
        var newArgs = new List<string>();
        foreach (var arg in args)
        {
            newArgs.Add(Newtonsoft.Json.JsonConvert.SerializeObject(arg));
        }

        return newArgs.ToArray();
    }
}

最后,将以下内容添加到log4net.config中,而不是您当前的布局:

    <appender name="StructLogAppender" type="log4net.Appender.RollingFileAppender">
        <file value="StructLogAppender\StrcutLog.log" />
        <layout type="Namespace.StructLayout, AssmbllyName">
            <conversionPattern value="%date{M/d/yyyy H:mm:ss.fff} - %message%newline" />
        </layout>
        <filter type="log4net.Filter.LevelRangeFilter">
            <param name="LevelMax" value="ERROR" />
        </filter>
        <appendToFile value="true" />
   </appender>

注意:

  • 此代码使用反射,因此可能会有一些负担,如果性能是一个问题,则不建议使用。
  • 请确保在log4net.config中自定义NamespaceAssmbllyName

0

像 @micah 一样,我建议使用 JSON,这次使用现有的解决方案:log4net.Ext.Json。安装包后,您只需将 SerializedLayout 添加到任何 appender 中:

<appender...>
    <layout type='log4net.Layout.SerializedLayout, log4net.Ext.Json'>
    </layout> 
</appender>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接