Java servlet Log4j
last modified July 13, 2020
Java servlet Log4j tutorial shows how to do logging with Log4j in Java servlets. This tutorial covers Log4j version 2.
Java Servlet
Servlet is a Java class which responds to a particular type of network request - most commonly an HTTP request. Java servlets are used to create web applications. They run in servlet containers such as Tomcat or Jetty. Modern-day Java web development uses frameworks that are built on top of servlets.
Log4j
Apache Log4j is a Java-based logging utility. It is a project of the Apache Software Foundation. Log4j can be configured through Java code or in a configuration file. Configuration files can be written in XML, JSON, YAML, or properties file format.
Log4j has three main components: loggers, appenders, and layouts. Loggers are named destinations that capture capture log messages and send them to appenders. Appenders deliver log messages to their destinations, such as files or consoles. Layouts are used to define the formatting of log messages.
Java servlet logging example
The following web application is doing logging with Log4j. In Servlet 3.0+ applications, Log4j works out of the box. It automatically starts when the application deploys and shuts down when the application undeploys.
$ tree . ├── pom.xml └── src └── main ├── java │ └── com │ └── zetcode │ ├── service │ │ └── MyService.java │ └── web │ └── MyServlet.java ├── resources │ └── log4j2.xml └── webapp ├── index.html ├── META-INF │ └── context.xml └── WEB-INF
This is the project structure. The Log4j configuration file is
placed in the src/main/resources/
directory.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zetcode</groupId> <artifactId>JavaServletLog4j</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>JavaServletLog4j</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>2.8.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project>
This is the Maven POM file. We have two artifacts: javax.servlet-api
for servlets and log4j-web
for logging with Log4j in web applications.
The maven-war-plugin
is responsible for collecting all artifact dependencies,
classes and resources of the web application and packaging them into a web application archive (WAR).
<?xml version="1.0" encoding="UTF-8"?> <Context path="/JavaServletLog4j"/>
In the Tomcat context.xml
file, we define the context path. It
is the name of the web application.
<?xml version="1.0" encoding="utf-8"?> <Configuration status="info"> <Properties> <Property name="logdir">/home/janbodnar/tmp</Property> <Property name="layout">%d [%t] %-5p %c- %m%n</Property> </Properties> <Appenders> <RollingFile name="LOCALHOST" fileName="${logdir}/localhost.log" filePattern="${logdir}/localhost.%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="${layout}"/> <Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy size="1 MB" /> </Policies> <DefaultRolloverStrategy max="10" /> </RollingFile> </Appenders> <Loggers> <Logger name="com.zetcode" level="info" additivity="false"> <AppenderRef ref="LOCALHOST" /> </Logger> <Root level="error"> </Root> </Loggers> </Configuration>
Log4j is configured in the log4j2.xml
. In our example, we have chosen
the XML file format.
<Properties> <Property name="logdir">/home/janbodnar/tmp</Property> <Property name="layout">%d [%t] %-5p %c - %m%n</Property> </Properties>
In the Properties
tag, we set the logging directory and layout.
The layouts define the format of the log.
The pattern layout consists of conversion
specifiers. Each specifier starts with a percent sign and is followed by optional format
modifier and mandatory conversion character. The %d
outputs the date of the logging event.
The %t
outputs the name of the thread that generated the logging event.
The %-5p
outputs the level of the logging event, where the level name has
minimum of five characters and the characters are left justified. The %c
outputs the name of the
logger that published the logging event. The %m
prints the application message associated
with the logging event and the %n
is the platform dependent line separator character
or characters.
<Appenders> ... </Appenders>
Appenders are objects which define where logging messages are saved. There are several possible destinations including consoles, files, database tables, or sockects.
<RollingFile name="LOCALHOST" fileName="${logdir}/localhost.log" filePattern="${logdir}/localhost.%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="${layout}" /> ... <DefaultRolloverStrategy max="10" /> </RollingFile>
We set the location of the log file. We use a rolling file appender,
which automatically rolls or archives the current log file and resumes logging in
a new file. The PatternLayout
sets the layout of the log messages.
The DefaultRolloverStrategy
deletes older archives if the number of
archives reaches ten.
<Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy size="1 MB" /> </Policies>
The triggering policies are defined in the Policies
tag.
They control the conditions under which rollovers occur. Here we use two
policies: TimeBasedTriggeringPolicy
and SizeBasedTriggeringPolicy
.
The TimeBasedTriggeringPolicy
starts a rollover according to the most
specific date and time pattern; in our case, every hour. The SizeBasedTriggeringPolicy
starts a rollover if the size of the log file reaches 1 MB.
<Loggers> <Logger name="com.zetcode" level="info" additivity="false"> <AppenderRef ref="LOCALHOST" /> </Logger> <Root level="error"> </Root> </Loggers>
In the Loggers
tag we define loggers. They are named log message destinations.
Each logger can have different level of logging configured. We define a logger with info
logging level. We append the rolling file appender that we have previously defined to this
logger. With additivity
set to false, the log messages are not propagated
to their ancestors.
package com.zetcode.web; import com.zetcode.service.MyService; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet"}) public class MyServlet extends HttpServlet { final static Logger logger = LogManager.getLogger(MyService.class); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { logger.info("MyServlet's doGet() called"); MyService service = new MyService(); service.doWork(); response.setContentType("text/plain;charset=UTF-8"); PrintWriter out = response.getWriter(); out.print("MyServlet called"); } }
This is the MyServlet
servlet. It calls a service method and sends text data
back to the client.
final static Logger logger = LogManager.getLogger(MyService.class);
We get the logger from the LogManager
.
logger.info("MyServlet's doGet() called");
We log an information level message.
MyService service = new MyService(); service.doWork();
We call a dummy service method.
PrintWriter out = response.getWriter(); out.print("MyServlet called");
We send text data to the client.
package com.zetcode.service; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class MyService { final static Logger logger = LogManager.getLogger(MyService.class); public void doWork() { logger.info("MyService's doWork() called"); } }
The MyService's
doWork
method logs an information level
message.
<!DOCTYPE html> <html> <head> <title>Home Page</title> <meta charset="UTF-8"> </head> <body> <a href="MyServlet">Call Servlet</a> </body> </html>
The home page contains a link which calls MyServlet
.
$ cat localhost.log 2017-11-14 16:50:30,157 [http-nio-8084-exec-5] INFO com.zetcode.service.MyService- MyServlet's doGet() called 2017-11-14 16:50:31,044 [http-nio-8084-exec-5] INFO com.zetcode.service.MyService- MyService's doWork() called
This is a sample output of logged messages.
In this tutorial, we have done some logging with Log4j in a Java web application.