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

如何通过编程方式移除Logback输出JSON日志中的部分属性

如何通过编程方式移除Logback JSON日志中的指定属性

目前Java生态中Logback输出JSON格式日志几乎都是基于logstash-logback-encoder组件实现,以下是三种可落地的编程实现方案,对应你给出的日志示例,可以按需移除version、level_value这类不需要的属性。


方案1:按需注册字段Provider,从源头不生成不需要的字段

logstash-logback-encoder的每个输出字段都对应独立的JsonProvider,编程初始化编码器时,只注册你需要保留的字段对应的Provider即可,不需要的字段不注册就不会出现在最终输出里。
示例代码:

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.ConsoleAppender;
import net.logstash.logback.encoder.LogstashEncoder;
import net.logstash.logback.composite.loggingevent.*;
import org.slf4j.LoggerFactory;

public class CustomLogbackInitializer {
    public static void initJsonLogger() {
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        
        LogstashEncoder jsonEncoder = new LogstashEncoder();
        // 清空编码器默认加载的所有Provider
        jsonEncoder.getProviders().removeAllProviders();

        // 逐个添加需要保留的字段对应的Provider
        jsonEncoder.getProviders().addProvider(new LoggingEventFormattedTimestampJsonProvider()); // 保留time字段
        jsonEncoder.getProviders().addProvider(new MessageJsonProvider()); // 保留message字段
        jsonEncoder.getProviders().addProvider(new LoggerNameJsonProvider()); // 保留logger_name字段
        jsonEncoder.getProviders().addProvider(new ThreadNameJsonProvider()); // 保留thread_name字段
        jsonEncoder.getProviders().addProvider(new LogLevelJsonProvider()); // 保留level字段
        jsonEncoder.getProviders().addProvider(new MdcJsonProvider()); // 保留MDC中注入的自定义字段,比如示例里的myid

        // 不需要version、level_value字段,就不注册VersionJsonProvider、LogLevelValueJsonProvider即可
        
        jsonEncoder.setContext(context);
        jsonEncoder.start();

        // 把编码器绑定到对应Appender,完成日志配置
        ConsoleAppender appender = new ConsoleAppender();
        appender.setEncoder(jsonEncoder);
        appender.setContext(context);
        appender.start();
        context.getLogger("root").addAppender(appender);
    }
}

这种方案性能最好,因为不需要在序列化阶段做额外判断,从字段生成阶段就过滤掉了不需要的内容,适合字段固定、需要移除多个默认字段的场景。


方案2:通过字段名配置直接屏蔽指定字段

如果只需要移除少量字段,不需要调整整个Provider列表,可以直接通过字段名配置把不需要输出的字段设为null,编码器序列化时会自动跳过这些字段:

LogstashEncoder jsonEncoder = new LogstashEncoder();
// 配置要屏蔽的字段
jsonEncoder.setFieldNames(new LogstashFieldNames()
        .setVersion(null) // 移除version字段
        .setLevelValue(null) // 移除level_value字段
);
// 其余配置保持默认即可
jsonEncoder.start();

这种方案代码量最少,适合只需要移除2-3个默认字段、不需要调整其他默认输出逻辑的场景。


方案3:自定义序列化拦截器,动态过滤任意字段

如果需要根据运行时逻辑动态判断是否移除字段,或者要过滤的字段来自第三方扩展的Provider,可以实现自定义的JSON生成器装饰器,在序列化写入阶段拦截指定字段:

import com.fasterxml.jackson.core.JsonGenerator;
import net.logstash.logback.decorate.JsonGeneratorDecorator;
import com.fasterxml.jackson.core.util.JsonGeneratorDelegate;
import java.io.IOException;
import java.util.Set;

public class FieldExcludeDecorator implements JsonGeneratorDecorator {
    // 定义要移除的字段集合
    private static final Set<String> EXCLUDE_FIELDS = Set.of("version", "level_value");

    @Override
    public JsonGenerator decorate(JsonGenerator generator) {
        return new ExcludeGenerator(generator, EXCLUDE_FIELDS);
    }

    private static class ExcludeGenerator extends JsonGeneratorDelegate {
        private final Set<String> excludeFields;
        private boolean skipCurrentValue = false;

        public ExcludeGenerator(JsonGenerator delegate, Set<String> excludeFields) {
            super(delegate);
            this.excludeFields = excludeFields;
        }

        @Override
        public void writeFieldName(String name) throws IOException {
            if (excludeFields.contains(name)) {
                skipCurrentValue = true;
                return;
            }
            skipCurrentValue = false;
            super.writeFieldName(name);
        }

        @Override
        public void writeString(String value) throws IOException {
            if (skipCurrentValue) {
                skipCurrentValue = false;
                return;
            }
            super.writeString(value);
        }

        @Override
        public void writeNumber(int v) throws IOException {
            if (skipCurrentValue) {
                skipCurrentValue = false;
                return;
            }
            super.writeNumber(v);
        }

        // 其余writeBoolean、writeObject、writeNull等方法按照相同逻辑重写,跳过要排除的字段值即可
    }
}

注册自定义装饰器到编码器即可生效:

jsonEncoder.addDecorator(new FieldExcludeDecorator());

这种方案灵活性最高,支持任意复杂的过滤规则,缺点是会在序列化阶段增加少量判断逻辑,适合有动态过滤需求的场景。


内容的提问来源于stack exchange,提问作者Bapan Biswas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 17:39:19