In a web application built with Maven 3, is there a way to have Logback use either a ConsoleAppender
or a RollingFileAppender
depending where/how the application is running?
In production the .war file is deployed on Tomcat 7. Locally I'm running the Jetty Maven plugin for testing purposes during development.
I would like to have the logging work like this:
mvn jetty:run
locally: Use ConsoleAppender
*.war
file is deployed on production (Tomcat 7): Use RollingFileAppender
During local development it just seems very comfortable to have all log output on the console. In production I would instead prefer to log to a file: CATALINA_BASE/logs/myApp.log
.
Obviously you could just use both a ConsoleAppender
and a RollingFileAppender
in logback.xml
. But to me it seems unnecessarily redundant to have all log output on production written to STDOUT
AND into a log file. Also, from the Tomcat documentation it sounds like logging to STDOUT on production is a bad practice in general.
I couldn't find any nice solutions on the web. Is there a good solution for this?
Here's my current logback.xml
which always logs to STDOUT
and to the desired log file:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${catalina.base}/logs/myApp.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${catalina.base}/logs/myApp.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.myDomain.myApp" level="DEBUG" />
<root level="DEBUG">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>
Basic Example and Configuration Let's start with a quick example of using Logback in an application. First, we need a configuration file. We'll create a text file named logback.xml and put it somewhere in our classpath: Next, we need a simple class with a main method: This class creates a Logger and calls info () to generate a log message.
By default, if we do not provide any configuration and add the dependencies in the project, Logback automatically configures the console appender and outputs the logs in the console.
By default, if we do not provide any configuration and add the dependencies in the project, Logback automatically configures the console appender and outputs the logs in the console. The default log level set is DEBUG.
In the previous examples, we were using the 11-line configuration file we created in section 4 to print log messages to the console. This is Logback's default behavior; if it can't find a configuration file, it creates a ConsoleAppender and associates it with the root logger. 6.1.
You may configure your logback and add profile information in it. No changes in POM required
<springProfile name="local">
<root level="DEBUG">
<!-- no appenders -->
<appender-ref ref="stdout"/>
</root>
</springProfile>
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="FILE_APPENDER"/>
</root>
</springProfile>
You Might need to include below spring files as well
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
For more info checkout logback
I had this same need and it turned out to be quite easy with the help of spring boot"ifulness" and conditional support available for logback. The following is a template that I came up with that could be for any app as it creates the logfile using spring.applcation.name if available, which you can define in bootstrap.properties:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE project>
<configuration>
<if condition='isDefined("logging.path")'>
<then>
<!-- get application name from external properties file -->
<property resource="bootstrap.properties" />
<!-- set local properties here for better visibility -->
<!-- TODO: make these profile conditional based on profiles -->
<property name="logging.maxfilesize" value="1GB" />
<property name="logging.maxdays" value="180" />
<!-- Assume file strategy for appender if logging path given -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- Use application.log if s.a.n not defined in bootstrap.properties -->
<file>${logging.path}/${spring.application.name:-application}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${logging.path}/${spring.application.name:-application}.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches maxFileSize -->
<maxFileSize>${logging.maxfilesize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- keep max days' worth of history -->
<maxHistory>${logging.maxdays}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root>
<appender-ref ref="FILE" />
</root>
</then>
<else>
<!-- The logging path not specified so assume console output -->
<!-- Note: In this case we don't care about the full date just the hour minutes seconds -->
<appender name="CON" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<root>
<appender-ref ref="CON" />
</root>
</else>
</if>
<!-- in-house loggers -->
<!-- 3rdparty Loggers -->
<logger name="org.springframework">
<level value="WARN" />
</logger>
<!-- default root level for everything else -->
<root>
<level value="INFO" />
</root>
</configuration>
If spring boot app with starter parent, you only need add the following to your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!-- Needed for conditional logback.xml statement support - very cool stuff -->
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
</dependency>
You can use profiles to switch between environment. Say you have two different logback.xml files for local and prod. Create a logback directory inside your resources directory. Inside the resources directory, create an environment specific directory. the directory name and envName inside property should match. Here is an example.
<profiles>
<profile>
<id>local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<envName>local</envName>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<envName>prod</envName>
</properties>
</profile>
</profiles>
<build>
<finalName>kp-prj</finalName>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/java</directory>
<includes>
<include>**/*.class</include>
</includes>
</resource>
<resource>
<directory>src/main/resources/logback/${envName}</directory>
</resource>
</resources>
</build>
And while using running maven command you specify the profile.
mvn run -Plocal
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With