我想在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);
答案 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
中自定义AssmbllyName
和log4net.config