在 logback 中对特定记录器使用不同的模式

2022-09-04 04:15:21

我正在使用slf4j的logback,我需要更改特定记录器的模式,但保持附加器相同。

这是我的配置:logback.xml

<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %class{36}:%L - %msg%n</pattern>
    </encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${logFile}</file>
    <append>false</append>
    <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %class{36}:%L - %msg%n</pattern>
    </encoder>
</appender>
<!-- We want error logging from this logger to go to an extra appender It still inherits CONSOLE STDOUT from the root logger -->
<logger name="${log.name:-com.mycompany}" level="${log.level:-INFO}">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE" />
</logger>
<logger name="completion-logger" level="${log.level:-INFO}">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE" />
</logger>
</configuration>

我想为“完成记录器”使用不同的模式。这可能吗?


答案 1

我创建了一个自定义的多布局模式类。自定义编码器有两个主要部分,即根布局和按记录器名称自定义布局。您可以在 中更改类位置并进行更新。com.example.demo.MultiLayoutPatternlogback.xml

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

        <encoder class="com.example.demo.MultiLayoutPattern">
            <pattern>ROOT %d{HH:mm:ss.SSS} [%thread] %-5level %class{36}:%L - %msg%n</pattern>

            <rule>
                <logger>com.example.demo</logger>
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %class{36}:%L - %msg%n</pattern>
            </rule>
            <rule>
                <logger>com.example.demo.TestService</logger>
                <pattern>SRV: %d{HH:mm:ss.SSS} [%thread] %class{36}:%L - %msg%n</pattern>
            </rule>
        </encoder>

    </appender>

    <root level="info">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

源代码:

package com.example.demo;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.Layout;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MultiLayoutPattern extends PatternLayoutEncoder {
    private List<Rule> rules = new ArrayList<>();
    private Map<String, Layout<ILoggingEvent>> layoutMap = new HashMap<>();

    public void addRule(Rule rule) {
        this.rules.add(rule);
        rule.start(context);
    }

    public byte[] encode(ILoggingEvent event) {
        Layout<ILoggingEvent> layout = getLayout(event.getLoggerName());
        String txt = layout.doLayout(event);
        return convertToBytes(txt);
    }

    private byte[] convertToBytes(String s) {
        Charset charset = getCharset();
        if (charset == null) {
            return s.getBytes();
        } else {
            return s.getBytes(charset);
        }
    }

    private Layout<ILoggingEvent> getLayout(final String name) {

        if (name == null) {
            throw new IllegalArgumentException("name argument cannot be null");
        }

        // if we are asking for the root logger, then let us return it without
        // wasting time
        if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
            return this.getLayout();
        }

        if (layoutMap.containsKey(name)) {
            return layoutMap.get(name);
        }

        // split package and class names
        String[] nameParts = name.split("[.]");

        // get root layout
        Layout<ILoggingEvent> layout = getLayout();

        // it is used for best match rule
        int bestMatch = 0;
        for (Rule rule : rules) {
            String[] loggerParts = rule.getLoggerParts();
            int i = 0;
            // match parts
            while (i < loggerParts.length && i < nameParts.length && nameParts[i].equals(loggerParts[i])) {
                i++;
            }

            if (i == loggerParts.length && i > bestMatch) {
                bestMatch = i;
                layout = rule.getPatternLayoutEncoder().getLayout();
            }
        }
        // save layout with logger
        layoutMap.put(name, layout);

        return layout;
    }

    @Override
    public void start() {
        super.start();
    }

    public static class Rule {
        private String logger;
        private String[] loggerParts;
        private String pattern;
        private PatternLayoutEncoder patternLayoutEncoder;
        private boolean outputPatternAsHeader = false;

        public String getLogger() {
            return logger;
        }

        public void setLogger(String logger) {
            this.logger = logger;
            this.loggerParts = logger.split("[.]");
        }

        public String[] getLoggerParts() {
            return loggerParts;
        }

        public String getPattern() {
            return pattern;
        }

        public void setPattern(String pattern) {
            this.pattern = pattern;
        }

        public boolean isOutputPatternAsHeader() {
            return outputPatternAsHeader;
        }

        public void setOutputPatternAsHeader(boolean outputPatternAsHeader) {
            this.outputPatternAsHeader = outputPatternAsHeader;
        }

        public PatternLayoutEncoder getPatternLayoutEncoder() {
            return patternLayoutEncoder;
        }

        public void start(Context context) {
            patternLayoutEncoder = new PatternLayoutEncoder();
            patternLayoutEncoder.setPattern(pattern);
            patternLayoutEncoder.setContext(context);
            patternLayoutEncoder.setOutputPatternAsHeader(outputPatternAsHeader);
            patternLayoutEncoder.start();
        }
    }
}

输出(控制台)

ROOT 03:29:14.435 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext:289 - Root WebApplicationContext: initialization completed in 705 ms
SRV: 03:29:14.465 [main] com.example.demo.TestService:13 - Test service initialized
ROOT 03:29:14.541 [main] INFO  o.s.s.c.ExecutorConfigurationSupport:181 - Initializing ExecutorService 'applicationTaskExecutor'
ROOT 03:29:14.642 [main] INFO  org.apache.juli.logging.DirectJDKLog:173 - Starting ProtocolHandler ["http-nio-8080"]
ROOT 03:29:14.660 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer:220 - Tomcat started on port(s): 8080 (http) with context path ''
03:29:14.668 [main] INFO  o.s.boot.StartupInfoLogger:61 - Started DemoApplication in 1.26 seconds (JVM running for 2.538)

答案 2

推荐