Ommadawn
Ommadawn

Reputation: 2730

Log4j2 disable console on production

I'm developing a Web app and I'm using log4j2. In developing mode, I'm logging using RollingFile and Console appenders.

Everything is working properly, but I'd want to disable the Console appender when my project will be released and it will be in production mode. Here's a slice of my log4j2.xml code:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="PropertiesConfig" packages="com.project.application">

    <!-- PROPERTIES -->
    <Properties>
        <Property name="webName">Project</Property> 
        <Property name="logBaseDir">${sys:catalina.base}/logs/</Property>
        <Property name="consolePattern">%highlight{[%-5level] [%d{yyyy-MM-dd HH:mm:ss,SSS}] [%c{1}] - %msg%n}</Property>
        <Property name="rollingFilePattern">[%-5level] [%d{yyyy-MM-dd HH:mm:ss,SSS}] [%c{1}] - %msg%n</Property>
    </Properties>

    <!-- APPENDERS -->
    <Appenders>
        <!-- Console -->
        <Console name="Console" 
                 target="SYSTEM_OUT"
                 immediateFlush="true">
            <PatternLayout>
                <pattern>${consolePattern}</pattern>
            </PatternLayout>
        </Console>

        <!-- RollingFile -->
        <RollingFile name="RollingFile" 
                     fileName="${sys:logBaseDir}${webName}/${webName}.log"
                     filePattern="${sys:logBaseDir}${webName}.%d{yyyy-MM-dd}.log"
                     immediateFlush="true">
            <PatternLayout>
                <pattern>${rollingFilePattern}</pattern>
            </PatternLayout>
            <Policies>
                <OnStartupTriggeringPolicy />
                <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            </Policies>
        </RollingFile>

    <!-- LOGGERS -->
    <Loggers>
        <Logger name="com.project.application" additivity="true" level="warn">
            <AppenderRef ref="RollingFile" />
        </Logger>

        <Root level="info"> <!-- @TODO disable in production -->
            <AppenderRef ref="Console" />                
        </Root>
    </Loggers>

</Configuration> 

Thank you!

Upvotes: 1

Views: 3165

Answers (2)

Mukit09
Mukit09

Reputation: 3399

Spring-lookup made my life easier. My appender is like this:

<Appenders>
    <Console name="console-local" target="SYSTEM_OUT">
        <PatternLayout
                pattern="%d{yyyy-MM-dd HH:mm:ss:SSS} [%thread] %-5level %logger{2}:%L - %msg%n" />
    </Console>
</Appenders>

I have added a property like this:

<Properties>
    <Property name="console-appender">console-${spring:profiles.active}</Property>
</Properties>

And the logger is like this:

<Loggers>
    <root level="info">
        <appender-ref ref="${console-appender}"/>
    </root>
</Loggers>

If my active profile is local, thus console-appender will be set to console-local, and the log will be shown in the console, as ref will find console-local.

Again, suppose, my active profile is prod, then console-appender will be set to console-prod, and the log will not be shown in the console, as ref will not find console-prod. Because Console's appender name is still console-local.

My log4j version is 2.14.1

Upvotes: 1

Tomasz Linkowski
Tomasz Linkowski

Reputation: 4496

Use a filter, e.g. ThreadContextMapFilter:

<Console name="Console" target="SYSTEM_OUT" immediateFlush="true">
  <ThreadContextMapFilter onMatch="DENY" onMismatch="NEUTRAL">
    <KeyValuePair key="is-production" value="1"/><!-- skip on production -->
  </ThreadContextMapFilter>
  <PatternLayout>
    <pattern>${consolePattern}</pattern>
  </PatternLayout>
</Console>

The initialization of the ThreadContext entry can be perfomed in a ServletContextListener, e.g.:

@WebListener
public class Log4jThreadContextInitializer implements ServletContextListener {

  @Override
  public void contextInitialized(ServletContextEvent sce) {
    String isProduction = isProduction() ? "1" : "0";
    sce.getServletContext().log("Setting 'is-production' flag for Log4j to " + isProduction);
    org.apache.logging.log4j.ThreadContext.put("is-production", isProduction);
  }

  private boolean isProduction() {
    // TODO: production detection
  }

  @Override
  public void contextDestroyed(ServletContextEvent sce) {
  }
}

Upvotes: 2

Related Questions