Prevent Spring Boot from printing logs to console - java

I am using spring boot for my application and I am using default spring boot logging.
In my application.properties, I have added file path for logging.file,
logging.file= ${logger_path}
and my pom.xml contains
<logger_path>/tmp/app.log</logger_path>
When I start the application, it prints the logging messages to the file at /tmp/app.log, but the problem is it also prints the log messages on the console. I really don't understand why it is printing on console (though it is printing them to the specified file) when I have specified a log file.
Is there any configuration to prevent spring boot from printing the log messages to console?

Spring boot comes with build-in logback logger, which is configured to print to the console by default.
You need to overwrite the logback configuration (providing your own logback.xml on the classpath).
This is described here - - section 66.1
How to disable logback logging read here -
as you can see you have to provide the value OFF...something like:
<configuration>
<include resource="base.xml" />
.
.
<property name="root.level.console" value="OFF" />
</configuration>
Note: Keep in mind that the general idea here is that the logback configuration coming from spring-boot is minimal. The intention is that you provide your own logback configuration and completely overwrite the existing one - e.g. providing your own logback configuration with only log file-appender configured - this should be your general approach.

Include file-appender.xml and not console-appender with following configuration in logback-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
You also need to add logging.file to your application.properties
This is in compliance to what is mentioned in spring boot documentation - http://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html

I tried removing console configuration from logback.xml. But, It was still logging in console. So What I did is, I just removed the appender being added in the logging configuration by springboot. Thereby, we can stop springboot logging in console and separate log file. Add the below lines at the end of your application specific appenders are added. Your custom appender should not match any of these appender names. It worked for me.
// get instance of your log4j instance
Logger logger = LogManager.getRootLogger();
logger.removeAppender("CONSOLE"); // stops console logging
logger.removeAppender("LOGFILE"); // stops file logging

A similar discussion can be found here.
My logback.xml looks like that:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
Just in case you still experience an issue: I have read many discussions about that topic and it was not working at all for me. Unfortunately I have made a really stupid mistake when I have created the file logback.xml for the very first time: A space was added at the beginning of the filename. Therefore the file was never used. So just have another look on the filename, add the file in "src/main/resources" and remove any "logging.config" entries from your property files.

Tested with latest 1.3.1 release, with newer releases base.xml has been renamed to defaults.xml
Answer here

Related

spring boot command line run not using logback-spring.xml

This app works fine in IntelliJ and creates the log files as per configurations, however when launched the app from command line its not using logback-spring.xml file and instead goes on to create *tmp/spring.log file which seems to coming from spring *logback/base.xml.
I have spent couple of days to troubleshoot this issue but nothing seems to work so far and other questions do not address the underlying issue, your help is appreciated.
I am launching the app as -
java -jar abc.jar -Dspring.profiles.active=test
I can see that logback-spring.xml is present inside abc.jar as
BOOT-INF/classes/ logback-spring.xml
Here you can find how to configure logback with spring-boot howto.logging.logback
With src/main/resources/logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<!-- include spring boot file-appender -->
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" /> <!-- add file-appender -->
</root>
<logger name="com.example" level="DEBUG"/>
</configuration>
And providing a logging file-name in src/main/resources/application.properties
logging.file.name=application.log
You should see a file application.log in the same directory as you launched your application with
java -jar your-app.jar --spring.profiles.active=test

Spring Boot: Enable logging in file in production environment only [duplicate]

I am implementing 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
logback-prod.xml
I am using Spring Boot version 1.2.2.RELEASE.
As you can read in Spring Boot documentation:
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. Am I on the right track with the above approach?
I have other solutions that work, but I find them not as elegant (conditional parsing with Janino in logback.xml file or command line property).
I found a solution and I understood why Spring doesn't use my logging.config property defined in the application.properties file.
Solution and explanation
When initializing logging, Spring Boot only looks in classpath or environment variables.
The solution I used was to include a parent logback.xml file that included the right logging config file according to the 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.
Example for JVM properties: -Dspring.profiles.active=dev
Reference documentation
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, so please 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 a conditional processing.
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
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
Documentation link here:
<springProfile name="dev">
<logger name="org.sample" level="DEBUG" />
</springProfile>
<springProfile name="prod">
<logger name="org.sample" level="TRACE" />
</springProfile>
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>
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.
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.

Logback logs kept open by application and not deleting from disk

