C# 是否为特定NLog实例设置ValueFormatter?
我有两个NLog实例,其中一个需要一个特殊的ValueFormatter来序列化参数。ValueFormatter使用以下代码设置:C# 是否为特定NLog实例设置ValueFormatter?,c#,.net,nlog,formatter,C#,.net,Nlog,Formatter,我有两个NLog实例,其中一个需要一个特殊的ValueFormatter来序列化参数。ValueFormatter使用以下代码设置: NLog.Config.ConfigurationItemFactory.Default.ValueFormatter = new NLogValueFormatter(); 因此,正如您所看到的,它将应用于所有伐木工人。我在NLogger上找不到任何可能需要ValueFormatter的属性 有没有办法将此ValueFormatter仅绑定到其中一个记录器 编
NLog.Config.ConfigurationItemFactory.Default.ValueFormatter = new NLogValueFormatter();
因此,正如您所看到的,它将应用于所有伐木工人。我在NLogger上找不到任何可能需要ValueFormatter的属性
有没有办法将此ValueFormatter仅绑定到其中一个记录器
编辑1:
private CommunicationFormatProvider provider = new CommunicationFormatProvider();
public void LogCommunication(string message, params object[] args)
{
_comLogger.Log(LogLevel.Info, provider, message, args);
}
public class CommunicationFormatProvider : IFormatProvider, ICustomFormatter
{
public string Format(string format, object arg, IFormatProvider formatProvider)
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.Append(format);
var myTarget = LogManager.Configuration.FindTargetByName("communicationTarget");
myTarget = ((myTarget as NLog.Targets.Wrappers.WrapperTargetBase)?.WrappedTarget) ?? myTarget;
var jsonLayout = (myTarget as NLog.Targets.TargetWithLayout)?.Layout as NLog.Layouts.JsonLayout;
if (jsonLayout?.MaxRecursionLimit > 0)
strBuilder.Append(JsonConvert.SerializeObject(arg, new JsonSerializerSettings() { MaxDepth = jsonLayout?.MaxRecursionLimit }));
return strBuilder.ToString();
}
object IFormatProvider.GetFormat(Type formatType)
{
return (formatType == typeof(ICustomFormatter)) ? this : null;
}
}
编辑2:
public bool FormatValue(object value, string format, CaptureType captureType, IFormatProvider formatProvider, StringBuilder builder)
{
if (value.GetType() == typeof(LogData))
return false;
builder.Append(format);
try
{
var myTarget = LogManager.Configuration.FindTargetByName("communicationTarget");
myTarget = ((myTarget as NLog.Targets.Wrappers.WrapperTargetBase)?.WrappedTarget) ?? myTarget;
var jsonLayout = (myTarget as NLog.Targets.TargetWithLayout)?.Layout as NLog.Layouts.JsonLayout;
if (jsonLayout?.MaxRecursionLimit > 0)
{
var jsonSettings = new JsonSerializerSettings() { MaxDepth = jsonLayout?.MaxRecursionLimit };
using (var stringWriter = new StringWriter())
{
using (var jsonWriter = new JsonTextWriterMaxDepth(stringWriter, jsonSettings))
JsonSerializer.Create(jsonSettings).Serialize(jsonWriter, value);
builder.Append(stringWriter.ToString());
}
}
else
value = null;
}
catch(Exception ex)
{
builder.Append($"Failed to serlize {value.GetType()} : {ex.ToString()}");
}
return true;
}
JSON序列化程序:您可以确保要格式化的对象继承自
IFormattable
然后,您可以实现不同的格式化程序,每个记录器可以在记录特殊对象时选择自己的收藏夹
与此格式化程序类似,此格式化程序提供异常对象的特殊格式:
然后,在记录特殊对象时,在记录器上调用方法时,只需确保使用IFormatProvider formatProvider
-参数
我想您可以自定义NLogValueFormatter
执行默认格式。需要特殊附加格式化的记录器可以提供自己的自定义IFormatProvider
更新答案您是否知道可以使用消息模板强制NLog自动执行对象的JsonSerialization:
这将执行默认的ToString操作:
logger.Info(“Hello{World}”,new{Name=“Earth”,Type=“Water Planet”})代码>
这将表明对象可以安全反射(请注意@
):
logger.Info(“Hello{@World}”,new{Name=“Earth”,Type=“Water Planet”})代码>
另请参见:NLog JsonLayout有两个选项,这两个选项对于LogEvent属性的序列化非常重要:
- IncludealProperty
- 最大递归极限
默认参数如下所示:
<layout type="JsonLayout" includeAllProperties="false" maxRecursionLimit="0">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level}"/>
<attribute name="message" layout="${message}" />
</layout>
<layout type="JsonLayout" includeAllProperties="true" maxRecursionLimit="10">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level}"/>
<attribute name="message" layout="${message}" />
</layout>
public class Planet
{
public string Name { get; set; }
public string PlanetType { get; set; }
public override string ToString()
{
return Name; // Will be called in normal message-formatting
}
}
logger.Info("Hello {World}", new Planet() { Name = "Earth", PlanetType = "Water Planet" });
然后您可以像这样记录对象:
<layout type="JsonLayout" includeAllProperties="false" maxRecursionLimit="0">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level}"/>
<attribute name="message" layout="${message}" />
</layout>
<layout type="JsonLayout" includeAllProperties="true" maxRecursionLimit="10">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level}"/>
<attribute name="message" layout="${message}" />
</layout>
public class Planet
{
public string Name { get; set; }
public string PlanetType { get; set; }
public override string ToString()
{
return Name; // Will be called in normal message-formatting
}
}
logger.Info("Hello {World}", new Planet() { Name = "Earth", PlanetType = "Water Planet" });
默认的JsonLayout将只包括默认属性,其中消息
-属性表示你好地球
但是带有includealProperties=“true”
的JsonLayout将包括任何其他LogEvent属性。并将包括已完全序列化的World
-属性
其思想是,在记录时不应关心非直瞄目标的配置。日志规则+目标配置+布局配置决定了最终应该如何编写
如果确实希望将对象序列化为${message}
,则还可以执行以下操作:
logger.Info("Hello {@World}", new Planet() { Name = "Earth", PlanetType = "Water Planet" });
如果不希望LogEvent属性与默认属性混合在一起,则可以执行以下操作:
<layout type="JsonLayout" maxRecursionLimit="10">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level}"/>
<attribute name="message" layout="${message}" />
<attribute name="properties" encode="false">
<layout type="JsonLayout" includeAllProperties="true" maxRecursionLimit="10" />
</attribute>
</layout>
如果您有一个混合了字段和属性的对象,那么您可以告诉NLog对该类型执行自定义反射:
LogManager.Setup().SetupSerialization(s =>
s.RegisterObjectTransformation<GetEntityViewRequest>(obj =>
return Newtonsoft.Json.Linq.JToken.FromObject(obj) // Lazy and slow
)
);
LogManager.Setup().SetupSerialization(s=>
s、 寄存器对象转换(obj=>
返回Newtonsoft.Json.Linq.JToken.FromObject(obj)//懒惰且缓慢
)
);
谢谢,我创建了一个IFormatProvider实现,它是在调用ILogger.Log(LogLevel、IFormatProvider、string object[])时提供的,但从未触发该格式?请参见编辑。我想您需要显示更多的代码。如何将实现ICustomFormatter的对象传递给记录器?您是否自定义对象实现了ifformattable
?@Banshee Btw。您实现的代码看起来非常奇怪(在格式化程序中查找目标配置)。我认为你应该提出一个新的问题,问你如何达到最终目标。我想你正在走一条通往目的地的非常奇怪的路,并且正在克服不应该克服的障碍。默认情况下,只有时间、操作和客户端将被记录到磁盘上,但我需要能够在运行时设置是否要添加参数,以及这些参数的设置深度。因为它需要在运行时,所以每次都需要读取设置。我想我可以修正一下,这样每次通话只能读一次,但这不是现在最重要的部分。此时,我只需要一个rout,在这里我可以指出,这个特定的记录器将根据特定的方法格式化其输出。谢谢,您在另一篇文章“NLog仅在默认情况下序列化对象属性(当具有适当的getter时)。它忽略对象字段。”中写道,这就是我需要手动序列化对象的原因。上面我的文章中的代码按照我的需要工作,它提供了正确的数据,但我理解我的方法不是故意的。那么,如何从配置中为1个特定记录器定制maxRecursionLimit序列化?请确保特殊记录器命中配置为具有maxRecursionLimit=1
的目标,并且该目标的布局将进行反射。您可以为自己的类型(包含字段)自定义反射,如:@Banshee,因此您的问题不是“如何使用配置中的maxRecursionLimit为1个特定记录器自定义序列化?”而是“如何使用字段自定义对象的序列化?”@Banshee,但是的,这个答案几乎是我重复的。您为什么不想调用NLogRegisterObjectTransformation
?我们得到了大量包含字段、默认值和属性的复杂对象,GetEntityViewRequest只是其中之一。所有这些都需要以一种通用的方式进行序列化,我们可以在运行时设置深度。这也需要仅在处理通信的NLogger上设置,而不是在我们的其他NLogger上设置。我可以在我的第一篇文章中进行选择,以尊重配置文件的深度,但听起来这是一种糟糕的方式。那么,在不操纵数据模型的情况下,什么样的方法最适合我们的数据模型呢?注意,我们所有的类都是带有DataMembers.Btw的DataContractsJsonSerializerSettings.MaxDepth
在此处无效。它仅在“阅读”时使用,而不是