spring boot, logback and logging.config property

2019-01-12 18:25发布

问题:

I am implement logging in a spring boot project with logback library. I want to load different logging configuration files according to my spring profiles (property 'spring.pofiles.active'). I have 3 files : logback-dev.xml, logback-inte.xml and logback-prod.xml. I am using spring boot version 1.2.2.RELEASE.

As you can read in spring boot documentation (here). It says:

The various logging systems can be activated by including the appropriate libraries on the classpath, and further customized by providing a suitable configuration file in the root of the classpath, or in a location specified by the Spring Environment property logging.config. (Note however that since logging is initialized before the ApplicationContext is created, it isn’t possible to control logging from @PropertySources in Spring @Configuration files. System properties and the conventional Spring Boot external configuration files work just fine.)

So I tried to set 'logging.config' property in my application.properties file:

logging.config=classpath:/logback-${spring.profiles.active}.xml

But when i start my application, my logback-{profile}.xml is not loaded...

I think logging is a common problem that all projects using spring boot have encountered. I want to know if I am in the right direction or not because I have other solutions that works too but i find them not elegant (conditional parsing with Janino in logback.xml file or command line property).

回答1:

I found a solution and I understood why spring doesn't take care about my 'logging.config' property defined in application.properties file.

Solution and explanation :

When initialize logging, spring boot only looks in classpath or environments variables ( see http://docs.spring.io/spring-boot/docs/0.5.0.M3/api/org/springframework/boot/context/initializer/LoggingApplicationContextInitializer.html).

The best solution I found is to inclued a parent logback.xml file that will included the right logging config file according to my spring profile.

logback.xml :

<configuration>
    <include resource="logback-${spring.profiles.active}.xml"/>
</configuration>

logback-[profile].xml (in this case, logback-dev.xml) :

<included>

    <!-- put your appenders -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
     ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
       <encoder>
           <pattern>%d{ISO8601} %p %t %c{0}.%M - %m%n</pattern>
           <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- put your loggers here -->
    <logger name="org.springframework.web" additivity="false" level="INFO">
        <appender-ref ref="CONSOLE" />
    </logger>

    <!-- put your root here -->
    <root level="warn">
        <appender-ref ref="CONSOLE" />
    </root>

</included>

Note : 'spring.profiles.active' has to be set in command line arguments when starting the app. E.G for JVM properties : -Dspring.profiles.active=dev

Ref docs :

  • http://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html
  • http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html
  • http://docs.spring.io/spring-boot/docs/0.5.0.M3/api/org/springframework/boot/context/initializer/LoggingApplicationContextInitializer.html

Edit (multiple active profiles) : In order to avoid multiple files, we could use conditional processing which requires Janino dependency (setup here), see conditional documentation. With this method, we can also check for multiple active profiles at the same time. E.G (I did not test this solution, put comment if it does not work):

<configuration>

    <if condition='"${spring.profiles.active}".contains("profile1")'>
        <then>
         <!-- do whatever you want for profile1 -->
        </then>
    </if>

    <if condition='"${spring.profiles.active}".contains("profile2")'>
        <then>
         <!-- do whatever you want for profile2 -->
        </then>
    </if>

    <!-- common config -->

</configuration>

See javasenior answer for another example of conditional processing.



回答2:

Another approach that could handle multiple profiles is to create a separate properties file for each environment.

application-prod.properties

logging.config=classpath:logback-prod.xml

application-dev.properties

logging.config=classpath:logback-dev.xml

application-local.properties

logging.config=classpath:logback-local.xml

BE AWARE

If you aren't careful you could end up logging somewhere unexpected

-Dspring.profiles.active=local,dev //will use logback-dev.xml
-Dspring.profiles.active=dev,local //will use logback-local.xml


回答3:

Instead of adding separate logback xmls for each profile or having the IF condition , I would suggest the following (If you have less difference in the xmls') for easy conditional processing :

<springProfile name="dev">
<logger name="org.sample" level="DEBUG" />
</springProfile>
<springProfile name="prod">
<logger name="org.sample" level="TRACE" />
</springProfile>


回答4:

Conditional processing with logback will be a solution without many logback files. Here is a link and a sample logback configuration with spring profiles.

<configuration>

    <property name="LOG_LEVEL" value="INFO"/>

        <if condition='"product".equals("${spring.profiles.active}")'>
           <then>
                <property name="LOG_LEVEL" value="INFO"/>
           </then>
           <else>
                <property name="LOG_LEVEL" value="ERROR"/>
           </else>
        </if>

         .
         .
         appender, logger tags etc.
         .
         .

         <root level="${LOG_LEVEL}">
             <appender-ref ref="STDOUT"/>
         </root>

</configuration>

Also, you might have to add this to your pom.xml

<dependency>
    <groupId>org.codehaus.janino</groupId>
    <artifactId>janino</artifactId>
    <version>3.0.6</version>
</dependency>


回答5:

Spring has support of next tag <springProperty/> inside Logback XML file, this tag described here . It means that you can easily add variable from Spring property file, even this variable value resolves from environment/system variable by Spring.



回答6:

You can specific different logback.xml for different profile, only 3 steps:

1, Specify actived profile in application.properties or application.yml:

spring.profiles.active: test

2, Config logback to include different configuration by profile:

<!DOCTYPE configuration>
<configuration scan="true" scanPeriod="30 seconds">
    <springProperty scope="context" name="profile" source="spring.profiles.active"/>
    <include resource="logback.${profile}.xml"/>
</configuration>

3, Create configuration file logback.test.xml:

<?xml version="1.0" encoding="UTF-8"?>
<included>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    <root level="INFO"/>
</included>

It's very simple, don't need do anything else.