Tomcat logs are being written to syslog instead to the application log in Spring Boot and Log4j - spring

It's a Spring Boot application with Log4j for logging.
All logs from org.apache.catalina.* are being sent to syslog, and it includes also uncaught exceptions.
Our app uses Log4j (v1) since it uses legacy code dependencies that use Log4j.
Spring Boot version is 1.5.2.RELEASE.
I believe that with correct set-up, also tomcat logs will be written to the same file that is configured in the log4j.xml, but i couldn't find any answer to that problem.
pom.xml (relevant parts):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring Logging -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.2.8.RELEASE</version>
</dependency>
log4j.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="true"
xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} [%t] %5p %c{1} - %m%n" />
</layout>
</appender>
<!-- File appender -->
<appender name="logFileAppender" class="org.apache.log4j.FileAppender">
<param name="File" value="/tmp/myappname.log"/>
<param name="Append" value="true" />
<param name="BufferedIO" value="false" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} [%t] %5p %c{1} - %m%n" />
</layout>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="consoleAppender" />
<appender-ref ref="logFileAppender" />
</root>
</log4j:configuration>

Could you try excluding it in the actuator artifact?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
Based on your comment:
If I understood correctly, the application is logging fine, it's the servlet container the logging to syslog when exceptions bubble up, isn't?
Could you also try adding:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-log4j</artifactId>
</dependency>
and / or passing where log4j config file is located:
-Dlog4j.configuration=<path to file>
If these don't work, the only thing I could think of is that you are using Spring Boot 1.5.x doesn't get along with Log4j and likely requires to uplift it to Log4j2

Related

Log4j2 with SpringBoot (configuration)

I did read other questions, also I've read configuration and I came up with a solution but I don't know if it's okay.
Problem: I have SpringBoot application and I was trying to use log4j2 as logging framework but I couldn't configure it properly. I had correct xml configuration, configuration was on a classpath but I was able to log only these 4 log levels:
INFO, WARN, ERROR and FATAL
By log4j2 documentation, if configuration is not found, default configuration is used and that configuration display only ERROR and FATAL, but mine app was showing 4 log levels as I wrote earlier. I found that behavior bizarre so I kept reading articles and I came up with this solution.
I replaced these 3 dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
With these 2:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
And it works, but it feels wrong. By excluding spring-boot-starter-logging my log4j2.xml has power again.
This is my (log4j2) XML file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} %p %m%n</Property>
<Property name="APP_LOG_ROOT">c:/temp</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${LOG_PATTERN}" />
</Console>
<RollingFile name="appLog"
fileName="${APP_LOG_ROOT}/SpringBoot2App/application.log"
filePattern="${APP_LOG_ROOT}/SpringBoot2App/application-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${LOG_PATTERN}" />
<Policies>
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="1" />
</RollingFile>
</Appenders>
<Loggers>
<Logger name="com.howtodoinjava.app" additivity="false">
<AppenderRef ref="appLog" />
<AppenderRef ref="Console" />
</Logger>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
And java class:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MyApp{
private static final Logger logger = LogManager.getLogger(MyApp.class);
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
logger.fatal("HoHoHo FATAL");
logger.debug("HoHoHo DEBUG");
logger.trace("HoHoHo TRACE");
logger.info("HoHoHo INFO");
logger.warn("HoHoHo WARN");
logger.error("HoHoHo ERROR");
}
}
So now if I set Root level="trace" in my log4j2.xml file, I will see all these HoHoHo logs in a console which is what I want. If I set Root level="error" I will see only error and fatal which is also okay. However, I noticed that by changing these levels logs, my application shows a bit different logs while starting so I'm not sure if that is okay or not.. I'm wondering if I configured everything the way it should be configured.
These 2 images are showing what is different when I change log levels between trace and error.
So in one example I have ~1150 lines and with other approach I have ~1200 and they're mostly identical besides this. And as you can see, when I use trace as logging level, my application doesn't start with Spring drawing on a first line in a console.
Sorry if post is too long or unclear, so I'll wrap my question up once again in one sentence. Did I configure my log4j2 correctly (check 2 dependencies I'm using instead of 3 that I removed). Thanks!
Everything is configured correctly.
Also check out https://www.baeldung.com/spring-boot-logging#log4j2-configuration-logging

