log4net复杂类型日志记录

时间:2018-03-08 13:37:29

标签: c# log4net

我想在c#中记录复杂类型对象并使用log4net进行记录。这样做的正确方法是什么?我使用filelogappender。所以我想在log中看到我的实体。我应该使用stringbuilder类并将我的实体转换为字符串或将其序列化为json,或者log4net是否具备此功能?

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

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

4 个答案:

答案 0 :(得分:1)

如果你想将复杂的对象记录到文件或sql,我对第一个评论,最好的方法是使用newtonsoft库(nuget包)通过json转换字符串

然后你可以随意包装和解包对象或动态更改数据(json将为你节省大量的时间和精力。)你也可以将它传递回前端进行控制台记录或调试,并查看对象你刚刚登录。

答案 1 :(得分:1)

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

日志记录机制执行足够多的工作 - 每次记录信息时都必须打开流和关闭流

您传输的数据主要是文本,没有简单的方法将复杂对象解析为文本表示,所以您看到的是“浅”。类型的文本表示:'Object object'

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

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

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

答案 2 :(得分:0)

与@micah一样,我建议使用现有解决方案的JSON:log4net.Ext.Json。安装软件包后,您只需向任何appender添加SerializedLayout

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

答案 3 :(得分:0)

您可以创建用于格式化日志消息的自定义布局:

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>

注意:

  • 此代码使用反射,因此可能有点沉重,因此不是 如果性能存在问题,则建议使用。
  • 确保在Namespace中自定义AssmbllyNamelog4net.config