# Java Servlet Log4j 教程

> 原文： [http://zetcode.com/articles/javaservletlog4j/](http://zetcode.com/articles/javaservletlog4j/)

Java servlet Log4j 教程显示了如何在 Java servlet 中使用 Log4j 进行日志记录。 本教程介绍 Log4j 版本 2。

## Java Servlet

Servlet 是 Java 类，可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器（例如 Tomcat 或 Jetty）中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

## Log4j

Apache Log4j 是基于 Java 的日志记录工具。 它是 Apache Software Foundation 的项目。 可以通过 Java 代码或在配置文件中配置 Log4j。 配置文件可以 XML，JSON，YAML 或属性文件格式编写。

Log4j 具有三个主要组件：记录器，附加器和布局。 记录器被命名为目标，可捕获捕获日志消息并将其发送到附加程序。 附加器将日志消息传递到其目的地，例如文件或控制台。 布局用于定义日志消息的格式。

## Java servlet 日志记录示例

以下 Web 应用正在使用 Log4j 进行日志记录。 在 Servlet 3.0+应用中，Log4j 可以直接使用。 它在应用部署时自动启动，在应用取消部署时自动关闭。

```java
$ 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

```

这是项目结构。 Log4j 配置文件位于`src/main/resources/`目录中。

`pom.xml`

```java
<?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>

```

这是 Maven POM 文件。 我们有两个工件：用于服务器小程序的`javax.servlet-api`和用于 Web 应用中 Log4j 记录的`log4j-web`。 `maven-war-plugin`负责收集 Web 应用的所有工件依赖项，类和资源，并将它们打包到 Web 应用存档（WAR）中。

`context.xml`

```java
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletLog4j"/>

```

在 Tomcat `context.xml`文件中，我们定义了上下文路径。 它是 Web 应用的名称。

`log4j2.xml`

```java
<?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>

```

在`log4j2.xml`中配置 Log4j。 在我们的示例中，我们选择了 XML 文件格式。

```java
<Properties>
  <Property name="logdir">/home/janbodnar/tmp</Property>
  <Property name="layout">%d [%t] %-5p %c - %m%n</Property>
</Properties>

```

在`Properties`标记中，我们设置了日志目录和布局。 布局定义了日志的格式。

模式布局由转换说明符组成。 每个说明符均以百分号开头，后跟可选的格式修饰符和强制转换字符。 `%d`输出记录事件的日期。 `%t`输出生成日志事件的线程的名称。 `%-5p`输出记录事件的级别，级别名称中至少要包含五个字符，并且这些字符必须对齐。 `%c`输出发布了记录事件的记录器的名称。 `%m`打印与日志记录事件关联的应用消息，`%n`是平台相关的行分隔符或多个字符。

```java
<Appenders>
...
</Appenders>

```

附加项是定义日志消息保存位置的对象。 有几个可能的目的地，包括控制台，文件，数据库表或原型。

```java
<RollingFile name="LOCALHOST"
    fileName="${logdir}/localhost.log"
    filePattern="${logdir}/localhost.%d{yyyy-MM-dd}-%i.log">
  <PatternLayout pattern="${layout}" />
...
  <DefaultRolloverStrategy max="10" />
</RollingFile>

```

我们设置日志文件的位置。 我们使用滚动文件附加器，该附加器会自动滚动或归档当前日志文件，并继续记录新文件。 `PatternLayout`设置日志消息的布局。 如果存档数量达到十个，则`DefaultRolloverStrategy`会删除较旧的存档。

```java
<Policies>
  <TimeBasedTriggeringPolicy />
  <SizeBasedTriggeringPolicy size="1 MB" />
</Policies>

```

触发策略在`Policies`标记中定义。 它们控制发生翻转的条件。 在这里，我们使用两个策略：`TimeBasedTriggeringPolicy`和`SizeBasedTriggeringPolicy`。 `TimeBasedTriggeringPolicy`根据最具体的日期和时间模式开始翻转； 就我们而言，如果每小时日志文件的大小达到 1MB，则`SizeBasedTriggeringPolicy`开始翻转。

```java
<Loggers>

  <Logger name="com.zetcode"
      level="info" additivity="false">
    <AppenderRef ref="LOCALHOST" />
  </Logger>

  <Root level="error">
  </Root>    

</Loggers>

```

在`Loggers`标签中，我们定义了记录器。 它们被称为日志消息目的地。 每个记录器可以配置不同级别的记录。 我们定义一个具有信息记录级别的记录器。 我们将先前定义的滚动文件附加器附加到此记录器。 在`additivity`设置为`false`的情况下，日志消息不会传播到其祖先。

`MyServlet.java`

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

```

这是`MyServlet` servlet。 它调用服务方法并将文本数据发送回客户端。

```java
final static Logger logger = LogManager.getLogger(MyService.class);

```

我们从`LogManager`获取记录器。

```java
logger.info("MyServlet's doGet() called");

```

我们记录一条信息级别的消息。

```java
MyService service = new MyService();
service.doWork();

```

我们称为虚拟服务方法。

```java
PrintWriter out = response.getWriter();
out.print("MyServlet called");

```

我们将文本数据发送给客户端。

`MyService.java`

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

```

`MyService`的`doWork()`方法记录信息级别的消息。

`index.html`

```java
<!DOCTYPE html>
<html>
    <head>
        <title>Home Page</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <a href="MyServlet">Call Servlet</a>
    </body>
</html>

```

主页包含一个调用`MyServlet`的链接。

```java
$ 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

```

这是已记录消息的示例输出。

在本教程中，我们已经在 Java Web 应用中使用 Log4j 完成了一些日志记录。

您可能也对以下相关教程感兴趣： [Java Log4j 教程](/java/log4j/)， [Java Servlet RESTful 客户端](/articles/javaservletrestclient/)， [Java Servlet 上传文件](/articles/javaservletuploadfile/)， [Java `RequestDispatcher`](/java/requestdispatcher/) ，[从 Java servlet 提供纯文本](/articles/javaservlettext/)， [Java servlet 复选框教程](/articles/javaservletcheckbox/)， [Java servlet 图像教程](/articles/javaservletimage/)， [Java Servlet HTTP 标头](/articles/javaservlethttpheaders/)或 [Java 教程](/lang/java/)