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

如何在NLog ≥ v5.0中覆盖内置JSON转换器实现字段脱敏

NLog v5.0+ 敏感字段脱敏实现方案

一、全局JSON转换器的正确注册方式

NLog v5.0废弃了ConfigurationItemFactory.Default.JsonConverter,改用LogManager.Setup()来配置自定义JSON处理逻辑:

  1. 实现适配NLog v5的序列化接口,推荐用NLog.Serialization.IJsonSerializer来覆盖全局序列化逻辑,若仅需字段级转换也可实现IJsonConverter
  2. 在程序初始化阶段注册:
// 非DI场景
LogManager.Setup()
          .SetupSerialization(config => 
              config.RegisterJsonSerializer(new YourCustomCensorSerializer()));

// ASP.NET Core DI场景
builder.Host.UseNLog(options =>
{
    options.SetupBuilder = setup => 
        setup.SetupSerialization(s => s.RegisterJsonSerializer(new YourCustomCensorSerializer()));
});

若仅需注册特定转换器:

LogManager.Setup()
          .SetupSerialization(s => s.RegisterJsonConverter(new YourCensorConverter()));

二、基于CensorMeAttribute的替代脱敏方案

如果全局转换器注册不生效,推荐以下几种灵活的字段级处理方式:

方案1:自定义LayoutRenderer处理标记属性

实现一个LayoutRenderer,反射检查日志对象的属性是否带有CensorMeAttribute,执行脱敏后再序列化:

[LayoutRenderer("censor-marked")]
public class CensoredPropertiesRenderer : LayoutRenderer
{
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        var targetObj = logEvent.Properties["LogData"]; // 假设日志对象存在于LogData属性中
        if (targetObj == null) return;

        var type = targetObj.GetType();
        foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            if (prop.GetCustomAttribute<CensorMeAttribute>() != null)
            {
                // 替换为脱敏值,比如***或部分掩码
                prop.SetValue(targetObj, "***");
            }
        }

        // 用NLog内置的JSON序列化器处理
        builder.Append(LogManager.LogFactory.ServiceProvider.GetRequiredService<IJsonSerializer>().Serialize(targetObj));
    }
}

在NLog配置文件中注册并使用:

<extensions>
    <add assembly="你的程序集名称" />
</extensions>
<targets>
    <target name="jsonFile" xsi:type="File" fileName="logs/app.log">
        <layout type="JsonLayout">
            <attribute name="timestamp" layout="${longdate}" />
            <attribute name="data" layout="${censor-marked}" />
        </layout>
    </target>
</targets>

方案2:结合第三方JSON序列化器实现脱敏

如果项目使用Newtonsoft.Json或System.Text.Json,可让NLog复用这些库的序列化逻辑,通过自定义契约解析器处理标记属性:
以Newtonsoft.Json为例:

  1. 安装NLog.Extensions.NewtonsoftJson包
  2. 实现自定义ContractResolver:
public class CensoredContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        if (member.GetCustomAttribute<CensorMeAttribute>() != null)
        {
            property.ValueProvider = new CensoredValueProvider(property.ValueProvider);
        }
        return property;
    }
}

public class CensoredValueProvider : IValueProvider
{
    private readonly IValueProvider _originalProvider;
    public CensoredValueProvider(IValueProvider originalProvider) => _originalProvider = originalProvider;

    public void SetValue(object target, object value) => _originalProvider.SetValue(target, value);
    public object GetValue(object target) => "***"; // 自定义脱敏逻辑
}
  1. 配置NLog使用Newtonsoft.Json并指定契约解析器:
LogManager.Setup()
            .SetupSerialization(s => s.UseNewtonsoftJson(jsonSettings => 
                jsonSettings.ContractResolver = new CensoredContractResolver()));

方案3:日志对象预处理

在调用NLog日志方法前,手动遍历对象属性,对带有CensorMeAttribute的字段进行脱敏,再传入日志。这种方式无需修改NLog配置,简单直接。

三、关键注意点

  • NLog v5的序列化体系已重构,务必使用SetupSerialization下的注册方法,避免依赖旧的ConfigurationItemFactory相关API
  • 若处理嵌套对象的敏感字段,需在自定义逻辑中添加递归遍历逻辑
  • 测试时要覆盖不同日志级别、不同对象结构的场景,确保脱敏效果符合预期

内容的提问来源于stack exchange,提问作者Astrid E.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 00:53:28