Log4j2.xml with springboot is not generating log file

I am upgrading log4j1 to logj42 in one of the springBoot porject (maven, Java 1.8) with log4j-core,log4j-api as maven dependency.
Log file mentioned in log4j2.xml as Rolling file appender is not creating log file, I am able to see the logs in console but no log file. Please reply if anyone has faced same issue.
By default spring boot contains an integration with logback logging library.
So you'll have to exclude the "default" and add a special starter that will handle the integration:
In the pom.xml make sure you have the following:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Optional: If you want to use an asynchronous logging, add also the following dependency:
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.6</version> <!-- check the actual version it might be different -->
</dependency>
After this step you can start configuring the log4j2. There are plenty of sample configurations and tutorials about this, examples: here and here.
I won't dive into possible configurations of log4j2, but from the spring boot's standpoint I'll mention that you should place the log4j2's configurations into src/main/resources/log4j2.xml
You can try with the below log4j2.xml. This is working for me.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config">
<Properties>
<Property name="basePath">/home/user/myapp/logs</Property>
</Properties>
<Appenders>
<!-- File Appender -->
<File name="FILE" fileName="${basePath}/my-app.log" append="true">
<PatternLayout pattern="%-5p | %d{yyyy-MM-dd HH:mm:ss} | [%t] %C{2} (%F:%L) - %m%n" />
</File>
<!-- Console Appender -->
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%-5p | %d{yyyy-MM-dd HH:mm:ss} | [%t] %C{2} (%F:%L) - %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="com.abc.xyz" level="debug" />
<Root level="info">
<AppenderRef ref="STDOUT" />
<AppenderRef ref="FILE" />
</Root>
</Loggers>
</Configuration>
Change the log file name and path accordingly.
Also change the package for the logger. <Logger name="com.abc.xyz" level="debug" />

How to add a rolling file logger to SpringBoot?

I am learning SpringBoot using this very good example here.
But one thing I wanted to learn how to add into this project is RollingFileAppender.
In my previous projects I always did the following:
1) Added these dependencies
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
2) Add the following file log4j.properties in the src/main/resources folder.
# Root logger option
log4j.rootLogger=INFO, stdout, loggerId
log4j.appender.loggerId=org.apache.log4j.RollingFileAppender
log4j.appender.loggerId.layout=org.apache.log4j.PatternLayout
log4j.appender.loggerId.layout.ConversionPattern=%d [%t] %-5p (%F:%L) - %m%n
log4j.appender.loggerId.File=logs/app.log
log4j.appender.loggerId.MaxFileSize=100MB
log4j.appender.loggerId.MaxBackupIndex=30
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# Silence unnecessary logs
log4j.logger.net.schmizz=OFF
log4j.logger.io.javalin=OFF
log4j.logger.net.dv8tion.jda.core.requests=OFF
3) In the code I can just invoke the logger:
private Logger LOG = LoggerFactory.getLogger(<class>)
(...)
LOG.info("logging a message")
And this would throw up logs to the console, and to a rolling file called logs/app.log with maximum size of 100MB (as defined in the properties file).
What is the correct way for doing this, in modern SpringBoot projects like the one I linked above in GitHub, possibly using the logger that comes with SpringBoot?
Thanks!
Logging in Spring Boot isn't fundamentally different than in a vanilla Java project. Spring Boot uses Commons Logging for all internal logging but leaves the underlying log implementation open. Default configurations are provided for Java Util Logging, Log4J2, and Logback. In each case, loggers are pre-configured to use console output with optional file output also available. By default, if you use the “Starters”, Logback is used for logging.1
If you want to stick with Log4J2, you'll have to exclude the default Logback dependency and include Log4J2:
<!-- exclude logback , add log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Then add a new file called log4j2.xml or (log4j2.properties) in src/main/resources
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="loggerId" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="logs/app.log"/>
<param name="MaxBackupIndex" value="30"/>
<param name="MaxFileSize" value="100MB"/>
<layout class="org.apache.log4j.PatternLayout ">
<param name="ConversionPattern" value="%d [%t] %-5p (%F:%L) - %m%n"/>
</layout>
</appender>
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
</layout>
</appender>
<logger name="io.javalin">
<level value="OFF"/>
</logger>
<logger name="net.dv8tion.jda.core.requests">
<level value="OFF"/>
</logger>
<logger name="net.schmizz">
<level value="OFF"/>
</logger>
<root>
<level value="INFO"/>
<appender-ref ref="stdout"/>
<appender-ref ref="loggerId"/>
</root>
</configuration>
For more information, baeldung.com is my goto place for good to-the-point tutorials on how to do this stuff. Since you're asking specifically for advice on Rolling File Appenders, I recommend A Guide to Rolling File Appenders. There's also a more generic article on Logging in Spring Boot.
Personally, I like to use Lombok annotations like #Slf4j to get rid of the logging boilerplate and prevent copy-and-paste mistakes.
Code on!

