Never worked with log4j before, that's why I may ask some stupid questions.
I got a multi-module Maven Web Application that runs on Glassfish 3.1.
Every module is more or less independent.
Well, I set up the log4j configurations (log4j.properties), put it in the Dist "module" config folder. Also, every pom.xml of every module has a log4j dependency. Added the classpaths. Also, added in the domain.xml the jvm option, referencing the log4j.property:
<jvm-options>-Dlog4j.configuration=file:///${com.sun.aas.instanceRoot}/log4j.properties</jvm-options>
In the Glassfish Admin panel, i added Configuration option referencing to the log4j.properties file (Configuration -> severf-config -> JVM General Settings -> JVM Options).
-Dlog4j.configuration=file:///${com.sun.aas.instanceRoot}/log4j.properties
I found This stuff out reading a lot on the Internet about log4j.
So, now my problem is that when I start the Maven Build, the build executes the Unit Test, and the framework works just fine, ut it doesn't log any activity from the application. What could it be?
Does every module needs its own log4j.property (I guess not, because it's logging already entries from methods called from the unit test from modules that don't have the log4j.propertie).
Is it possible that the log4j has to bi initialized before/during the start of the application?
Again, it logs unit test and maven build, but not during runtime, that's what I don't get. Am I missing something?
The solution was to put the log4j.properties file into the persist Maven module (src/main/resources).
Now, it logs the activities..
Related
I am trying to do a log4j migration for a legacy application. I made the changes to the configuration files and tested it locally with Tomcat, where the logs were displayed correctly. However when I deploy on WAS, the logging stops.
I checked a lot of pages about the necessary dependencies and the possible problems, but now I feel I'm stuck. Here is what I already tried:
Added the log4j jars manually to the lib/ext directory in WAS (together with commons-logging, I read an article where it helped, although all these jar-s were already present in the ear)
Double checked, that the configuration file is on the classpath and that it's syntax is correct
Added logj42-web dependency
Added the necessary filters in web.xml (Spring version is 3.8, so also the config listener with the config name context-param)
Checked classloader in WAS - it's parent first
Am I missing something?
Any ideas are appreciated. Thank you in advance!
WAS includes its own commons-logging API (that does not utilize Log4j), so bringing your own logger requires a bit of extra class-loader-related config. Typically, that would go something like this:
Put your commons-logging and log4j jars, along with your logging properties files, in some directory (not WAS_HOME/lib/ext) readable by the user running the server.
Create a shared library on the server, with that directory as its class path, and select the "use an isolated class loader" option. Associate that shared library with your application or web module.
Ideally, that should be it. Isolated shared libraries search themselves before delegating to the server's loaders, so your application will "see" the commons-logging/log4j classes in the shared library instead of in the server, and likewise, it should pick up the configuration files from that directory instead of the ones found in the server.
You can also accomplish this same basic thing by leaving all the logging stuff in your WAR or EAR and setting its class loader to parent-last (which causes the class loader to search locally before delegating to the server-level loaders), but that is a bit riskier configuration - if your application includes APIs that are also provided by the server, parent-last class loading increases the possibility of ClassCastExceptions or LinkageErrors.
The project artifact structure is:
test.ear
--lib - has all log4j2 jars core, web, bridge and JCL
--META-INF -- has app.xml, JBoss specific deployment XML, and manifest file
--a.war -- each war has web.xml with log4jConfiguration and Log4jServletContextListener specified.
--b.war
--c.war
The war creates context with log4jConfiguration, which is "classpath:test.xml". I can see each war creating the context with log4jContextName I have provided in web.xml.I have a few crons, too, which run based on configured time intervals. When crons run, and many of the JMS process run, I observed the log files are not populated with logs(From project-specific classes). While going through the log4j2 code, I understood that log4j2 creates a context for each classloader. And in my case, it creates a context for "test.ear", which is defaulted to error(DefaultContext) as it is not able to find a default log4j2.xml since I have a custom named(test.xml) on in the classpath. The Log4jServletContextListener does not catch the "test.ear" event.
How to inject my "classpath:test.xml" while log4j2 creates a context for the ear file? Since my project can be both deployed to WebSphere and JBoss, I am looking forward to suggestions that are not server-specific. Or is there a way to create a single context for all the war and ear somehow? I have different apps outside this ear in same server so I cannot give an environmental config of -Dlog4j.configurationFile as other apps have there own log4j2 xml's.
One approach that I can think of is to place your log4j config file test.xml in a shared library and configure your application to use the shared library.
The following link describes how to configure a shared library for a server or an enterprise application on WebSphere.
https://www.ibm.com/support/pages/how-create-shared-library-and-associate-it-application-server-or-enterprise-application-websphere-application-server
The shared library should be a generic function for modern Java app servers, so JBoss should also be able to configure this.
This is a strange problem. I have an existing JEE project that is and has been in production on WebSphere 7. It is a multi-module EAR file. It has 2 WARs and 1 shared Java project. Most of it is Spring 4 based, but we have some web services we host using axis2 (1.5.4). This project does not use Maven. It does use a WebSphere deployment.xml (in the EAR) with the warClassloaderPolicy="SINGLE" and the classloader mode="PARENT_LAST". This controls the classloader policies for this EAR. All the jar files that the Java project and the WARs rely on are stored at the EAR level and referenced at the module level via the manifest files. That all works fine and has for several years.
Now I was trying to convert this project to a Maven project after all these years. Initially, I left the deployment.xml file settings as they always have been. But with these settings I was getting:
java.lang.VerifyError at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl "org.springframework.oxm.jaxb.Jaxb2Marshaller".
After much googling on this site and all around and trying 50,000 things, I tried one thing, which worked for most of the app. I switched the classloader mode to "PARENT_FIRST" and all of a sudden the WAR that exclusively uses Spring 4 worked. It started up without error and I was able to run it.
But, the other WAR which hosts the axis2 web services started getting the error:
org.apache.axis2.deployment.WarBasedAxisConfigurator <init> org.apache.commons.fileupload.FileUploadException....Caused by: java.lang.NoClassDefFoundError: org.apache.commons.fileupload.FileUploadException....Caused by: java.lang.ClassNotFoundException: org.apache.commons.fileupload.FileUploadException
This class (org.apache.commons.fileupload.FileUploadException) is in both the compile and runtime classpath. In eclipse I can see it in the "Maven Dependencies" library that the m2e eclipse plugin creates from the POM files. I can also see this jar in the WebSphere runtime module classpath inspector (it shows up in there 3 times! Once under each WAR and once just in a list from the Maven repository location.)
One thing of note is that I've configured the project with a parent POM, where most of the dependencies are declared at the parent and then are inherited for each of the modules. In the EAR project, the POM is using the maven-ear-plugin with skinnyWars=true. However, it appears the skinnyWars directive is not respected when the m2e eclipse plugin deploys the EAR into the local WebSphere server (that is evident because I see these jars showing up in the classpath 3 times). But when I create an EAR using the Maven build, the EAR comes out correctly with each jar only showing up in the EAR one time.
This is my last hope to post something here and see if someone has an idea for something to try, otherwise I can't think of anything else to try.
Thanks...
Is there a particular reason you need to run with a single class loader for all the WAR modules, other than convenience? If not, you could rework the application in order to allow you to run PARENT_FIRST in the Spring WAR and PARENT_LAST in the Axis2 WAR.
If that's not an option for some reason, the path of least resistance might be to go back to PARENT_LAST and remove some libraries from the app or module. The VerifyError generally occurs if you're running with PARENT_LAST and have a library in the app that is also present in the server - in this case, the exception looks like it's coming out of JAXB, so you might want to see if simply removing JAXB (and perhaps JAXP, if present, since it's heavily used by JAXB) from the application resolves the issue with your default setup.
You could also stick with PARENT_FIRST and move the Axis2 jars to an shared library with an isolated class loader, associated with the app. An isolated shared library would make just the stuff in the shared library PARENT_LAST, so you can avoid the VerifyError and still get PARENT_LAST for Axis2. The issue in the PARENT_FIRST case appears to be because you're picking up WebSphere's copy of Axis2 but somehow have a dependency inserted from your app's copy - the failing class load is occurring in a server-level loader, so it doesn't see the copy in your app.
I have a multi-module maven project with one root and multiple child projects. I am planning to use SL4J for logging. However, I have to place the log4j.properties in all child projects to be able to configure log4j.
To be able to reuse a single properties file, I tried keeping the file in src\main\resources directory of the root. However, sl4j complains that it cannot find the properties file unless it exists in each individual project.
Is it possible what I am trying to do? If so, how do I do that?
The 'distributable' is responsible for the final log4j.properties, not every dependency is has. However, tests will probably complain about the absence of this file, so put a version of log4j.properties under src/test/resources.
I'm working on a project that uses two maven projects (named core and webapp); core is built with JAR packaging and used for two different purposes: as a stand-alone app (essentially an executable JAR), and also embedded into webapp.
For its purpose as a stand-alone app, core needs to have its own logback configuration (a logback.xml file) that needs to be included on the classpath. Normal Maven convention would have me put it in src/main/resources/logback.xml. That works fine, but causes a problem when the core JAR is included in webapp. webapp needs to have its own logback configuration, but the container (tc Server or Jetty) is picking up the one from core.jar first.
I realize that logback can be told about a custom config location via a system property (-D on the command line) but that's not viable in a app container like Tomcat or Jetty.
I've read some other people asking about this situation, but none of the solutions I've seen sits well with me. One solution involved setting up a context listener that runs early in the webapp initialization and explicitly configures logback based on a <context-param>. That's a bit brutish in my opinion, and probably a hard sell to my fellow dev team when log4j "just works" in this situation.
I'm far from a Maven expert, so I'm hoping there is some elegant way to get Maven to help me here. Or perhaps some logback extension or add-on that makes it more web-app friendly. Or even a clever idea that I haven't thought of.
There are a number of possible solutions, but the easiest is to put the file in its own module and mark the dependency as provided. The, conspire to have it on the classpath when running the standalone version of the app.
The solution that we ended up using was to leave only the common "non-app" pieces (code and configuration) in core and then extract the other "app" pieces into a new module (batch-app).
The logging configuration only lives in the 2 app projects (webapp and batch-app) that depend on core. core has a logback-test.xml configuration in it, but that's excluded from the JAR that maven builds (since it's in the src/test/resources folder).