Spring Boot with log4j2 not working when change default properties file name - spring-boot

I have Spring Boot application and I want to use log4j2 instead of logback. I've already done all the necessary steps to exclude spring-boot-starter-logging from spring-boot-starter-web and added spring-boot-starter-log4j2 dependency.
When I add log4j2.properties file under resources folder it works correct and I can see logs.
But when I change file name to, lets say log4j2-demo.properties and set logging.config=classpath:log4j2-demo.properties nothing prints to console. For testing purpose I've set different name for lo4gj2 file in logging.config and it gives error with file not found and I think logging.config property actually working and reading my properties file.
application.properties file:
spring.profiles.active=dev
application-dev.properties file:
logging.config=classpath:log4j2-demo.properties
log4j2 properties file:
status=debug
name=PropertiesConfig
#
filters=threshold
#
filter.threshold.type=ThresholdFilter
filter.threshold.level=debug
#
appenders=console
#
appender.console.type=Console
appender.console.name=STDOUT
appender.console.layout.type=PatternLayout
appender.console.layout.pattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
#
rootLogger.level=info
rootLogger.appenderRefs=stdout
rootLogger.appenderRef.stdout.ref=STDOUT
my application structure:
src
main
java
resources
application.properties
application-dev.properties
log4j2-demo.properties
pom.xml :
...
<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.graylog2.log4j2</groupId>
<artifactId>log4j2-gelf</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.zalando/logbook-spring-boot-starter -->
<dependency>
<groupId>org.zalando</groupId>
<artifactId>logbook-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
...

If you use log4j 2.13.0 you can use profiles to define log4j 2 system properties in your spring configuration. So you could have:
application-dev.properties
log4j2.configurationFile=log4j2-demo.properties.
Log4j 2.13.0 also supports placing the log4j 2 configuration file in Spring Cloud Config.

