Separate Log4j 2 instances for each web apps in Tomcat 9 - java

I am using Log4j 2 as logging framework in my application and running it on Tomcat 9.0.54. Now, if I deploy 2 instances of same application, it creates Log4j instance for first and all logs goes to the first application's log files.
For example, Tomcat/webapps has 2 folders i.e.
APP1
APP2
Both have logs folder under it, but logs are being created only in APP1/logs and logs for both applications are being updated there.
I tried configuring it from Java.
System.setProperty("log4j.configurationFile", Class.forName("com.example.MyAppListener").getResource("/log4j2.xml").toString());
LoggerContext context = (LoggerContext) LogManager.getContext(false);
if(!context.isInitialized()) {
context.initialize();
}else {
context.reconfigure();
}
I tried debugging Log4j 2 source, it appears to be that when context being initialized, it takes same configuration location for both applications. It seems like ClassLoader is loading single context object at Tomcat server level.
And web.xml as well
<context-param>
<param-name>log4jConfiguration</param-name>
<param-value>/WEB-INF/log4j2.xml</param-value>
</context-param>
The behavior is the same in both
Also, Log4j 2 jars are separately deployed in WEB-INF/lib folder for each application.

Actually, the problem was the configLocation. When I tried to get the context, configLocation property was set null and log4j loaded the same configuration object when initializing the context which was used for the first application logger's context and its configuration property has configLocation of the first application. I modified my code to explicitly provide configLocation to the context object and it worked.
URL configLocation = Class.forName("com.example.MyAppListener").getResource("/log4j2.xml");
LoggerContext context = (LoggerContext) LogManager.getContext(false);
context.setConfigLocation(configLocation.toURI());
if(!context.isInitialized()) {
context.initialize();
}else {
context.reconfigure();
}

Related

Get values of individual context.xml in Jersey's ResourceConfig?