Spring output console dissapeared after removing logback dependency

I am trying to use log4j2 as logger, for that i have included
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
and used
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
in every dependency that used logback due to conflict, however after doing this, the spring upon running prints only its Logo and nothing.
DO i need to configure somehow spring for log4j2 or how to solve this?
Yes offcourse. You need to create log4j2.xml in src/main/resources path.
In that Xml file you need to configure your application logging level in ConsoleAppender.
Please add this xml configuration in log4j2.xml.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="ConsoleAppender"></AppenderRef>
</Root>
</Loggers>
</Configuration>

No appenders could be found for logger in local server but same application works fine in Production server- log4j

We have two servers. One for QA and another is Production server (hosted on AWS). I have used "apache-tomcat-8.5.16" server in both environment. We have developed Spring boot app and Log4j configuration is same for applications deployed in both servers.
logging.level.net.companyname= DEBUG
logging.level.com.google.api.ads.dfp.lib.client.DfpServiceClient.soapXmlLogger=WARN
logging.level.com.google.api.ads.dfp.lib.client.DfpServiceClient.requestInfoLogger=INFO
Yet, in local server (used for QA), we are getting the error "log4j:WARN No appenders could be found for logger (org.springframework.web.context.support.StandardServletEnvironment" .
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
log4j:WARN No appenders could be found for logger (org.springframework.web.context.support.StandardServletEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
But in Production server we are getting logs without any problem.
If it does matter, below is the pom.xml configuration related to log4j.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
Even configurations inside "apache-tomcat-8.5.16/conf/logging.properties" file are also same in both servers.
How to get logs as we are getting in Production environment?
What else would make difference when both tomcat server versions are same and same war is deployed on both of them with same configuration settings?
Thank you.
Update:
I downloaded the war file to local from server for testing and even there, log4j is working fine. What else do I need to check?
Thank you.
This is an alternative and recommended solution.
After waiting for a week, I thought, why should I worry on framework that has reached it's end of life. I upgraded to log4j2 and provided log4j2.xml file in the classpath (in my case, /src/main/resources, working in STS-Spring Tool Suite, Spring application.).
However the actual reason for this weird behavior is still unknown.
Below is the pom.xml file tailored only log4j2 dependency for verbosity.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - ***CustomLog*** %msg ***/CustomLog***%n" />
</Console>
<File name="traceLoggerFile" fileName="logs/trace.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
<File name="debugLoggerFile" fileName="logs/debug.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
<File name="infoLoggerFile" fileName="logs/info.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
<File name="errorLoggerFile" fileName="logs/errors.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Logger name="com.packageName" level="TRACE">
<AppenderRef ref="traceLoggerFile" level="TRACE" />
<AppenderRef ref="debugLoggerFile" level="DEBUG" />
<AppenderRef ref="infoLoggerFile" level="INFO" />
<AppenderRef ref="errorLoggerFile" level="ERROR" />
</Logger>
<Root level="DEBUG">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
You need to give proper package name or class name in this line
<Logger name="com.packageName" level="TRACE">
Will be happy if anyone can find the actual reason.
Thank you.

Resources