I have an Spring-Boot application on Linux that writes to service logs using Logback. Logback is setup to write to a file (account-service.log) and rotate the file at 10.5MB and finally delete the file on the 8th rotate. This is the default configuration.
The issue I'm having is the first log file created is written to past the 10.5MB size limit (it does rotate at the 10.5MB mark). So it's increasing in size until it becomes the 8th file and then it tries to get deleted. At this point the file is 84MB (10.5MB * 8) size. You can see here the file increasing in size
The main problem with that is that the OS tries to delete the file but since the application, because of Logback, still keeps it open then the filesystem doesn't show the deleted file (like with command find or du) and the system still keeps the space allocated on the disk. Also the file is still written to so it's taking up more and more disk space. I ran sudo lsof | grep deleted to find out that this file isn't being fully deleted.
Also interestingly the group that that first file belongs to is different than the rest. The first file has group root while the rest have the correct group name of account-service. This might be why the application can't close the file but I'm not sure.
The Logback dependency comes from my Spring-Boot pom:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
The subsequent log files do get deleted ok and don't get written to past the 10.5 MB limit.
Has anyone seen this issue or found a way to fix it?
So I was able to solve most of my problems but one issue still remains.
The main issue was that I was using the built in logback xml for logging (base.xml). There it was configured for both console and file logging to be enabled.
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
So when I run it locally I get my logs written to my terminal and service log file which is good but the issue occurs on deployed instances. What happened was that both "CONSOLE" and "FILE" loggers where writing to the file which is why even after the first file rotated, it was still being written too. The "CONSOLE" logger was writing to the first file even though it rotated because from its point of view that file is the terminal. This also helped fix a double logging issue we were seeing.
My fix was to add my own logback xml (logback-spring.xml) to override the base.xml one.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<springProfile name="default">
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</springProfile>
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
This stops console logging on deployed instances and thus keeps the first file from logging past the 10.5MB limit. This fix fixed the disk space issue we experienced too.
The only issue I was not able to solve yet it why the file is kept open by the application and thus not allowing it to be fully deleted from the disk space.
As you have mentioned the file as root user access permissions which do not look correct. Can you check the application by doing ps -efw | grep applicationName to see what user permissions it has as your application should have application user permissions only.

Components written against log4j1 are not logging after log4j2 upgrade

I've been banging my head over this one for a few days and can't get it figured out. Log4j2 is backwards compatible if you add the log4j1 compatibility library.
My web-inf\lib has:
slf-api
log4j-1.2-api (backwards compat. library)
log4j-api (log4j2)
log4j-core (log4j2)
log4j-web (auto-wiring for web applications)
My web.xml has:
<!-- log4j2 auto-wiring -->
<context-param>
<param-name>log4jConfiguration</param-name>
<param-value>file:///${catalina.base}/conf/log4j2.xml</param-value>
</context-param>
My [tomcat]/conf/log4j2.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug">
<Appenders>
<!-- Appends to CONSOLE -->
<Console name="consoleAppender" target="SYSTEM_OUT">
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="%5p (%F:%L) - %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="com.mycompany.componentA" level="WARN" />
<Logger name="com.mycompany.componentA.QueryLogger" level="DEBUG" />
<Logger name="com.mycompany.mycode" level="DEBUG" />
<Root level="WARN">
<AppenderRef ref="consoleAppender" />
</Root>
</Loggers>
</Configuration>
I have upgraded code under my control (com.mycompany.mycode) to log4j2 APIs and they work/log flawlessly. Code that is not under my control but was written against log4j1 (com.mycompany.componentA) just simply fails to log at all. No errors, no debugs, nothing.
Something interesting though... when I start the application I get a log4j1 warning about incorrect configurations when the application starts. This also stumps me because there are no log4j1 libraries (except the compatibility API) in the WAR. Warning is:
log4j:WARN No appenders could be found for logger (com.mycompany.componentB)
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
EDIT: I (finally) figured out what's going on. One of my dependencies did a horribly bad thing and BUNDLED the log4j1 classes into it's final jar. So there are no log4j1 jars on the classpath, but there are log4j1 CLASSES on the classpath.
The only way I was able to get this working was to:
Create BOTH a log4j1 and log4j2 XML configuration files (even though the log4j2 configuration contained all the loggers I wanted)
Let Log4j2 auto-wire itself via the 'log4j-web' artifact + 'log4jConfiguration' web.xml parameter
Manually wire log4j1 by calling the deprecated Log4jConfigurer.initLogging(...) API on server startup
This is probably horribly incorrect, but as indicated above, it was the only way I got it working after weeks of fooling around.
My understanding of the lo4j1 bridge is that wiring up log4j2 and including the bridge is all that should be required (e.g. no need to manually wire log4j1). In practice, that does not seem to be occurring.
That error message means you still have the log4j-1.x jar in your application. Look for it in your WEB-INF/lib and remove it and then it should work.
If not in WEB-INF/lib, then perhaps in your web container (Tomcat?) shared lib folder? Ralph is right that this error message is generated by Log4j-1.2, so it is on the classpath somewhere... Try printing the value of System property java.class.path if necessary.
Update: another way to find the location of the Log4j1 jar is by printing the value of org.apache.log4j.AppenderSkeleton.class.getResource("/org/apache/log4j/AppenderSkeleton.class") from your application.
(I originally suggested Category but this also exists in the Log4j 1 bridge, so AppenderSkeleton is better.)

Spring Boot, logback and logging.config property

I am implementing 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
logback-prod.xml
I am using Spring Boot version 1.2.2.RELEASE.
As you can read in Spring Boot documentation:
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. Am I on the right track with the above approach?
I have other solutions that work, but I find them not as elegant (conditional parsing with Janino in logback.xml file or command line property).
I found a solution and I understood why Spring doesn't use my logging.config property defined in the application.properties file.
Solution and explanation
When initializing logging, Spring Boot only looks in classpath or environment variables.
The solution I used was to include a parent logback.xml file that included the right logging config file according to the 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.
Example for JVM properties: -Dspring.profiles.active=dev
Reference documentation
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, so please 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 a conditional processing.
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
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
Documentation link here:
<springProfile name="dev">
<logger name="org.sample" level="DEBUG" />
</springProfile>
<springProfile name="prod">
<logger name="org.sample" level="TRACE" />
</springProfile>
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>
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.
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.

Categories

Resources