We have Spring java-based web deployments which use log4j2.xml for logging messages to files, etc.
We now need to update our log4j2.xml configs in order to be able to do a ${web:contextPath} web lookup inside them so that we can use a deployment's context name as part of the log file's name which the loggers log messages to. However, when we deploy the apps, the log4j2 configurations fail to recognise any web lookup related stuff. The file created to log messages to is simply created with the name ${web and no messages are actually logged in them.
I have read various docs online related to log4j2 web lookups when running in 3.0 servlets but I still can't see what the problem might be in our configurations. And I don't know what to look for in the log4j's trace logs in order to see what it is that we are missing.
Our Stack:
Windows and Linux OSes
Java 8
Tomcat 7.0.5x
log4j-xxx 2.2 (log4j-api, log4j-core, log4j-slf4j-impl, log4j-jcl, log4j-web all in classpath)
Any help on how to get web lookups to work is much appreciated.
Cheers,
PM
If you have a Spring 4 java annotation based web application, it is possible to have log4j-slf4j-impl jar in the classpath and still do a log4j2 web lookup by having your web initialization class extend Log4jServletContainerInitializer and calling super.onStartup() on it.
Example:
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.apache.logging.log4j.web.Log4jServletContainerInitializer;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
public class WebInitialiser extends Log4jServletContainerInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext)
throws ServletException {
super.onStartup(null, servletContext);
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(ApplicationConfig.class, IntegrationConfig.class,
JmsConfig.class, JmxConfig.class);
servletContext.addListener(new ContextLoaderListener(rootContext));
}
}
Note however that you still seem to need to have your web.xml include a <display-name> node in order for log4j2 web lookups to work on a Tomcat 7.0.5x container.
For more detail on all this, see the answers that I got in the log4j user mailing list thread:
log4j2 web lookup questions
Cheers,
PM.
Related
The Restlet framework documentation touts it's ability to run stand-alone via it's Server class and using the jse library build or to run in a Servlet container like Tomcat using the jee library build.
The library helpfully produces two types of log records, code related log records for debugging and errors and access related log records that look like this:
20-Dec-2018 12:33:01.723 INFO [http-nio-8088-exec-52] org.restlet.engine.log.LogFilter.afterHandle 2018-12-20 12:33:01 0:0:0:0:0:0:0:1 - 0:0:0:0:0:0:0:1 8088 POST /WebApp/route - 204 0 647 11619 http://localhost:8088 PostmanRuntime/7.4.0 -
This is helpful in stand-alone mode with the -jse build where Engine#setLogLevel(...) exists. I find this Apache httpd like logging to be extra noise when using the -jse build inside of a Tomcat container where I already have a separate access log. Unfortunately Engine#setLogLevel doesn't exist in the JEE build.
Using the simple Apache Tomcat Restlet JEE example code, where is the ideal place to disable the Restlet access log?
After testing different things, using Logger.getLogger("org.restlet").setLevel(Level.WARNING) was the only thing that reliably suppressed the Restlet access log messages. I tried org.restlet.engine, org.restlet.engine.og, and org.resetlet.engine.log.LogFilter and various component access methods, none suppressed the message. I'm not sure if I'm not suppressing more than I really wanted. It seems that if Engine#setLevel isn't available in JEE, then access logging should be default suppressed in JEE.
package my.package.space;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.restlet.Application;
import org.restlet.Restlet; // from org.restlet.jee artifact version 2.3.12
import org.restlet.routing.Router;
public class MyJeeApplication extends Application {
/**
* Creates a root Restlet that will receive all incoming calls.
*/
#Override
public synchronized Restlet createInboundRoot() {
// Create a router Restlet that routes each call to a new instance of HelloWorldResource.
Router router = new Router(getContext());
// Set restlet log level to warning to suppress
// INFO org.restlet.engine.log.LogFilter.afterHandle access log messages
Logger.getLogger("org.restlet").setLevel(Level.WARNING);
// Defines only one route
//router.attach("/hello", HelloWorldResource.class);
router.attachDefault(HelloWorldResource.class);
return router;
}
}
We've generated a basic Spring Boot application to test some features.
I've prepared it to be deployed on an embedded server and on Java EE servers (Tomcat 7 and JBoss EAP 6.2) without applying any changes.
I've included server.context-parameters.* property on application.properties file.
If I deploy the application on an embedded server using java -jar or mvn spring-boot:run, it's working without problems. But, If I deploy the same application on Tomcat 7 or JBoss EAP 6.2, I'm not able to load the context-params correctly.
Which is the correct way to define context parameters on Spring Boot application deployed on Java EE container without use web.xml file?
You could see all debugging information related with this Spring Boot issue here
Finally, I found the following solution thanks to Stéphane Nicoll
server.context-parameters.* only works for embedded servers, so to configure context-parameters on Java EE server is necessary to include a #Bean of type ServletContextInitializer like the following:
#Bean
public ServletContextInitializer contextInitializer() {
return new ServletContextInitializer() {
#Override
public void onStartup(ServletContext servletContext)
throws ServletException {
servletContext.setInitParameter("dummy.type","on-context-parameters");
}
};
}
I haven't been working on real world web projects. At university we used both Servlets and Spring for Java web development. In both projects we were given web.xml files already configured and we were doing only minor changes in them. Now I need to build a web app from a scratch. I created new Servlet class in Eclipse and it didn't automatically create any web.xml. Then I googled, and I read from several resources that web.xml is not really needed, but that reasoning was put in couple of sentences, so I am not sure if using annotations instead of web.xml will be no problem. I will be really glad if there is no need to configure web.xml, because I haven't configured one by myself and I want to focus more on the business logic.
Thank you in advance!
You don't need a web.xml file if you have a container that supports the latest j2ee specs.
Here is a link to an simple servlet example that use an annotation and here you can find the same for Spring MVC; I post the example here for you convenience
public class MyWebApplicationInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet());
registration.setLoadOnStartup(1);
registration.addMapping("/example/*");
}
}
Here is another link that show how to use the other annotations available(#ServletFilter, #WebServletContextListener); you can download the specs form here in order to get a more detailed view of the annotations available via j2ee.
Starting in Servlet 3, no web.xml is required. You're going to want to use something like Tomcat 7 or 8 (better choice). For raw servlets this is a good starting point.
If you want to use modern Spring, Grails 3 is a great way to go. It side steps all of these issues and Grails is a very productive framework for web development. You can think of it as Ruby on Rails built on top of Spring and Hibernate.
At this point, you shouldn't have to write any web.xml to get set up unless you use a framework that needs it. I don't know about spring mvc, but Grails doesn't require you to do that and it uses most of what you're already used to using.
Another way (Spring 3.1+) -
An abstract base class implementation of WebApplicationInitializer named AbstractDispatcherServletInitializer makes it even easier to register the DispatcherServlet by simply overriding methods to specify the servlet mapping and the location of the DispatcherServlet configuration -
public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {
#Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
#Override
protected WebApplicationContext createServletApplicationContext() {
XmlWebApplicationContext cxt = new XmlWebApplicationContext();
cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
return cxt;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Whether or not you need web.xml is dependent on which servlet specification you claim in your application. If you will be building an app using spec 3.0, you can use annotations to declare your servlets, and deploy it to a container without needing a web.xml file. This was done as part of JSR-315.
Here I found an example of Web Application without using the deployment descriptor file(web.xml). The only point to consider here is this will work with the latest tomcat versions >=7.0
Visit http://java-demos.blogspot.com/2014/01/servlet-web-application-without-webxml.html
Visit https://www.baeldung.com/java-web-app-without-web-xml
Use Spring Boot, which will manage the container and all the boilerplate configuration for you. You can generate a ready-to-launch skeleton with Initializr.
No, there will be no need of web.xml for servlet based application if you are using servlet version >3.0 and tomcat 7 as it will not run in the previous versions of tomcat.
Annotation represents the metadata. If you use annotation, deployment descriptor (web.xml file) is not required. Have a look Here for all available annotation.
I'v mostly used XML based configuration for applicationContexts. I have a requirement where I need to use #configuration to create my beans using #Bean now.
Brief description of why ?
weblogic deploys a spring web-app "A". A makes calls to B(not spring,not web app-no WEB_INF). B just contains common service calls to external servers. Hence B.jar is bundled into A and A is then deployed on web-logic.
Now i need to use spring beans in B.)
So the options available at this point:
Bundle applicationContext.xml and all the property files into B.jar. (keep in mind it is a very complex build process with 20 property files and 100s of beans. So I also need to register propertymanager bean etc..). Then initialize appcontext in a static initializer block and look for appcontext within B.jar.
Use #configuration to register an Appconfig.class instead of an XML. (no changes to build process here).
With this option i need to use a clientInterceptor. Could you provide me with the #Bean definition of this.
How do I configure clientInterceptor in #appconfig.class.
*please let me know if there any other options.
Spring-ws-core - 2.1.4.release
spring-core-3.2.4
expression,context,beans - 3.0.5
spring-oxm-1.0.3
weblogic - 12c
jdk - 1.7
This is my first post here. Any suggestions would be welcome and appreciated. Apologize for any forum faux paus.
I'm using Tomcat to serve my Java Servlets and it's kinda more for me. I just need to serve, Servlet Requests alone, no static content, neither JSP, etc. So I was looking for a Servlet container that can be embedded in my Application. I felt it if stripped Jetty and use it as a Servlet Container alone, it can be more scalable and occupying small memory footprint, [I don't need Jetty's 'Web Server' and other Parts]. So I've a few questions though,
How do I embed Jetty in my Application Code to serve Servlet Requests alone?
If I embed Jetty code in my Application Code, will I be able to easily upgrade Jetty Versions?
I got the Jetty code here, if I have to embed Jetty's Servlet Container in my App, which one should I use from the source,
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/snapshot/jetty-9.0.3.v20130506.tar.bz2 ,
jetty-9.0.3.v20130506/jetty-servlet or jetty-9.0.3.v20130506/jetty-servlets
I intend to serve API Requests with my Applications and I'm looking for Performance and Scalability as main constraints. And of course Servlet 3.0 support.
What you are looking for is running Jetty in an embedded scenario.
There's plenty of examples available showing how to tie together the various pieces you need to accomplish your goals.
Check out the embedded examples in the jetty source tree.
For the record, jetty standalone is really just jetty embedded with a few startup and classpath related bootstraps. It is the same code, and assembled in basically the same way.
Since you stated you want Servlet 3.0, have no interest in JSP, this is rather easy to setup. (JSP is trickier to setup, but possible).
For servlet 3.0 specific embedding, there's a complete example project hosted at github.
https://github.com/jetty-project/embedded-servlet-3.0
In short, you'll have the following initialization code.
package com.company.foo;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.TagLibConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
public class EmbedMe {
public static void main(String[] args) throws Exception {
int port = 8080;
Server server = new Server(port);
String wardir = "target/sample-webapp-1-SNAPSHOT";
WebAppContext context = new WebAppContext();
// This can be your own project's jar file, but the contents should
// conform to the WAR layout.
context.setResourceBase(wardir);
// A WEB-INF/web.xml is required for Servlet 3.0
context.setDescriptor(wardir + "WEB-INF/web.xml");
// Initialize the various configurations required to auto-wire up
// the Servlet 3.0 annotations, descriptors, and fragments
context.setConfigurations(new Configuration[] {
new AnnotationConfiguration(),
new WebXmlConfiguration(),
new WebInfConfiguration(),
new TagLibConfiguration(),
new PlusConfiguration(),
new MetaInfConfiguration(),
new FragmentConfiguration(),
new EnvConfiguration() });
// Specify the context path that you want this webapp to show up as
context.setContextPath("/");
// Tell the classloader to use the "server" classpath over the
// webapp classpath. (this is so that jars and libs in your
// server classpath are used, requiring no WEB-INF/lib
// directory to exist)
context.setParentLoaderPriority(true);
// Add this webapp to the server
server.setHandler(context);
// Start the server thread
server.start();
// Wait for the server thread to stop (optional)
server.join();
}
}