I have a pretty simple servlet setup with
Jersey
no web.xml
Tomcat 9
Maven for creating the .war and handling dependencies
Now I need to deploy a test and a production version of the servlet on the server and I a trying to use the individual context.xml file for each environment. A quote from the docs
Individual Context elements may be explicitly defined:
In individual files (with a ".xml" extension) in the $CATALINA_BASE/conf/[enginename]/[hostname]/ directory. The context path and version will be derived from the base name of the file (the file name less the .xml extension). This file will always take precedence over any context.xml file packaged in the web application's META-INF directory.
All this also sounds easy here:
To give an example: if we wanted to deploy three installations of an application for test, stage and production, we would create three context.xml files:
tomcat/conf/catalina/localhost/test.xml
tomcat/conf/catalina/localhost/stage.xmltomcat/conf/catalina/localhost/prod.xml
And then deploy the same .war file three times as:
tomcat/webapps/test.war
tomcat/webapps/stage.war
tomcat/webapps/prod.war
And each installation would pick up its specific configuration automatically.
You can also read this documentation:
For Tomcat 5.0.x and later, WTP 2.0.x and later offers the opportunity to write the contexts to separate XML files in the proper folder (typically conf/Catalina/localhost) according to the requirements of that particular version. This behavior is enabled by checking the Publish module contexts to separate XML files option in the Server Options section of the Tomcat server editor. Note that only contexts for added projects will be written to separate XML files. Manually added contexts in server.xml will remain there.
There are several instructions, how to retrieve a value from the context.xml. For example:
<Environment name="companyName" value="My Company, Incorporated" type="java.lang.String" />
Can be used by
InitialContext context = new InitialContext();
Context xmlNode = (Context) context.lookup("java:comp/env");
String companyName = (String) xmlNode.lookup("companyName");
But this was listed for a Spring setup, how can this be done in a Jersey ResourceConfig based application/servlet?
For example:
#ApplicationPath("/")
public class MyMain extends ResourceConfig {
private final Logger logger = LoggerFactory.getLogger(MyMain.class);
public MyMain() {
try {
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
String myEnv = (String) envCtx.lookup("my-env");
this.logger.debug("Env: {}", myEnv);
} ...
is running into NamedExceptions: javax.naming.NameNotFoundException: Name [my-env] is not bound in this Context. Unable to find [my-env].
Is there any way to get the context configuration with Jersey, or do I need to use a different approach?
I also have no clue, how to debug the InitialContext. So the file is there and it is read by Tomcat, but I don't know how I can access it in the application. Do I need to use ServletContext.getInitParameter() instead - and how?
Update
My Eclipse setup seems to be the problem, because the published xml file is not the original, individual context.xml in my /Catalina/localhost folder. Is there any way to make sure that the original file is published in the Eclipse-Tomcat server?
"Publish module contexts to separate XML files" is checked. What is Update context paths? in publishing options (no effect visible, though)?
Here is the :

websphere liberty - Not able to generate application specific logging using slf4j or log4j

How can I generate Application specific logs in IBM Websphare Liberty server, I am using SLF4j, the message.log and console.log is updating fine but the application specific logs are not getting generated.
If the logging issue can be resolved using Log4j, then also will work for me.
Tried loading log4j2 file explicitly in static block and also placed in resource folder, both didnt worked.
able to see liberty server log but application logs are not generating at all.
The root cause of not seeing log4j logs is usually because the log4j2 configuration file is not being picked up by the classloader. You have a few options here to solve your problem.
Copy to Liberty shared-library directory. It can be one of the following:
${shared.config.dir}/lib/global
${server.config.dir}/lib/global
You can refer to IBM websites to find out the exact location of ${shared.config.dir} and ${server.config.dir} in your Liberty installation
at here
Alternatively, you can place the log4j configuration file anywhere on your file system and add the following lines to your server.xml
<library id="log4jConfig">
<folder dir="/{directory containning log4j config file}" scanInterval="5s" />
</library>
<webApplication id="myapp" location="myapp.war" name="My App"/>
<classloader commonLibraryRef="log4jConfig"/>
</webApplication>
Set as a JVM argument inside the jvm.options file
-Dlog4j.configurationFile=file:/path/to/log4j2.xml
Package it inside your maven application war file under src/main/resources
Blow fix worked for me, from the application class or entry point use below code to reload the slf4j configuration.
private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(theClassfromwheregeneratinglogs.class);
static {
try {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(context);
// Call context.reset() to clear any previous configuration, e.g. default
// configuration. For multi-step configuration, omit calling context.reset().
context.reset();
configurator.doConfigure("/appserver/wlpusr/servers/applogs/logback.xml"); //This will reload the slf4j configuration from the given file location.
} catch (JoranException je) {
// StatusPrinter will handle this
}}

how spring mvc application scan configuration files under classpath

Here i have a bean initialized InitializingBean in Spring MVC application. In order to register in spring-servlet application context, i two lines of code below:
#Autowired
private ApplicationContext context;
#Override
public void afterPropertiesSet() throws Exception {
if (context.getParent() != null) { // debug mode and add a breakpoint here, four times came here while application start up
}
}
Obviously, if four root application context initialized, some where error. but i really don't know why?
Here i make some assumption:
contextConfigLocation in web.xml file is classpath*:, and tomcat may detect multiple applicationContext.xml files under classpath jar files.(but spring xml files are really not locate in such jar files)
there are some configuration class in jar files and who make spring mvc application scan the same jar file twice or more(but i did not find such class)
Maybe i'm totally error, hope someone can give me some hint and thanks.
when starting your tomcat,the tags in your web.xml ,specificly,your codes will detect the configuration you wrote,initilized the spring container,such as,Application-Context.xml,if there is any tag in this file , the Spring will add the file you write, for example, you write "Application-context-data.xml" in your tag,the Spring container will initilized it !

Does depedent project in java take log4j config of parent project?

I am having project A and project B, A has jar dependency of project B. I have defined log4j.xml in project A but I am not able to see logs of sub-project(B.jar) in file appender as well as tomcat server console. Does project B will take log4j.xml form parent project A or not then which config does it use?
There is one log4j config for your entire JVM (unless you're working in a containerized environment using class loaders and.... that's not what's described).
Missing log messages implies that the configuration from log4j either (a) isn't what you think it is (i.e. a different log4j.xml is being used) or (b) doesn't have the right settings for the missing log lines.
Adding the following to the JVM at startup may help:
-Dlog4j.debug
It may also be possible to browse the log4j settings via MBeans in jconsole.
If you want all apps (WAR files) in a Tomcat instance to have the same logging configs, the simple solution is to arrange that all WAR files have a copy of the same config file.
If you want the apps to share a common logging framework (with a single configuration), then you should consider using Context Selectors, as described in the Log4j 2 documentation.
Using Context Selectors
There are a few patterns for achieving the desired state of logging separation using ContextSelectors:
Place the logging jars in the container's classpath and set the system property log4j2.contextSelector to org.apache.logging.log4j.core.selector.BasicContextSelector. This will create a single LoggerContext using a single configuration that will be shared across all applications.
Place the logging jars in the container's classpath and use the default ClassLoaderContextSelector. Follow the instructions to initialize Log4j 2 in a web application. Each application can be configured to share the same configuration used at the container or can be individually configured. If status logging is set to debug in the configuration there will be output from when logging is initialized in the container and then again in each web application.
Follow the instructions to initialize Log4j 2 in a web application and set the system property or servlet context parameter log4j2.contextSelector to org.apache.logging.log4j.core.selector.JndiContextSelector. This will cause the container to use JNDI to locate each web application's LoggerContext. Be sure to set the isLog4jContextSelectorNamed context parameter to true and also set the log4jContextName and log4jConfiguration context parameters.
The exact method for setting system properties depends on the container. For Tomcat, edit $CATALINA_HOME/conf/catalina.properties. Consult the documentation for other web containers.
I don't think there is a direct equivalent in Log4j 1.x.

How to enable directory listing in Spring 4 with Tomcat?

I know there is are global Tomcat settings, but is there an approach to define directory listing on application (context) level? I'd like to list static content from the directory, e.g. "webapp/images".
I do not have web.xml. The configuration is done in WebAppIntializer which extends AbstractAnnotationConfigDispatcherServletInitializer and everything is by default.

Categories