MST

星途 面试题库

面试题:Java自定义日志级别及复杂过滤规则的设计与实现

假设现有一个大型分布式Java项目,需要自定义一种新的日志级别用于特殊业务场景,并设计一套复杂的过滤规则,该规则不仅基于日志级别,还需结合业务标识、请求来源等多维度信息进行日志过滤。请详细阐述设计思路,包括自定义日志级别在不同日志框架(如log4j2、SLF4J结合Logback)中的实现方式,以及复杂过滤规则的代码实现架构。
32.0万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

自定义日志级别实现思路

  1. Log4j2
    • 定义自定义日志级别:通过实现org.apache.logging.log4j.Level接口,创建自定义的日志级别类。例如:
    public class CustomLevel extends Level {
        public CustomLevel(int level, String name, int syslogEquivalent) {
            super(level, name, syslogEquivalent);
        }
    }
    
    • 使用自定义日志级别:在配置文件(如log4j2.xml)中,可以通过additivity等属性配置该级别日志的输出规则。例如:
    <Logger name="com.example" level="CustomLevel" additivity="false">
        <AppenderRef ref="ConsoleAppender"/>
    </Logger>
    
  2. SLF4J 结合 Logback
    • 定义自定义日志级别:在logback.xml中,可以通过<root>标签或<logger>标签自定义日志级别。例如:
    <logger name="com.example" level="TRACE">
        <appender - ref ref="STDOUT"/>
    </logger>
    
    • 由于 SLF4J 是日志门面,本身不实现日志功能,而 Logback 是常用实现。要在代码中使用自定义级别,在获取日志记录器时,如Logger logger = LoggerFactory.getLogger(YourClass.class);,然后使用logger.trace("Your message with custom level")等方法记录日志。

复杂过滤规则代码实现架构

  1. 定义过滤条件接口
    • 创建一个接口,例如LogFilter,定义一个方法boolean filter(LogRecord record),其中LogRecord类包含日志级别、业务标识、请求来源等多维度信息。
    public interface LogFilter {
        boolean filter(LogRecord record);
    }
    
  2. 实现具体过滤规则
    • 对于基于日志级别的过滤:
    public class LevelLogFilter implements LogFilter {
        private final Level level;
        public LevelLogFilter(Level level) {
            this.level = level;
        }
        @Override
        public boolean filter(LogRecord record) {
            return record.getLevel().isGreaterOrEqual(level);
        }
    }
    
    • 对于基于业务标识的过滤:
    public class BusinessIdLogFilter implements LogFilter {
        private final String businessId;
        public BusinessIdLogFilter(String businessId) {
            this.businessId = businessId;
        }
        @Override
        public boolean filter(LogRecord record) {
            return record.getBusinessId().equals(businessId);
        }
    }
    
    • 对于基于请求来源的过滤:
    public class RequestSourceLogFilter implements LogFilter {
        private final String requestSource;
        public RequestSourceLogFilter(String requestSource) {
            this.requestSource = requestSource;
        }
        @Override
        public boolean filter(LogRecord record) {
            return record.getRequestSource().equals(requestSource);
        }
    }
    
  3. 组合过滤规则
    • 创建一个CompositeLogFilter类实现LogFilter接口,用于组合多个过滤规则。
    import java.util.ArrayList;
    import java.util.List;
    public class CompositeLogFilter implements LogFilter {
        private final List<LogFilter> filters = new ArrayList<>();
        public void addFilter(LogFilter filter) {
            filters.add(filter);
        }
        @Override
        public boolean filter(LogRecord record) {
            for (LogFilter filter : filters) {
                if (!filter.filter(record)) {
                    return false;
                }
            }
            return true;
        }
    }
    
  4. 在日志框架中应用过滤规则
    • Log4j2:可以通过自定义Filter类,在filter方法中调用上述CompositeLogFilter进行过滤。然后在log4j2.xml中配置该自定义Filter
    • Logback:类似地,通过自定义AppenderFilter类,在doAppenddecide方法中调用CompositeLogFilter进行过滤,并在logback.xml中配置。例如,自定义一个Filter
    import ch.qos.logback.classic.spi.ILoggingEvent;
    import ch.qos.logback.core.filter.Filter;
    import ch.qos.logback.core.spi.FilterReply;
    public class CustomLogbackFilter extends Filter<ILoggingEvent> {
        private CompositeLogFilter compositeLogFilter;
        @Override
        public FilterReply decide(ILoggingEvent event) {
            LogRecord record = convertToLogRecord(event);
            if (compositeLogFilter.filter(record)) {
                return FilterReply.ACCEPT;
            }
            return FilterReply.DENY;
        }
        private LogRecord convertToLogRecord(ILoggingEvent event) {
            // 实现将ILoggingEvent转换为LogRecord的逻辑
        }
    }
    
    然后在logback.xml中配置该CustomLogbackFilter