11

For log4j2, is it possible for using different pattern layout for different log level and output to SYSTEM_OUT?

Here is my log4j2.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
        <Appenders>
            <Console name="debugMsg" target="SYSTEM_OUT">
                <PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %l - %msg%n"/>
            </Console>
            <Console name="infoMsg" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %msg%n"/>
            </Console>
        </Appenders>
        <Loggers>
            <Root level="trace"  additivity="false">
                <AppenderRef ref="infoMsg" level="info"/>
                <AppenderRef ref="debugMsg" level="debug"/>
            </Root>
        </Loggers>
    </Configuration>

However, the INFO level message are shown in both "infoMsg" and "debugMsg" pattern.

2015-12-24 10:51:56.176 Log4j is ready.
[INFO ] 2015-12-24 10:51:56.176 com.myftpserver.MyFtpServer.<init>(MyFtpServer.java:65) - Log4j is ready.
2015-12-24 10:51:56.176 Configuration file is loaded
[INFO ] 2015-12-24 10:51:56.176 com.myftpserver.Configuration.load(Configuration.java:74) - Configuration file is loaded
[DEBUG] 2015-12-24 10:51:56.176 com.myftpserver.Configuration.load(Configuration.java:82) - supportPassiveMode=true
2015-12-24 10:51:56.301 User Manager class is loaded.
[INFO ] 2015-12-24 10:51:56.301 com.myftpserver.Configuration.load(Configuration.java:119) - User Manager class is loaded.
2015-12-24 10:51:56.301 File Manager class is loaded.
[INFO ] 2015-12-24 10:51:56.301 com.myftpserver.Configuration.load(Configuration.java:121) - File Manager class is loaded.
2015-12-24 10:51:56.301 Server Initialization completed.
[INFO ] 2015-12-24 10:51:56.301 com.myftpserver.MyFtpServer.<init>(MyFtpServer.java:69) - Server Initialization completed.
2015-12-24 10:51:56.301 Available passive port:[1232, 1233, 1234]
[INFO ] 2015-12-24 10:51:56.301 com.myftpserver.MyFtpServer.<init>(MyFtpServer.java:75) - Available passive port:[1232, 1233, 1234]

So, is it possible to remove duplicate item?

thank you very much and Merry X'mas

4 Answers 4

11

The latest versions of Log4j2 allow a pattern selector instead of just a single pattern. Log4j provides a selector based on markers but not one based on levels. Create a Jira issue and I will add it. However, Log4j does allow you to used a script to select the pattern. It would be simple to write one that selects based on the level.

In the configuration above the debug appender is also going to output info level events, which is why you see the duplicates.

I haven't tested it but I believe the configuration below should do what you want:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout>
                <ScriptPatternSelector defaultPattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %l - %msg%n">
                    <Script name="LevelSelector" language="bsh"><![CDATA[
                        if (logEvent.getLevel() == org.apache.logging.log4j.Level.INFO) {
                            return "INFO";
                        } 
                        return null;
                        ]]>
                    </Script>
                    <PatternMatch key="INFO" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %msg%n"/>
                </ScriptPatternSelector>
            </PatternLayout>
        </Console> 
    </Appenders>
    <Loggers>
        <Root level="trace">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>
Sign up to request clarification or add additional context in comments.

Comments

7

Yes. Since log4j 2.13 there is the LevelPatternSelector. You can use it like that.

I use the error/fatal case as default pattern. You can also specify it explicite.

      <Console name="stdout" target="SYSTEM_OUT">
         <PatternLayout>
            <LevelPatternSelector defaultPattern="%highlight{[%p] %d{HH:mm:ss} %c:%L %m}{bright,red}%n">
               <PatternMatch key="WARN" pattern="%highlight{[%p] %d{HH:mm:ss} %c:%L %m}{bright,yellow}%n" />
               <PatternMatch key="INFO" pattern="[%style{%p}{blue}] %d{HH:mm:ss} %c:%L %m%n" />
               <PatternMatch key="DEBUG" pattern="[%p] %d{HH:mm:ss} %c:%L %m%n" />
               <PatternMatch key="TRACE" pattern="[%p] %d{HH:mm:ss} %c:%L %m%n" />
            </LevelPatternSelector>
         </PatternLayout>
      </Console>

Comments

4

Finally, I get it works

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout>
                    <ScriptPatternSelector defaultPattern="">
                        <Script name="LevelSelector" language="javascript"><![CDATA[
                            result=null;
                            switch (logEvent.getLevel())
                            {
                                case org.apache.logging.log4j.Level.DEBUG:
                                case org.apache.logging.log4j.Level.INFO:result=logEvent.getLevel();
                                                                         break;
                                default:result=null;                                            
                            }
                            result;
                            ]]>
                        </Script>
                        <PatternMatch key="DEBUG" pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %l - %msg%n"/>
                        <PatternMatch key="INFO" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %msg%n"/>
                    </ScriptPatternSelector>
                </PatternLayout>
            </Console> 
        </Appenders>
        <Loggers>
            <Root level="trace">
                <AppenderRef ref="Console"/>
            </Root>
        </Loggers>
    </Configuration>

thank you for your inspiration.

Comments

0

I was very interested in the programmatic version of this. If you go here, it’ll get you started. Then you can use this, which works:

    String level = String.format("\u001b[0;34m%s\u001b[m", "%-5level");
    AppenderComponentBuilder sqlConsole = builder.newAppender("sqlconsole", "Console");
    LayoutComponentBuilder sqlLayout = builder.newLayout("PatternLayout");
    String colorSql = String.format("\u001b[0;35m%s\u001b[m", "%msg");
    
    String redLevel = String.format("\u001b[0;31m%s\u001b[m", "%-5level");
    ComponentBuilder patternSelector = builder.newComponent("LevelPatternSelector")
      .addAttribute("defaultPattern", level + ": " + colorSql + "%n")
      .addComponent(builder.newComponent("PatternMatch")
          .addAttribute("key", "ERROR")
          .addAttribute("pattern", redLevel + ": " + colorSql + "%n"));
        
    sqlLayout.addComponent(patternSelector);
    sqlConsole.add(sqlLayout);
    builder.add(sqlConsole);

It’s using bash (shell?) color codes but…I hope you can manage. Then reference the “sqlconsole” appender when you configure the loggers, or as otherwise needed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.