You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Boot中读取Tomcat的访问日志?

问题背景

运行在Tomcat上的Spring Boot应用生成了access_log日志,日志样本如下:

IP - - [17/Feb/2023:17:27:20 +0400] "GET /web-services/112233.jpg HTTP/1.1"
IP - - [17/Feb/2023:17:27:29 +0400] "GET /web-services/ HTTP/1.1" 200 189
IP - - [17/Feb/2023:17:27:29 +0400] "GET /web-services/112233.jpg HTTP/1.1" 304

当前application.properties配置:

spring.mvc.view.prefix= /WEB-INF/jsp/
spring.mvc.view.suffix= .jsp

server.tomcat.accesslog.enabled= true

尝试过注入AccessLogValve但始终为null,添加额外Tomcat日志配置也未解决问题,需要在Java中读取这些日志内容。


解决方案

方法一:直接读取日志文件

Tomcat的access_log是本地文件,可通过Java文件IO直接读取,需注意日志文件的路径和滚动规则。

代码实现

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

@RestController
public class AccessLogController {

    // 从配置文件读取日志目录,默认取Tomcat logs目录
    @Value("${server.tomcat.accesslog.directory:${catalina.base}/logs}")
    private String accessLogDir;

    // 读取日志前缀,默认是localhost_access_log
    @Value("${server.tomcat.accesslog.prefix:localhost_access_log}")
    private String accessLogPrefix;

    @GetMapping("/access-logs")
    public List<String> getAccessLogs() throws IOException {
        // 若配置了file-date-format,需拼接日期(如localhost_access_log.2023-02-17.txt)
        // 此处示例取基础日志文件名,实际可遍历目录按修改时间获取最新日志
        String logFilePath = accessLogDir + "/" + accessLogPrefix + ".txt";
        return Files.readAllLines(Paths.get(logFilePath));
    }
}

注意事项

  • 若开启了日志滚动(按日期/大小切割),需遍历日志目录,筛选出目标日期或最新的日志文件
  • 确保应用程序对日志目录有读取权限

方法二:自定义AccessLogValve捕获日志

默认的AccessLogValve由Tomcat初始化,不属于Spring容器管理,无法直接注入。可自定义Valve继承AccessLogValve,在日志生成时直接捕获内容。

1. 自定义AccessLogValve

import org.apache.catalina.valves.AccessLogValve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import java.util.concurrent.CopyOnWriteArrayList;

public class CustomAccessLogValve extends AccessLogValve {

    // 线程安全集合存储日志,实际可替换为数据库、消息队列等持久化方式
    private static final CopyOnWriteArrayList<String> accessLogs = new CopyOnWriteArrayList<>();

    @Override
    public void log(Request request, Response response, long time) {
        // 调用父类方法生成标准日志字符串
        String logEntry = super.getLogEntry(request, response, time);
        if (logEntry != null) {
            accessLogs.add(logEntry);
        }
        // 保留原有的日志写入文件逻辑
        super.log(request, response, time);
    }

    public static CopyOnWriteArrayList<String> getAccessLogs() {
        return accessLogs;
    }
}

2. 注册自定义Valve到Tomcat

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TomcatConfig {

    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> customTomcatAccessLog() {
        return factory -> {
            CustomAccessLogValve customValve = new CustomAccessLogValve();
            // 配置日志格式,与application.properties保持一致
            customValve.setPattern("%h %l %u %t \"%r\" %s %b");
            // 配置日志存储目录、前缀等,可从配置文件读取
            customValve.setDirectory("logs");
            customValve.setPrefix("localhost_access_log");
            customValve.setSuffix(".txt");
            customValve.setEnabled(true);
            // 将自定义Valve添加到Tomcat引擎
            factory.addEngineValves(customValve);
        };
    }
}

3. 在Controller中获取日志

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class AccessLogController {

    @GetMapping("/access-logs")
    public List<String> getAccessLogs() {
        return CustomAccessLogValve.getAccessLogs();
    }
}

注意事项

  • 内存存储的日志仅在当前应用节点有效,集群环境下需将日志持久化到共享存储或数据库
  • 自定义Valve的配置需与application.properties中的Tomcat日志配置保持一致,避免重复或冲突

内容的提问来源于stack exchange,提问作者YourDaddyProgrammer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:45:46