log4j implementation in my spring webapp - spring

i need to implement log4j on my spring webapp. I was trying in using log4j.xml and then calling it in my java file private static Logger logger = Logger.getLogger(IndexController.class);
Somewat like above and then logger.info("Index Controller done successfully");
but it didnt worked out.
So, please get me some steps and where to keep what to make it work. I have kept my log4j.xml inside WEB-INF folder.
Thanks in advance!!!

For the default setup, ensure that the log4j.xml file is at the root of the classpath. Also, ensure that you have the log4j (and commons-logging) dependency.
We may need more information to really get this working with your particular setup.

Related

log4j2 the logger get by Slf4j LoggerFactory.getILoggerFactory can only read default log4j.xml without profile

Use log4j2 in SpringBoot project with test profile,
org.slf4j.LoggerFactory.getLogger("xxx") can get test profile LoggerContext and read configuration from log4j2-test.xml.
But
org.slf4j.LoggerFactory.getILoggerFactory().getLogger("xxx") can only get current LoggerContext and read configuration from log4j2.xml.
LoggerFactory.getLogger("xxx"); // log4j2-test.xml
LoggerFactory.getILoggerFactory().getLogger("xxx"); // log4j2.xml
Is it a bug of log4j2?
I tested LoggerFactory.getILoggerFactory().getLogger("xxx") with Logback, Logback can choose log4j2-test.xml properly.
SpringBoot version: 2.4.5
Add some background to help more people: ParSeq framework prints logs by LoggerFactory.getILoggerFactory().getLogger("xxx").
No, this would not be a bug in Log4j. Log4j knows nothing about Spring profiles and does not incorporate them in its logic of locating a configuration file.
The methods in LoggerFactory that you are calling are static. That means they are implemented by SLF4J. The SLF4J source shows that getLogger("XXX") does
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
which is exactly the same as what you are manually doing in your second call, so I cannot see how there could be any difference between them.
I also doubt that Logback can choose log4j2-test.xml properly since that would be an invalid configuration file for Logback.
It should be a bug of log4j2:
JIRA_LOG4J2-3083

Spring Boot 2: Using external Property-Files

I have a executeable jar what I want to configure by properties outside of the jar. What works fine is application.properties, when putting it to config folder close to the jar. But I have a second property-file what seems not to be picked up and I would like to have the best practice for that.
The folder config looks like:
In the config-folder you will find:
Both property-files are also in the src/main/resources folder.
My StartClass looks like:
#SpringBootApplication
#PropertySource("migration-shrink.properties")
public class MigrationShrinkApplication implements CommandLineRunner {}
My bat file looks like:
java -jar migration-shrink-0.0.1-SNAPSHOT.jar -Dspring.config.location=./config/migration-shrink.properties
I wanted to separate Spring-Configuration from Application-Configuration, thats why I have two different property-files.
Thank you!
The #PropertySource annotation is not necessary.
As of Spring Boot 2.0, you can declare additional locations with:
-Dspring.config.additional-location=./config/migration-shrink.properties
Keep in mind that those additional locations are searched before others, so values can be overridden in the other locations.
See the Spring Boot reference documentation.

How to push external xml file into spring boot embedded tomcat continer

i have created springboot project which gives fat-jar. i want to push external xml file in runtime into it.i want to place that xml file into spring-boot-tomcat container. tried many ways to do it (#import, --spring.config.location,etc) those ways didn't work out for me.
That xml file is ApplicationInsight.xml, which is used to post telemetry from our application to Azure portal.
Highly appreciate any help.
Based on the GitHJub issue, I think part of the problem is how you are passing JVM parameters, and how you are using "spring.config.location".
I am not familiar with Azure Insights really, but if I understand correctly, it is trying to load the ApplicationInsights.xml file to configure itself, and it's doing this automatically. So you really can't set it up in the WebConfigurerAdapter as I previously suggested because it has already initialized itself before that, correct? I left that part in anyways, but I get that it needs to be loaded sooner so I provided a few additional ways to add the file to the classpath ASAP.
New Stuff
First take a look at this line you had originally posted ala GitHub:
java -jar build/libs/file-gateway.jar --spring.config.location=classpath:/apps/conf/ApplicationInsight.xml
Instead the value should be just a folder path, without "classpath" of "file" prefix. Also, try using '-D' instead of '--'.
java -jar build/libs/file-gateway.jar -Dspring.config.location=/apps/conf/
The property is supposed to either refer to a directory containing auto configuration property files for Spring Boot. It can also work for referring to a specific "application.properties|yml" file.
With that, my previous suggestion may work for you.
Old Suggestion
If you require a unique way for loading resources, you can add a resource handler to your application.
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Value("${telemetry.folder}")
private String telemetryFolder;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceLocations(telemetryFolder);
}
}
And/or you could load it with apache IO:
#Value("${telemetry.file}")
private String telemetryFile;
#Autowired
private ResourceLoader resourceLoader;
public String telemtryXml(){
return org.apache.commons.io.IOUtils.toString(resourceLoader.getResource(telemtryFile).getInputStream());
}
But this will only work if the api you are using doesn't need to be initialized much earlier.
More New Stuff
In your last post on the GitHub issue, you tried this:
java -jar build/libs/file-gateway.jar -applicationinsights.configurationDirectory="/apps/conf/"
Instead, try adding the property as a jvm parameter like this:
java -jar build/libs/file-gateway.jar -Dapplicationinsights.configurationDirectory=/apps/conf/
Notice that I added a capital 'D' character after the, and I removed the quotes from the path.
Other ways to add the file to classpath are.
Add the directory to the JVM classpath.
java -cp "build/libs/file-gateway.jar:/apps/conf/*" your.package.MainSpringBootApplication
This requires that you specify the main class which is (commonly) annotated with '#SpringBootApplication' and contains the main method. You do not execute the jar like before, but you do still add it to the classpath.
Forget about SpringBoot, and go back to your roots as a JEE developer. Add a "context.xml" for your app under the "src/main/resources/META-INF" folder, or "src/main/webapp/META-INF". I prefer the later if I'm building an executable war file, and the former for jars.
Example context.xml:
<?xml version='1.0' encoding='utf-8'?>
<!-- path should be the context-path of you application.
<Context path="/">
<Resources className="org.apache.catalina.webresources.StandardRoot">
<PreResources base="/apps/conf"
className="org.apache.catalina.webresources.DirResourceSet"
internalPath="/"
webAppMount="/WEB-INF/classes"/>
</Resources>
</Context>
You can also use JVM parameters with EL.
So if you execute the jar with this:
java -jar build/libs/file-gateway.jar -Dapplicationinsights.configurationDirectory=/apps/conf/
You could set the resources base with this:
<!--snip -->
<PreResources base="${applicationinsights.configurationDirectory}"
<!--snip -->
Hope that helps:)

