You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NLog多场景下控制台不同JSON格式日志输出方案咨询

最优方案:利用NLog的条件规则与结构化日志能力,避免手动拼接JSON

针对你在WebAPI2 + NLog 4.0.3场景下需要输出10种不同JSON格式控制台日志的需求,我推荐你优化方案1的思路,通过NLog内置的条件路由和MDLC(映射诊断逻辑上下文)来实现——完全不需要手动拼接JSON(方案2的手动拼接容易出现转义错误、难以维护,还浪费了NLog的结构化日志能力)。

一、核心思路

  1. 为每种日志场景配置独立的Console Target,每个Target对应专属的JsonLayout结构
  2. 通过NLog的规则(Rules)配置条件过滤,根据日志上下文(比如MDLC标记、是否存在异常、日志级别)自动路由到对应Target
  3. 代码中通过MDLC传递场景专属的字段值,无需手动拼接JSON字符串

二、具体配置(web.config)

首先在配置文件中定义所有场景的Target和对应的条件规则:

<configSections>
  <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
</configSections>

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>
    <!-- 场景1:异常日志Target -->
    <target xsi:type="Console" name="console_exception" >
      <layout xsi:type="JsonLayout">
        <attribute name="id" layout="${mdlc:item=id}" />
        <attribute name="uuid" layout="${mdlc:item=uuid}" />
        <attribute name="key" layout="${mdlc:item=key}" />
        <attribute name="message" layout="${message}" />
        <attribute name="stack_trace" layout="${exception:format=ToString}" />
      </layout>
    </target>

    <!-- 场景2:数据库耗时日志Target -->
    <target xsi:type="Console" name="console_databaseTimeTaken" >
      <layout xsi:type="JsonLayout">
        <attribute name="id" layout="${mdlc:item=id}" />
        <attribute name="message" layout="Time taken to retrieve data from database" />
        <attribute name="Time" layout="${message}" />
      </layout>
    </target>

    <!-- 其他8种场景的Target,按照同样的方式配置专属JsonLayout -->
  </targets>

  <rules>
    <!-- 异常日志规则:当日志携带异常时,路由到console_exception -->
    <logger name="*" minLevel="Error" writeTo="console_exception" when="${exception:innerFormat=ToString} != ''" />

    <!-- 数据库耗时日志规则:当MDLC中存在LogType=DatabaseTime标记时,路由到console_databaseTimeTaken -->
    <logger name="*" minLevel="Info" writeTo="console_databaseTimeTaken" when="${mdlc:item=LogType} == 'DatabaseTime'" />

    <!-- 其他场景的规则:根据各自的判断条件(比如MDLC标记、日志级别、特定关键字)配置对应的when表达式 -->
  </rules>
</nlog>

三、代码中如何使用

1. 记录异常日志

using NLog;
using NLog.MappedDiagnosticsLogicalContext;

// 初始化Logger
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

try
{
    // 你的业务逻辑代码
}
catch (Exception ex)
{
    // 使用MDLC传递场景专属字段,using块确保上下文自动清理
    using (MappedDiagnosticsLogicalContext.SetScoped("id", "5656"))
    using (MappedDiagnosticsLogicalContext.SetScoped("uuid", "xdd895-65454"))
    using (MappedDiagnosticsLogicalContext.SetScoped("key", "somekeyname"))
    {
        _logger.Error(ex, "Exception occurred during operation");
    }
}

2. 记录数据库耗时日志

var timeTakenInMs = 1100;

using (MappedDiagnosticsLogicalContext.SetScoped("id", "8898998"))
using (MappedDiagnosticsLogicalContext.SetScoped("LogType", "DatabaseTime"))
{
    // 这里的日志消息会被填充到JsonLayout的Time字段中
    _logger.Info($"{timeTakenInMs} (in milli seconds)");
}

四、为什么这个方案是最优的

  • 避免手动拼接错误:NLog的JsonLayout会自动处理JSON转义,再也不用担心日志内容里的双引号破坏JSON结构
  • 易维护扩展:新增场景只需要添加新的Target和规则,无需修改业务代码;后续如果要把日志输出到文件、ELK等平台,只需要复用现有Layout配置
  • 上下文管理更规范:MDLC的SetScoped方法会自动清理上下文,避免内存泄漏或上下文污染
  • 完全兼容你的技术栈:MDLC和条件规则在NLog 4.0.3中已经完全支持,不需要升级依赖

五、对原有方案的补充说明

  • 你之前的方案1没找到正确的条件路由方式,通过when表达式和MDLC标记就可以完美解决日志路由问题
  • 方案2的手动拼接JSON是不推荐的,不仅容易出错,还丢失了NLog结构化日志的所有优势

内容的提问来源于stack exchange,提问作者Gowtham.K.Reddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:41:03