I'm not sure if this answer applies to this question, but in my case, I added the resource to the build configuration on my pom.xml, e.g.
...
<build>
...
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include> <!-- or **/*.properties -->
</includes>
</resource>
</resources>
...
</build>
...
Of course, I excluded spring-boot-starter-logging from spring-boot-starter-web and spring-boot-starter-actuator
...
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
...
Although, I used the default log4j2 file name log4j2.xml and the step configuration on the application.yml was not required, I mean this configuration logging.config=classpath:log4j2-demo.properties

Related

Spring Boot with Jetty: disable o.a.tomcat.util.scan.StandardJarScanner

I use Spring Boot with Jetty and JSP/JSTL:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>apache-jsp</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>apache-jstl</artifactId>
</dependency>
During startup, I get a number of warnings like:
WARN 18439 --- [ main] o.a.tomcat.util.scan.StandardJarScanner : Failed to scan [file:/home/user/.m2/repository/.../guava.jar] from classloader hierarchy
There are spurious jars in these warnings. Why tomcat scans anything if it is absent from the configuration files and it is Jetty which runs? Is the scan needed for e.g. JSP/JSTL? Can it be disabled? I can't use this because no Tomcat libraries are available in the application.
EDIT: Tomcat (?) sources are apparently called by Jasper, used in turn by Jetty. Thus, I put this into pom.xml in order to disable Jar scanning by Jetty:
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<webApp>
<!-- no need to scan anything as we're using servlet 2.5 and moreover, we're not using Servl
<!-- for more relevant information regarding scanning of classes refer to https://java.net/j
<webInfIncludeJarPattern>^$</webInfIncludeJarPattern>
<containerIncludeJarPattern>^$</containerIncludeJarPattern>
<!--<webInfIncludeJarPattern>.*/spring-[^/]*\.jar$|.*/.*jsp-api-[^/]\.jar$|./.*jsp-[^/]\.jar
</webApp>
</configuration>
</plugin>
but it did not have any effect.
Your org.apache.tomcat.util.scan.StandardJarScanner is coming from the apache-jsp-<ver>.jar on the classpath.
Apache Jasper JSP needs to scan your classpath for TLDs when it does the JSPC steps.
Since you are using spring-boot, there's no real separation of WebAppClassLoader and SystemClassLoader, so it's forced to scan the entire classloader hierarchy to find those TLDs.
This scan is independent of Jetty, so that means the webInfIncludeJarPattern and containerIncludeJarPattern configurations will have no impact.
The best advice here is to precompile your JSP's with jspc during build-time and just have the runtime Jasper JSP never have the need to kick off JSPC and it's associated TLD scan.
If you still want runtime JSPC, consider setting the following property at Server startup, before your Context has started to initialize.
System.setProperty(
org.apache.tomcat.util.scan.Constants.SKIP_JARS_PROPERTY,
"*.jar");
That will tell the StandardJarScanFilter to skip all files ending in .jar.
Note that there is also a Constants.SCAN_JARS_PROPERTY which you get to specify specific jars to scan. (I don't know if this property supports globs, or relative references)

WEB-INF not getting added to SpringBoot jar

I'm putting together a webapp using SpringBoot.
The REST part works fine, but the "JSP part" is borked. The endpoints are called, everything is fine until I return the basename of the JSP page, such as return "info"; The method returns a String.
When I invoke an endpoint, I get this message:
[...] [dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Could not resolve view with name 'info' in servlet with name 'dispatcherServlet'] with root cause
javax.servlet.ServletException: Could not resolve view with name 'info' in servlet with name 'dispatcherServlet'
I followed "the pattern" for adding JSP support to SpringBoot (I say "the pattern" because the dozen or so sources I found all seem to quote the same example).
I'm building a JAR with Maven, looking into that jar, I don't find the JSP files, or even any of the WEB-INF directory structure, so I believe the problem is somewhere between Maven and SpringBoot's plugin.
Here are the pieces of the POM, most of the dependencies removed:
<packaging>jar</packaging>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
...
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
The POM was built mostly from an archetype.
I'm rather ignorant about debugging Maven builds, assuming that this is a Maven problem, however, I suppose it could have something to do with the springboot plugin. I appreciate all assistance, include better resources to read than the ones that I found.
UPDATE
Per Qiu Zhou's comment about the , I added the following to the POM:
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
and moved the JSP directory to src/main/resources/WEB-INF/jsp. The JAR file now contains this:
BOOT-INF/classes/WEB-INF/jsp/info.jsp
which seems to be correct. I no longer get the dispatcherServlet message (see above), however, when I curl the site, this is what I get:
% curl localhost:8099/info
{"timestamp":"2020-09-01T17:22:28.413+00:00","status":404,"error":"Not Found","message":"","path":"/info"}
The controller code is this:
#Controller
public class SimpleController {
#GetMapping("/info")
public String info() {
return "info";
}
}
I remain perplexed -- Is the JAR built correctly??
Thanks
You are not specifying the version of the plugin you wish to use. Depending on the version you might need to configure the plugin to add the resources directory to the application classpath by adding the following to the plugin configuration
<configuration>
<addResources>true</addResources>
</configuration>
This enables hot reloading of resources, but what is actually recommended now for this and other development features is adding spring dev tools dependency.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>2.3.3.RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>
You can learn more about it by reading the plugin docs.
https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/html/#run
khmarbaise provided a solution in his comment - which was to package the JAR as a WAR. I waited for him to post an answer v. a comment, but its been quite a while, so I will answer on his behalf.
try following steps:
1、include jstl dependency:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
2、put your jsp files in src/main/webapp/WEB-INF/jsp directory. (manually create it if does not exist)
3、set view prefix in application.properties or application.yml:
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
4、specify where jsp files should be in output, put following config in pom.xml(based on the your config):
<packaging>jar</packaging>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
...
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
<includes>
<include>**/**</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>

How to configure for Spring Boot Configuration Annotation Processor using #ConfigurationProperties on IntelliJ?

On IntelliJ, I am getting a Spring Boot Configuration Annotation Processor not configured for having #ConfigurationProperties. Below is my class:
#Configuration
#ConfigurationProperties(prefix = "abc")
#Data
#RefreshScope
class Config {
String propA;
String propB;
...
}
I am not sure what's causing this and when I click on the wrench for settings, I do not see any options to configure for metadata files.
I faced the same problem with IntelliJ IDEA 2020.2 and Maven 3.6.2. The solution was to explicitly set the annotation processor in the maven-compiler-plugin settings. I found the answer here:
https://stackoverflow.com/a/48028193/9989732
https://stackoverflow.com/a/64031211/9989732
The full configuration:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.4.2</version>
<optional>true</optional>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<annotationProcessorPaths>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.4.2</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
I resolved it by adding the following dependency to my pom file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.2.6.RELEASE</version>
<optional>true</optional>
</dependency>
You can easily generate your own configuration meta-data file from items annotated with #ConfigurationProperties by using the spring-boot-configuration-processor jar. The jar includes a Java annotation processor which is invoked as your project is compiled. To use the processor, simply include spring-boot-configuration-processor as an optional dependency, for example with Maven you would add:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
For Gradle, like Maven, we need to add The appropriate annotation processor. To do so, add a line to the dependencies section in your build.gradle file.
dependencies {
...
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor:'
...
}

Spring Boot logging with Log4j2

Written simple POC to prove and test Spring Boot and log4j2 compatibility. Once successful I will move it to real application.
Please refer my POC source code:
https://github.com/Dennyss/SpringBootLog4j2POC
I know/read about Spring version and log4j2 compatibility from:
How to set up Spring Boot and log4j2 properly?
Found and tried recommendations described here:
Spring-Boot logging with log4j2?
But still not working. The problem is that both application logs and Spring logs are printing to console only.
Please refer maven dependencies below (from POC):
<dependencies>
<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>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
If I don't exclude Spring's logback and don't add boot-starter-log4j2 then application logs are printing to application file but Spring logs are not printing at all. I feel the problem somewhere with dependencies. Appreciate any help.
According to the Spring Boot Logging documentation, the location of the logging configuration file can be specified using the logging.config property. I noticed that your start.sh script is passing -Dlog4j.configurationFile. Normally, this would be sufficient for direct Log4J 2 integration, but Spring Boot uses logging.config.
After switching to this, it writes to the log files:
java -Dlogging.config=/share/LogPOC/log4j2.xml -cp poc.jar:libs/* com.poc.logger.Application

Log4j.properties in Spring boot

How to load Custom Log4j.properties file in Spring boot
My code in application.properties is here
logging.file=E:/Apps_Tek/apps-webservices-log/apps-webservices.log
logging.level.*=INFO
logging.config=log4j.properties
My code in log4j.properties is here
log4j.rootLogger=INFO,ConsoleAppender,FileAppender
log4j.appender.ConsoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.ConsoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.ConsoleAppender.layout.ConversionPattern=%-7p %d [%t] %c [%X{userName}] [%X{accessToken}] - %m%n
log4j.appender.FileAppender=org.apache.log4j.RollingFileAppender
log4j.appender.FileAppender.File=E:/Apps_Tek/apps-webservices-log/apps-webservices.log
log4j.appender.FileAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.FileAppender.layout.ConversionPattern=%-7p %d [%t] %c [%X{userName}] [%X{accessToken}] - %m%n
But i am not getting any expected output i.e., spring boot is not loading log4j.properties file. Spring boot is having its own default logging.
log4j.properties file is in src/main/resources
My question is how to map log4j.properties file with logging.config property in application.properties if it is in src/main/resources.
Please suggest all the required changes.
Thanks for any help in advance.
If you want spring boot to use log4j instead of its own default logging (logback) then you have to exclude default logging and include the log4j dependency for spring boot in your pom.xml:
<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-log4j</artifactId>
</dependency>
that way is going to look for your log4j.properties file located in src/main/resources.
Also if you wish to use properties defined in you application.properties inside the log4j.properties file
for example, you want to have log.file.path defined in your application.properties and use it on log4j.properties
Then you have to define filtering inside your pom.xml:
<filters>
<filter>src/main/resources/application.properties</filter>
</filters>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>log4j.properties</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
That way you can have:
log4j.appender.file.File=${log.file.path}/${project.artifactId}.log
in your log4j.properties file
To exclude default logging and include the log4j dependency for spring boot in your pom.xml:
<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>
if you wish to use log4j properties defined in you application.properties inside the log4j.properties file need to add below property in application.properties file.
logging.config = src/main/resources/log4j2.properties
Then spring boot will read the properties from log4j2.properties file
In log4j2.properties file add the below properties
name=PropertiesConfig
appenders = console, file
appender.console.type = Console
appender.console.name = ConsoleAppender
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n
appender.file.type = File
appender.file.name = FileAppender
appender.file.fileName=/home/ubuntu/application.log
appender.file.layout.type=PatternLayout
appender.file.layout.pattern= %d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n
loggers=file
logger.file.name=com.project
logger.file.level = debug
logger.file.appenderRefs = file
logger.file.appenderRef.file.ref = FileAppender
rootLogger.level = debug
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = ConsoleAppender
Is there any other work around which doesnot require to specify
'logging.config = src/main/resources/log4j2.properties' inside application.properties file..?
Note : Spring boot version i am using is 2.1.3.RELEASE
Reference : https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html
My guess is that your pom.xml file is not set up to include the correct log4j dependency. If you do that it should automatically work. See their example at spring-boot-sample-actuator-log4j. Their project includes the artifact spring-boot-starter-log4j which should then allow your log4j.properties to be picked up from the current src/main/resources location and you should no longer need the logging.* entries in your properties. It may also be possible that you need to exclude their spring-boot-starter-logging as I see they are doing that as well. If this does not seem to resolve it please post your POM file in a location I can see it. Please let me know if this works for you.
In case someone faces the same problem, I did not have the spring-boot-starter dependency so I had to add the to the spring-boot-starter-web dependency, this is how it looked:
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Excluding logback dependencies to use l4j2 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
Then you add the Log4j2 Dependency:
<!-- Add Log4j2 Dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Your log4j2.properties file will be used for logging configurations from now on.

Resources