How to Access Spring Configuration Outside a JAR File

I am new with Spring Boot Development and currently can't move-on on the issue of how to load my spring application configuration outside the jar file.
My existing code looks like this
private ApplicationContext context;
public static void main(String[] args){
SpringApplication.run(SMPPEngine.c1ass);
new SMPPEngine();
}
public SMPPEngine(){
loadConfiguration();
process();
}
private void loadConfiguration(){
context = new ClassPatthlApplicationContext(”application-context.xm1”);
}
What I want to achieve is to have the jar file next to application-context.xml in one directory so that when there are configuration changes,I don't need to recompile my code just to reflect the changes on application-context.xml.
Based on what I've read on the internet, this is possible by using 'file://directory/application.xml' instead of classpath. But my problem on using the later is that when you place your jar and file to other location, I am required to do code change to reflect the new directory which does not solve the problem of getting away from code recompilation.
I hope I made my issue clear, and get an immediately response with you guys :)
Thanks in advance :)
There are many approaches to do this, standard, you can use spring file: prefix for accessing filesystem paths.
but with spring boot, you can specifiy it in application.properties with
spring.config.location propertiy, or you can add it in command line when run the spring boot jar file like
java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
But for your codes, actually you do not need to re-create the spring context from the configuration files, but you want get the context instance, you just need to inject it
#Autowired
private ApplicationContext context;
Another approach, if you have the infrastructure. Would be to use Spring Cloud Config. After your Boot application is configured to read from it, they can be modified at anytime without recompilation or restarting.

Changing application context path leads to using different (unknown) logging configuration

Setup:
Tomcat 6.0.16
Struts 2.1.6
Apache Commons Logging 1.0.4
Log4J 1.2.17
What I did:
Change in server.xml:
<Context path="/" .../></Context>
to
<Context path="/shop" .../></Context>
The issues:
Everything in the application is working fine (on the first glance). All links are correct and working etc.
Now I discovered that the Loggers using Commons Logging (with Log4J) (usually the Loggers in Spring, Struts and OGNL) are using a different logger configuration than the default used before. Loggers using Log4J directly in the application are working fine with this configuration.
For debugging purpose I have a JSP listing all the loggers with:
Logger.getRootLogger().getLoggerRepository( ).getCurrentLoggers()
But the "commons logging logger" are not listed anymore, although I could verify that they exist if I debug the code.
The question:
How do I find the other configuration/root logger?
Do I have to change anything in the struts configuration (or somewhere else) in relation to the context path change?
Any ideas what the issue might be here?
Edit: I'm getting closer:
The platform I am using is loading a minimal logging at start up. Before changing the context the advanced logging was loaded right afterwards and everything was fine. For some reason the listener of the web.xml (Spring initialization, etc.) is now running before the advanced logging is loaded. These classes are using the apache commons logging api and get loggers assigned basing on the simple root logger. Right afterwards the root logger is replace by the platform but the commons loggers are not updated with the new configuration.
New question:
As I stated below, changing anything in the platform is no option. So why did the listener run earlier when I change the context and how can I prevent this.
For the sake of the moment Apache Tomcat uses JDK logging. If you didn't place commons-logging.properties file to your source dir the default logger using commons logging will be log4j. Anyway the Tomcat will not use that logging because it needs a special configuration to tell it to use log4j.
The root logger is what you use in the log4j configuration. For example
log4j.rootLogger=ERROR,Console
Changing context path is nothing related to the logging used by application.
I didn't see any issue with logging rather that in recent releases regarding implementation priority.
The logging creates a dependency between multiple tomcat web application and due this fact requires a specific order of loading this modules. Renaming the context to "/shop" leads to an other order as StandardContext.filterDefs is a simple HashMap and does not preserve the order of the server.xml.
I could fix my issues in running the required steps in a listener.
web.xml
<listener>
<listener-class>com.[...].InitListener</listener-class>
</listener>
InitListener.java
package com.[...];
public class InitListener
{
static
{
// init Log4J, etc.
}
}
{code}
(Btw. Listener order should be identical to the web.xml)

Resources