Log4j2.xml with springboot is not generating log file - spring-boot

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" />

Related

Spring 5 Framework Logging with slf4j/log4j2

I have a application that I've put together to become familiar with Spring Framework 5, using Maven and Java 8. Once executed, it extracts some information from a PostgreSQL database table and logs it to the console (via slf4j/log4j2).
The actual application logic is working fine - I'm seeing the info retrieved from the database on the console as expected. However, I'm not seeing any of the expected Spring/DBCP2 logging. After the application finishes executing, there are only 15 lines printed on the console - all lines that I specifically logged via logger.debug("...").
The dependencies section of my pom.xml looks like this:
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.1</version>
</dependency>
</dependencies>
My log4j2.xml file looks like this...
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE Configuration>
<Configuration status="INFO" strict="true">
<Properties>
<Property name="CONSOLE_PATTERN">%-5level %c{1} %M - %m%n</Property>
</Properties>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="${CONSOLE_PATTERN}" />
</Console>
</Appenders>
<Loggers>
<Logger name="local.spring5" level="DEBUG" additivity="false">
<AppenderRef ref="STDOUT" />
</Logger>
<Logger name="org.apache.commons.dbcp2" level="DEBUG" additivity="false">
<AppenderRef ref="STDOUT" />
</Logger>
<Logger name="org.springframework" level="INFO" additivity="false">
<AppenderRef ref="STDOUT" />
</Logger>
<Root level="INFO">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
Note that if I change the org.springframework logging level to DEBUG or TRACE, I see spring logging appropriate for those levels. Setting the log level to INFO, WARN or ERROR results in no logging from spring at all. I'm sceptical, to say the least, that spring doesn't log anything at those levels.
Does anyone have any ideas on how to get the spring framework logging to appear?

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.

Logging using log4j2

I'm trying to change from log4j1 to log4j2. What I did:
deleted old configuration file log4j.xml
created new config file log4j2.xml
created jboss-deployment-structure.xml
edited pom
Environment:
Wildfly 10
1 EAR
4 WAR
The web.xml isn't being used in the file. The previous log4j config log was in the EAR (only)
Log4j2 config file
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<File name="MyFile" fileName="all.log" immediateFlush="false" append="false">
<PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
<AppenderRef ref="MyFile"/>
</Root>
</Loggers>
</Configuration>
Jboss deployment structure
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<!--Use log4j.xml file instaead of using the loggin subsystem configuration -->
<exclusions>
<module name="org.apache.log4j" />
</exclusions>
</deployment>
</jboss-deployment-structure>
new maven dependencies
<!-- Apache Log4j API -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
<!-- Apache Log4j SLF4J Binding -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.8.2</version>
</dependency>
<!-- Apache Log4j Core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
Has I said earlier I was using log4j1 with SLF4j has facade. These are the changes I've made (I'm trying to start with a simple configuration file I've found online). The file is not even created, but the console log is working just fine.
Thanks,
I got it to work with a webapp in JBoss 7.1.1 using the below config.
/src/main/resources/log4j2.xml
... above unchanged ...
<File name="MyFile" fileName="/Users/tima/Desktop/all.log" immediateFlush="true" append="true">
... below unchanged ...
WEB-INF/jboss-deployment-structure.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
<deployment>
<exclusions>
<module name="org.apache.log4j" />
</exclusions>
</deployment>
</jboss-deployment-structure>
The pom file is the same as yours.
Test controller
#Controller
#RequestMapping("/test1")
public class HelloWorldController {
private static final Logger logger = LogManager.getLogger(HelloWorldController.class);
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Map<String, Object>> printHello() {
logger.info("entered printHello()");
System.out.println("entered printHello() 2");
Map<String, Object> resultMap = new HashMap<String, Object>();
return new ResponseEntity<>(resultMap, HttpStatus.OK);
}
}
Results
$: cat ~/Desktop/all.log
2017-05-11 15:13:35.918 [http--0.0.0.0-8080-2] INFO com.tima.controller.HelloWorldController - entered printHello()
Also in the server.log I can see the following:
15:13:35,937 INFO [stdout] (http--0.0.0.0-8080-2) entered printHello() 2
EDIT
If you want to use the org.slf4j.Logger logger, you have to add the lines below to the jboss-deployment-structure.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
<deployment>
<exclusions>
<module name="org.slf4j" />
<module name="org.slf4j.impl" />
</exclusions>
</deployment>
</jboss-deployment-structure>
EDIT 2
If you are using an EAR file, you can set up logging by using a common JAR that is shared across other modules / WARs in the EAR file.
In the common JAR have:
The log4j-api, log4j-core, log4j-slf4j-impl as dependencies in the pom.xml.
The log4j2.xml under src/main/resources
Have the common jar as a dependency in the WAR files. And you can remove the jboss-deployment-structure.xml file from all WAR files.
The jboss-deployment-structure.xml file will now be located in the EAR file under src/main/application/META-INF/, and contain:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
<sub-deployment name="war-1.war">
<exclusions>
<module name="org.slf4j" />
<module name="org.slf4j.impl" />
</exclusions>
</sub-deployment>
<sub-deployment name="war-2.war">
<exclusions>
<module name="org.slf4j" />
<module name="org.slf4j.impl" />
</exclusions>
</sub-deployment>
...other wars here...
</jboss-deployment-structure>
The above configuration will print from all WAR files to the same file. But you can configure the log4j2.xml file to print to different files based on the package name. That approach is explained in this question
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<Properties>
<Property name="basePath">C:\\logs</Property>
</Properties>
<Appenders>
<RollingFile name="fileLogger" fileName="${basePath}/app-info.log" filePattern="${basePath}/app-info-%d{yyyy-MM-dd}.log">
<PatternLayout>
<pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="com.howtodoinjava" level="debug" additivity="true">
<appender-ref ref="fileLogger" level="debug" />
</Logger>
<Root level="debug" additivity="false">
<appender-ref ref="console" />
</Root>
</Loggers>
for morw you can follow this link : -
http://howtodoinjava.com/log4j2/log4j-2-xml-configuration-example/
You'll probably fair better to exclude the logging subsystem in your jboss-deployment-structure.xml. I would have done this as a comment, but pasting the xml wouldn't have been pretty.
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<exclude-subsystems>
<subsystem name="logging" />
</exclude-subsystems>
</deployment>
</jboss-deployment-structure>

Resources