Logging in Jetty
last modified January 27, 2024
Logging is recording the activity of a program during its lifetime. Logging is used for problem diagnosis, auditing, debugging, or information gathering.
There are several logging frameworks available in Java. If we do not
specify a logging framework, Jetty defaults to its built-in
org.eclipse.jetty.util.log.StdErrLog
implementation.
Default logging
In this section we show how to configure Jetty's standard logging.
$ java -jar $JETTY_HOME/start.jar 2014-09-12 12:06:25.699:INFO::main: Logging initialized @496ms 2014-09-12 12:06:25.973:INFO:oejs.Server:main: jetty-9.2.2.v20140723 2014-09-12 12:06:26.006:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/home/janbodnar/prog/jetty/my-base/webapps/] at interval 1 ...
By default, Jetty prints messages to the console. The messages appear at the console where we started the server.
$ java -jar $JETTY_HOME/start.jar --add-to-start=logging INFO: logging initialised in ${jetty.base}/start.ini (appended) MKDIR: ${jetty.base}/logs
To start configuring the logging facility, we need to enable Jetty's logging module. The logs directory is created as well.
$ pwd /home/janbodnar/prog/jetty/my-base $ mkdir resources $ cat resources/jetty-logging.properties org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog org.eclipse.jetty.LEVEL=INFO jetty.logs=logs
Inside our Jetty base directory, we create the resources directory.
In the jetty-logging.properties
file we configure the
standard logging. The messages are directed to the logs
subdirectory.
$ java -jar $JETTY_HOME/start.jar 2014-09-12 17:05:41.535:INFO::main: Logging initialized @2575ms 2014-09-12 17:05:42.040:INFO::main: Redirecting stderr/stdout to /home/janbodnar/prog/jetty/my-base/logs/2014_09_12.stderrout.log
Starting Jetty, we learn that logging is redirected to the logs subdirectory.
$ ls -1 logs/ 2014_09_12.stderrout.log 2014_09_12.stderrout.log.105458616 2014_09_12.stderrout.log.150542014
The log files are created in the logs subdirectory.
Enabling log4j
Apache log4j
is a popular logging library. Jetty supporst log4j
via Jetty via the Slf4j
facade and the Slf4j
binding layer for log4j
.
The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction
for various logging frameworks, such as java.util.logging
,
logback
, and log4j
. It allows to plug in the desired logging
framework at deployment time.
$ cat resources/jetty-logging.properties org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
In the jetty-logging.properties
file, we choose the simple logging
facade for doing logging in Jetty.
$ mkdir -p lib/logging/ $ mv ~/Downloads/log4j-1.2.17.jar lib/logging/ $ mv ~/Downloads/slf4j-api-1.7.7.jar lib/logging/ $ mv ~/Downloads/slf4j-log4j12-1.7.7.jar lib/logging/
The lib/logging
directory is created. The necessary JAR files
are downloaded from a Maven repository and moved to the newly
created directory.
$ java -jar $JETTY_HOME/start.jar --list-modules ... Jetty Active Module Tree: ------------------------- + Module: jsp-impl [enabled] + Module: jstl-impl [enabled] + Module: logging [enabled] ...
Remember that the logging
module must be enabled for Jetty base.
package com.zetcode; import org.apache.log4j.Logger; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.annotation.WebServlet; @WebServlet(urlPatterns = "/mylogservlet") public class MyLoggingServlet extends HttpServlet { static Logger log = Logger.getLogger(MyLoggingServlet.class.getName()); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().println("MyLogginServlet called"); log.info("MyLoggingServlet called"); } }
We create a simple Java servlet in which we do some basic logging.
static Logger log = Logger.getLogger(MyLoggingServlet.class.getName());
The Logger
class is created.
log.info("MyLoggingServlet called");
A message having INFO level is written.
log4j.rootLogger=INFO, filer log4j.appender.filer=org.apache.log4j.FileAppender log4j.appender.filer.layout=org.apache.log4j.PatternLayout log4j.appender.filer.layout.ConversionPattern=[%d] %p %c - %m%n log4j.appender.filer.File=${jetty.base}/logs/jetty.log log4j.appender.filer.append=true
The log4j.properties
is a configuration file for log4j
.
We place it inside the resources directory. Inside the configuration
file, we choose logging into a file with a specific logging pattern.
The log messages will contain the date, the log level, and the
application message.
<?xml version="1.0" encoding="UTF-8"?> <project name="MyLoggingServlet" default="compile"> <property name="name" value="mls"/> <property environment="env"/> <property name="src.dir" value="src"/> <property name="web.dir" value="${src.dir}/web"/> <property name="build.dir" location="${web.dir}/WEB-INF/classes"/> <property name="jetty.lib.dir" location="${env.JETTY_HOME}/lib"/> <property name="log4j.lib.dir" location="${env.JETTY_BASE}/lib/logging"/> <property name="dist.dir" location="dist"/> <property name="deploy.path" location="${env.JETTY_BASE}/webapps"/> <path id="compile.classpath"> <fileset dir="${jetty.lib.dir}"/> <fileset dir="${log4j.lib.dir}"/> </path> <target name="init"> <mkdir dir="${build.dir}"/> <mkdir dir="${dist.dir}"/> </target> <target name="compile" depends="init"> <javac srcdir="${src.dir}" destdir="${build.dir}" includeantruntime="false"> <classpath refid="compile.classpath"/> </javac> <echo>Compilation completed</echo> </target> <target name="archive" depends="compile"> <war destfile="${dist.dir}/${name}.war" needxmlfile="false"> <fileset dir="${web.dir}"/> </war> <echo>Archive created</echo> </target> <target name="clean" depends="init"> <delete dir="${build.dir}"/> <delete dir="${dist.dir}"/> <echo>Cleaning completed</echo> </target> <target name="deploy" depends="archive"> <copy file="${dist.dir}/${name}.war" overwrite="true" todir="${deploy.path}"/> <echo>Archive deployed</echo> </target> </project>
This is the Ant build file for our example.
$ ant deploy $ curl localhost:8080/mls/mylogservlet MyLogginServlet called
The web archive containing our servlet is built and deployed. The servlet is called.
$ tail -2 logs/jetty.log [2014-09-16 15:11:25,254] INFO org.eclipse.jetty.server.Server - Started @2719ms [2014-09-16 15:11:42,214] INFO com.zetcode.MyLoggingServlet - MyLoggingServlet called
After building and running the example, we find out the logging message in the log file.
Request log
Requests are logged to provide useful statistics for website owners. Jetty has
NCSARequestLog
class to save incoming request logs. The class can
use the NCSA common and NCSA extended log formats. (NCSA HTTPd was an early web
server developed at National Center for Supercomputing Applications.)
These formats have items including client's IP address and user agent, time of
request, status code, and HTTP method. They are understood by most
web analysis software.
The example shows how to enable request logging in Jetty.
<!DOCTYPE html> <html> <body> Simple page. </body> </html>
Our application will display this simple web page.
<?xml version="1.0" encoding="UTF-8"?> <project name="RequestLog" default="archive"> <property name="name" value="relog"/> <property environment="env"/> <property name="src.dir" value="src"/> <property name="web.dir" value="${src.dir}/web"/> <property name="dist.dir" location="dist"/> <property name="deploy.path" location="${env.JETTY_BASE}/webapps"/> <target name="init"> <mkdir dir="${dist.dir}"/> </target> <target name="archive"> <war destfile="${dist.dir}/${name}.war" needxmlfile="false"> <fileset dir="${web.dir}"/> </war> <echo>Archive created</echo> </target> <target name="clean" depends="init"> <delete dir="${dist.dir}"/> <echo>Cleaning completed</echo> </target> <target name="deploy" depends="archive"> <copy file="${dist.dir}/${name}.war" overwrite="true" todir="${deploy.path}"/> <echo>Archive deployed</echo> </target> </project>
This is Ant build file for for the example code.
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/relog</Set> <Set name="war">/home/janbodnar/prog/jetty/logging2/dist/relog.war</Set> <Set name="handler"> <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"> <Set name="requestLog"> <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog"> <Set name="filename"><Property name="jetty.logs" default="./logs"/>/access-yyyy_mm_dd.request.log</Set> <Set name="filenameDateFormat">yyyy_MM_dd</Set> <Set name="LogTimeZone">CET</Set> <Set name="retainDays">90</Set> <Set name="append">true</Set> <Set name="logLatency">true</Set> </New> </Set> </New> </Set> </Configure>
This is XML configuration for our web application. The request log handler is enabled only for this web application. Each day a new log file is created. Log files are kept for 90 days before being deleted.
$ cp relog.xml $JETTY_BASE/webapps
The relog.xml
file is copied to the webapps directory of
the Jetty base. The file serves as the application deployer.
$ curl localhost:8080/relog/ <!DOCTYPE html> <html> <body> Simple page. </body> </html>
A request is made from a curl
client.
$ tail -1 logs/access-2014_09_13.request.log 127.0.0.1 - - [13/Sep/2014:13:29:11 +0200] "GET /relog/ HTTP/1.1" 200 60 "-" "curl/7.35.0" 18
This is a sample of a request logged in the access log file.
In this chapter of the Jetty tutorial, we have done some basic logging.
Author
List all Java tutorials.