1

Is it possible to load different log4j configuration based on which spring boot profile I am using.

Let's say I have in application.properties

log.level=DEBUG
log.path=/opt/tomcat/logs/blabla.log
log.appender=CONSOLE

and in application-live.properties I have different values for all 3

log.level=WARN
log.path=/crazy/tomcat/logs/blabla.log
log.appender=FILE

and in log4j.xml I have definition for CONSOLE appender, FILE appender, and multiple loggers

<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
        <param name="File" value="${log.path}" />
        <param name="maxFileSize" value="8MB"/>
        <param name="maxBackupIndex" value="50"/>
        <param name="Append" value="true"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d{MM-dd HH:mm:ss} [${project.artifactId}-${project.version}] %p [SearchID - %X{searchID}] %c{1}.%M(%L) %m%n" />
        </layout>
    </appender>
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d{MM-dd HH:mm:ss} [${project.artifactId}-${project.version}] %p [SearchID - %X{searchID}] %c{1}.%M(%L) %m%n" />
        </layout>
    </appender>

<logger name="com.mchange" >
        <level value="${log.level}" />
        <appender-ref ref="${log.appender}" />
    </logger>

    <logger name="java.sql" >
        <level value="${log.level}" />
        <appender-ref ref="${log.appender}" />
    </logger>

    <logger name="org.springframework">
        <level value="${log.level}" />
        <appender-ref ref="${log.appender}"/>
    </logger>
<root>
        <level value="${log.level}"/>
        <appender-ref ref="${log.appender}"/>
    </root>

So I have to inject all 3 values in different places in log4j.xml This configuration is not working right now, since when I use -Dlog4j.debug to check what is going on I see that all the values for the properties are missing, like they are not loaded from application.properties at the time when log4j configuration is being loaded. Is there a way to accomplish this. I've read all of the spring-boot documentation, as I can see there is no example where I use both application properties and explicit log config like log4j which I need. I also need to add, that I cannot use logback instead of log4j.

tibortru
  • 692
  • 5
  • 26

2 Answers2

1

You can use separate folders in src/main/environment for different configurations according to the environment.

Then if you use gradle build like this,

./gradlew build -Penv=prod

Then, to catch the environment add following to your build.gradle,

 project.ext {
 environment = "dev"
 }

 loadConfiguration()

 def loadConfiguration() {
    project.environment = hasProperty('env') ? env : 'dev'
 }

Then copy the config using following while build. (Move this to separate file called copy.gradle and use apply from: 'copy.gradle' at the top of your build file),

task copyConfiguration << {
println "Target environment: $environment"
  copy {
    from "src/main/environment/$project.environment"
    into "src/main/resources"
    include "*/"
  }
}

For maven it seems easy than gradle,

<profiles>
<profile>
    <id>dev</id>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
    <build>
        <resources>
            <resource>
                <directory>src/main/resources/dev</directory>
            </resource>
        </resources>
    </build>
</profile>
<profile>
    <id>prod</id>
    <build>
        <resources>
            <resource>
                <directory>src/main/resources/prod</directory>
            </resource>
        </resources>
    </build>
</profile>
</profiles>

and build like mvn install -Pdev, I took it from here, and read here for some more info.

Community
  • 1
  • 1
Maleen Abewardana
  • 13,600
  • 4
  • 36
  • 39
  • I should have added that I use MAVEN for build. – tibortru Nov 25 '15 at 12:53
  • You can do the same with maven, but i dont have any code right now – Maleen Abewardana Nov 25 '15 at 12:55
  • Thanks @Maleenc I understand your answer know, we used to have these maven profiles before we switched to spring-boot. Altough I did find something similar, I deployed WAR and in command line added -Dlogging.config=classpath:log4j-local.xml , this way I choose which log4j configuration will be used at deployment time, but I need to have fixed values in it for properties like Level, Path, Appender... I guess it's something – tibortru Nov 26 '15 at 12:45
  • I would appreciate, If you could rate or accept my answer. – Maleen Abewardana Nov 26 '15 at 16:13
1

I have managed to have desired implementation with multiple log4j.xml files, one for every profile (log4j-dev.xml, log4j-loca.xml etc.) and with custom LoggingApplicationListener that I implemented based on the answer given here. I copied most of the code from spring's LoggingApplicationListener, I amended changes for methods like in the answer in link, and I refactored method

private void initializeSystem(ConfigurableEnvironment environment, LoggingSystem system) {
        LogFile logFile = LogFile.get(environment);
        String activeProfile = environment.getActiveProfiles()[0];
        String logConfig = "classpath:log4j-" + activeProfile + ".xml";
        if(StringUtils.hasLength(logConfig)) {
            try {
                ResourceUtils.getURL(logConfig).openStream().close();
                system.initialize(logConfig, logFile);
            } catch (Exception var6) {
                this.logger.warn("Logging environment value \'" + logConfig + "\' cannot be opened and will be ignored " + "(using default location instead)");
                system.initialize((String)null, logFile);
            }
        } else {
            system.initialize((String)null, logFile);
        }

    }

This is for example that you have only one active profile at a time. For multiple profiles I have no answer.

Community
  • 1
  • 1
tibortru
  • 692
  • 5
  • 26