ZetCode

Jetty 中的日志记录

最后修改于 2024 年 1 月 27 日

日志记录 是在程序生命周期中记录程序的活动。日志记录用于问题诊断、审计、调试或信息收集。

Java 中有几种日志框架可用。如果我们不指定日志框架,Jetty 会默认使用其内置的 org.eclipse.jetty.util.log.StdErrLog 实现。

默认日志记录

在本节中,我们将展示如何配置 Jetty 的标准日志记录。

$ 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
...

默认情况下,Jetty 会将消息打印到控制台。消息会出现在我们启动服务器的控制台上。

$ java -jar $JETTY_HOME/start.jar --add-to-start=logging
INFO: logging         initialised in ${jetty.base}/start.ini (appended)
MKDIR: ${jetty.base}/logs

要开始配置日志记录功能,我们需要启用 Jetty 的日志记录模块。日志目录也会被创建。

$ 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

在我们的 Jetty 基本目录中,我们创建 resources 目录。在 jetty-logging.properties 文件中,我们配置标准日志记录。消息会被定向到 logs 子目录。

$ 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

启动 Jetty 后,我们会发现日志记录被重定向到了 logs 子目录。

$ ls -1 logs/
2014_09_12.stderrout.log
2014_09_12.stderrout.log.105458616
2014_09_12.stderrout.log.150542014

日志文件被创建在 logs 子目录中。

启用 log4j

Apache log4j 是一个流行的日志库。Jetty 通过 Slf4j 门面和 Slf4jlog4j 的绑定层支持 log4j。

Java 的简单日志门面 (SLF4J) 作为各种日志框架(如 java.util.logginglogbacklog4j)的简单门面或抽象。它允许在部署时插入所需的日志框架。

$ cat resources/jetty-logging.properties 
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog

jetty-logging.properties 文件中,我们选择简单日志门面来在 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/

lib/logging 目录被创建。必要的 JAR 文件从 Maven 仓库下载并移动到新创建的目录。

$ java -jar $JETTY_HOME/start.jar --list-modules
...
Jetty Active Module Tree:
-------------------------
 + Module: jsp-impl [enabled]
 + Module: jstl-impl [enabled]
 + Module: logging [enabled]
...

请记住,必须为 Jetty 基本目录启用 logging 模块。

MyLoggingServlet.java
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");
    }
}

我们创建一个简单的 Java servlet,并在其中进行一些基本的日志记录。

static Logger log = Logger.getLogger(MyLoggingServlet.class.getName());

创建了 Logger 类。

log.info("MyLoggingServlet called");

写入一条 INFO 级别的消息。

log4j.properties
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

log4j.propertieslog4j 的配置文件。我们将其放在 resources 目录中。在配置文件中,我们选择将日志记录到具有特定日志模式的文件中。日志消息将包含日期、日志级别和应用程序消息。

build.xml
<?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>

这是我们示例的 Ant 构建文件。

$ ant deploy
$ curl localhost:8080/mls/mylogservlet
MyLogginServlet called

构建并部署包含我们的 servlet 的 Web 存档。调用该 servlet。

$ 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

构建并运行示例后,我们在日志文件中找到了日志消息。

请求日志

记录请求是为了提供有用的网站所有者统计信息。Jetty 有 NCSARequestLog 类来保存传入的请求日志。该类可以使用 NCSA 通用和 NCSA 扩展日志格式。(NCSA HTTPd 是国家超级计算应用中心开发的早期 Web 服务器。)这些格式包含客户端的 IP 地址和用户代理、请求时间、状态码和 HTTP 方法等项目。它们被大多数 Web 分析软件理解。

该示例演示了如何在 Jetty 中启用请求日志记录。

index.html
<!DOCTYPE html>
<html>
<body>

Simple page.

</body>
</html>

我们的应用程序将显示这个简单的网页。

build.xml
<?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>

这是示例代码的 Ant 构建文件。

relog.xml
<?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>

这是我们 Web 应用程序的 XML 配置。请求日志处理器仅为该 Web 应用程序启用。每天都会创建一个新的日志文件。日志文件保留 90 天后会被删除。

$ cp relog.xml $JETTY_BASE/webapps

relog.xml 文件被复制到 Jetty 基本目录的 webapps 目录中。该文件用作应用程序部署程序。

$ curl localhost:8080/relog/
<!DOCTYPE html>
<html>
<body>
Simple page.
</body>
</html>

使用 curl 客户端发出请求。

$ 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

这是访问日志文件中的一个请求示例。

在 Jetty 教程的本章中,我们进行了一些基本的日志记录。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有Java教程