Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using different pattern for a specific logger in logback

I am using logback with slf4j and I need to change the pattern for a specific logger but keep the appenders same.

Here's my configuration: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>

I would like to use a different pattern for 'completion-logger'. Is this possible?

like image 978
Krishnaraj Avatar asked Feb 16 '15 08:02

Krishnaraj


People also ask

Is Logback better than log4j2?

Key Difference Between Log4j vs LogbackAs logback is improved, version log4j and versions log4j2 and logback have no difference in terms of performance or any features. Therefore log4j is the most used logging utility before the logback newer versions were invented.

How do I enable debug logs in Logback?

You can now use -Dlogback. debug=true to enable debugging of the logback setup. Unfortunately, there is no way to enable debugging via a System property. You have to use <configuration debug="true"> in the logback.

Which of the following file is used by Logback logging system?

properties file will be defined as properties in the logback. xml file.


1 Answers

I have created a custom multi-layout pattern class. The custom encoder has main two parts that root layout and custom layouts by logger names. You can change the class position and update com.example.demo.MultiLayoutPattern in logback.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>

Source Code:

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();
        }
    }
}

Output (Console)

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)
like image 186
Ismail Durmaz Avatar answered Oct 17 '22 17:10

Ismail Durmaz