如何将自定义NLog LayoutRenderer传递给Database Target参数?
问题分析与解决方案
你的核心误解在于混淆了LayoutRenderer的职责和日志数据载体的概念:你把自定义的LogMessage同时作为LayoutRenderer(日志渲染组件)和日志数据对象,但NLog的LayoutRenderer实例是由框架创建用于解析日志事件的,和你传入的日志数据对象完全是两个独立的实例,所以你设置的属性不会传递到LayoutRenderer中,最终只会执行Append方法里的固定文本。
下面提供两种可行的解决方案:
方案一:使用结构化日志(推荐,无需自定义LayoutRenderer)
直接将日志数据的属性注入到日志事件的属性集合中,通过NLog内置的${event-properties}布局渲染器读取。
代码修改
internal class Program { private static NLog.Logger logger = NLog.LogManager.Setup().GetCurrentClassLogger(); static void Main(string[] args) { var message = new LogMessage() { IncomingOrOutgoing = MessageDirection.Incoming, MessageType = MessageType.TestType, MessageKey = "TestKey", Message = "Test Incoming" }; // 用结构化日志传递属性 logger.Info("记录消息", new { MessageKey = message.MessageKey, Message = message.Message, IncomingOrOutgoing = message.IncomingOrOutgoing }); } } // 普通数据类,无需继承LayoutRenderer public class LogMessage { public MessageDirection IncomingOrOutgoing { get; set; } public MessageType MessageType { get; set; } public string Message { get; set; } public string MessageKey { get; set; } }
NLog配置修改
<target name="db" xsi:type="Database" connectionString="..." commandType="StoredProcedure" commandText="[dbo].[IncomingOutgoingMessageLog]"> <parameter name="@MessageKey" layout="${event-properties:MessageKey}" /> <parameter name="@Message" layout="${event-properties:Message}" /> <parameter name="@IncomingOrOutgoing" layout="${event-properties:IncomingOrOutgoing}" /> </target>
方案二:自定义LayoutRenderer解析日志对象
如果坚持要用自定义LayoutRenderer,需要让它从日志事件中提取你传入的LogMessage对象,再根据参数输出对应属性。
代码修改
internal class Program { private static NLog.Logger logger = NLog.LogManager.Setup() .SetupExtensions(s => s.AutoLoadExtensions().RegisterLayoutRenderer<LogMessageRenderer>()) .GetCurrentClassLogger(); static void Main(string[] args) { var message = new LogMessage() { IncomingOrOutgoing = MessageDirection.Incoming, MessageType = MessageType.TestType, MessageKey = "TestKey", Message = "Test Incoming" }; // 直接传入LogMessage对象作为日志消息 logger.Info(message); } } // 自定义LayoutRenderer,专门负责解析LogMessage对象 [LayoutRenderer("LogMessage")] public class LogMessageRenderer : LayoutRenderer { [DefaultParameter] public string PropertyName { get; set; } protected override void Append(StringBuilder builder, LogEventInfo logEvent) { // 从日志事件中获取传入的LogMessage对象 if (logEvent.MessageObject is LogMessage message) { switch (PropertyName) { case "MessageKey": builder.Append(message.MessageKey); break; case "Message": builder.Append(message.Message); break; case "IncomingOrOutgoing": builder.Append(message.IncomingOrOutgoing.ToString()); break; default: builder.Append("未知属性"); break; } } } } // 普通数据类 public class LogMessage { public MessageDirection IncomingOrOutgoing { get; set; } public MessageType MessageType { get; set; } public string Message { get; set; } public string MessageKey { get; set; } }
NLog配置保持不变
<target name="db" xsi:type="Database" connectionString="..." commandType="StoredProcedure" commandText="[dbo].[IncomingOutgoingMessageLog]"> <parameter name="@MessageKey" layout="${LogMessage:MessageKey}" /> <parameter name="@Message" layout="${LogMessage:Message}" /> <parameter name="@IncomingOrOutgoing" layout="${LogMessage:IncomingOrOutgoing}" /> </target>
内容的提问来源于stack exchange,提问作者mt14
相关产品推荐
相关产品推荐

