mababaka

Back

一、项目背景与目标

你是一名资深 Java 框架开发工程师、Spring Boot Starter 架构师及 Vue 3 前端工程师。

请开发一个完整、可运行、可测试、可复用、可发布的开源级项目:

Spring Boot Live Log Starter

项目目标:让任何使用 Spring Boot 4.x、Java 21、Spring MVC、Log4j2 的应用,只需引入 Maven Starter 依赖并在 application.yml 中开启功能,就能自动获得一个内置的 Web 日志控制台。

用户无需:

  • 修改现有业务 Controller。

  • 修改现有 Vue 前端项目。

  • 手动配置 Log4j2 Appender。

  • 安装 Redis、数据库、ELK、Loki 或其他服务。

  • 手动创建日志管理页面。

  • 编写日志采集和推送代码。

使用方式:

<dependency>
    <groupId>io.github.example</groupId>
    <artifactId>spring-boot-starter-live-log</artifactId>
    <version>1.0.0</version>
</dependency>
live-log:
  enabled: true
  web:
    path: /live-log
  buffer:
    capacity: 10000

以上 Maven 坐标为项目暂定坐标,可以在实现中统一调整。

启动 Spring Boot 后访问:

http://localhost:8080/live-log

即可查看当前 Spring Boot 进程的历史日志和实时日志。

要求这是一个真正的 Spring Boot Starter,而不是把日志 Controller 直接写在业务项目里。

二、技术栈

后端:

  • Java 21

  • Spring Boot 4.x

  • Spring MVC

  • Log4j2

  • SLF4J

  • Maven

  • Jackson

  • JUnit 5

  • Spring Boot Test

前端:

  • Vue 3

  • TypeScript

  • Vite

  • Element Plus

  • Pinia(可选)

  • 原生 EventSource 或支持自定义请求头的 Fetch SSE 客户端

其他要求:

  • 不使用 Redis。

  • 不依赖数据库。

  • 不使用 WebSocket。

  • 不依赖 Node.js 运行时。

  • 不依赖外部日志服务。

  • 不修改业务应用原有的日志输出配置。

  • 所有前端静态资源最终打包进入 Starter JAR。

  • 必须支持 Spring Boot 可执行 JAR 部署。

首先检查当前 Spring Boot 4.x、Log4j2、Spring MVC 的实际 API 和 Maven 依赖版本,确保实现兼容,不要使用已经移除或废弃的接口。

三、项目模块结构

采用 Maven 多模块结构:

spring-boot-live-log/
├── pom.xml
├── README.md
├── live-log-core/
│   └── src/main/java/
│       └── .../
│           ├── model/
│           │   ├── LogEntry.java
│           │   └── LogLevel.java
│           ├── buffer/
│           │   └── LogRingBuffer.java
│           ├── dispatch/
│           │   ├── LogDispatcher.java
│           │   └── LogSubscriber.java
│           └── service/
│               └── LiveLogService.java
│
├── live-log-log4j2/
│   └── src/main/java/
│       └── .../
│           ├── LiveLogAppender.java
│           └── Log4j2AppenderManager.java
│
├── live-log-spring-boot-autoconfigure/
│   └── src/main/
│       ├── java/
│       │   └── .../
│       │       ├── autoconfigure/
│       │       │   └── LiveLogAutoConfiguration.java
│       │       ├── properties/
│       │       │   └── LiveLogProperties.java
│       │       ├── controller/
│       │       │   └── LiveLogController.java
│       │       ├── security/
│       │       │   ├── LiveLogAccessChecker.java
│       │       │   └── LiveLogSecurityInterceptor.java
│       │       └── web/
│       │           └── LiveLogWebMvcConfiguration.java
│       └── resources/
│           └── META-INF/spring/
│               └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│
├── live-log-spring-boot-starter/
│   └── pom.xml
│
├── live-log-ui/
│   ├── package.json
│   ├── vite.config.ts
│   ├── index.html
│   └── src/
│       ├── App.vue
│       ├── main.ts
│       ├── api/
│       ├── components/
│       │   └── LogConsole.vue
│       └── composables/
│           └── useLiveLog.ts
│
└── live-log-demo/
    ├── pom.xml
    └── src/main/
        ├── java/
        └── resources/
            └── application.yml

允许根据实际依赖关系调整模块划分,但必须保持清晰的职责边界。

四、核心日志数据模型

定义不可变日志对象:

public record LogEntry(
    long id,
    long timestamp,
    String level,
    String logger,
    String thread,
    String message
) {}

要求:

  1. 每条日志分配单调递增的 ID。

  2. ID 用于排序、去重和断线补发。

  3. timestamp 使用毫秒级 Unix 时间戳。

  4. message 应包含格式化后的日志消息。

  5. 异常堆栈必须能够完整展示,但需要受到单条日志大小限制。

  6. 对超长日志进行截断,并标记 truncated 状态。

  7. 不直接保存可变的 Log4j2 LogEvent 对象。

  8. 日志对象创建后不可修改。

建议增加:

  • throwable 信息。

  • truncated 标记。

  • MDC 上下文信息(可配置)。

  • 实例 ID 或进程启动 ID,用于识别服务重启。

注意:不能仅凭递增 ID 判断不同进程之间的日志连续性。

五、内存环形缓冲区

实现 LogRingBuffer。

默认容量:10000 条。

要求:

  1. 使用固定容量环形缓冲区。

  2. 达到容量后覆盖或淘汰最旧日志。

  3. 不允许无限增长。

  4. 支持多个线程并发写入。

  5. 支持多个线程并发读取。

  6. 保证日志 ID 与写入顺序一致。

  7. 支持读取最近 N 条。

  8. 支持读取指定 ID 之后的日志。

  9. 支持获取最早 ID、最新 ID 和当前日志数量。

  10. 支持检测请求的日志 ID 是否已超出缓冲区保留范围。

  11. 不应为每次写入复制整个缓冲区。

  12. 不应在锁内执行网络 I/O。

  13. 单条日志默认最大 32768 字符,可配置。

  14. 不允许外部代码直接修改内部缓冲区。

优先考虑数组实现的 RingBuffer,或者经过论证的有界 Deque。

建议提供:

LogEntry append(LogEntryDraft draft);

List<LogEntry> latest(int limit);

LogPage after(long id, int limit);

LogBufferStats stats();

对历史日志读取设置最大数量,避免一次返回过大的响应。

服务端清屏与前端清屏必须区分。

第一版的清屏只清空浏览器当前显示内容,不清空服务端日志缓冲区。

六、Log4j2 自动注册

实现自定义 LiveLogAppender,继承 Log4j2 的 AbstractAppender。

要求:

  1. 不需要用户修改 log4j2-spring.xml。

  2. 自动挂载到现有 LoggerContext。

  3. 不影响已有 ConsoleAppender。

  4. 不影响已有 RollingFileAppender。

  5. 不改变原有日志级别。

  6. 避免重复注册。

  7. 支持关闭时安全卸载。

  8. Log4j2 重新加载配置后能够重新挂载。

  9. 不能产生递归日志采集。

  10. 不能阻塞业务日志线程。

  11. Appender 内部异常不能影响业务逻辑。

  12. enabled=false 时不得注册。

  13. 如果应用不是 Log4j2,应明确跳过并提供可诊断信息,不能强制破坏原有日志系统。

特别注意:

Log4j2 初始化可能早于 Spring ApplicationContext。

不要直接依赖 @Autowired 注入 Appender。

应设计明确的 Appender 注册、启动、重载恢复和卸载机制。

优先采用 Log4j2 官方公开 API。

不得通过反射修改私有字段。

需要明确说明:通过 Spring 自动配置动态安装的 Appender,只能采集安装之后产生的日志。第一版不强制捕获 Spring Boot 最早期启动日志。

七、日志采集和异步分发

采用以下架构:

Log4j2
  |
  v
LiveLogAppender
  |
  v
LogRingBuffer
  |
  v
LogDispatcher
  |
  +--> Client A Queue --> SSE A
  |
  +--> Client B Queue --> SSE B
  |
  +--> Client C Queue --> SSE C

要求:

  1. Appender 只执行轻量级操作。

  2. 不在日志线程中发送 SSE。

  3. 每个 SSE 客户端拥有有界队列。

  4. 后台分发器负责发送。

  5. 慢客户端不能拖慢其他客户端。

  6. 队列满时执行明确策略,例如断开并要求重新同步。

  7. 避免为每条日志创建新线程。

  8. 不允许无限制创建线程。

  9. 不允许无限制创建队列。

  10. 服务关闭时停止分发线程并释放资源。

  11. 日志系统异常不能造成业务服务不可用。

需要考虑日志写入、缓冲区提交和事件分发之间的顺序。

如果选择异步发布事件,必须保证前端接收的 ID 顺序正确。

八、REST API

API 基础路径默认:

/live-log/api

1. 获取历史日志

GET /live-log/api/logs?limit=500

响应示例:

{
  "entries": [
    {
      "id": 10001,
      "timestamp": 1790000000000,
      "level": "INFO",
      "logger": "com.example.Application",
      "thread": "main",
      "message": "Application started"
    }
  ],
  "earliestId": 1,
  "latestId": 10001,
  "hasMore": true
}

要求支持:

  • limit。

  • beforeId。

  • afterId。

  • level。

  • keyword。

所有参数必须验证。

limit 默认 500,最大 2000。

搜索默认仅作用于内存缓冲区,不提供全量文件检索。

2. 获取缓冲区状态

GET /live-log/api/stats

返回:

{
  "capacity": 10000,
  "size": 8500,
  "earliestId": 100,
  "latestId": 8600,
  "connectedClients": 2,
  "instanceId": "generated-instance-id"
}

3. SSE 实时日志

GET /live-log/api/stream?afterId=8600
Accept: text/event-stream

事件格式:

id: 8601
event: log
data: {"id":8601,"level":"INFO","message":"New log"}

必须支持:

  • afterId。

  • Last-Event-ID。

  • 心跳。

  • 客户端断开。

  • 自动重连。

  • 断线补发。

  • 历史日志已淘汰时的 gap 事件。

  • 服务重启时的实例 ID 识别。

建议事件类型:

  • log

  • heartbeat

  • gap

  • ready

  • error

不得在连接初始化、补发和实时订阅之间出现竞态条件。

必须设计原子订阅或等效机制,确保历史与实时事件无缝衔接。

同一条日志允许前端通过 ID 去重,但正常情况下不应无故重复发送。

当日志已从环形缓冲区淘汰时,必须明确通知前端,不能承诺无法实现的完整补发。

4. 健康检查

可选提供:

GET /live-log/api/health

仅返回日志组件健康状态,不泄露系统敏感信息。

九、SSE 连接管理

使用 Spring MVC 的 SseEmitter,或者经过论证的 Spring MVC SSE 实现。

要求:

  • 心跳默认 20 秒。

  • 最大连接数默认 10。

  • 单客户端队列容量默认 1000。

  • 客户端关闭后立即释放资源。

  • 服务关闭时完成所有 SSE 连接。

  • 异常连接及时移除。

  • 防止重复释放。

  • 防止内存泄漏。

  • 处理代理服务器缓冲问题。

  • 支持浏览器自动重连。

  • 避免线程池耗尽。

  • 明确规定事件发送顺序。

需要编写 SSE 并发和断线恢复测试。

十、Vue 3 内置日志控制台

前端使用:

  • Vue 3

  • TypeScript

  • Vite

  • Element Plus

页面采用深色终端风格,布局简洁、现代。

必须包含:

1. 实时日志显示

  • 时间戳。

  • 日志级别。

  • Logger 名称。

  • 线程名称。

  • 日志内容。

  • 异常堆栈。

不同日志级别采用不同颜色。

2. 日志级别过滤

支持:

  • ALL

  • TRACE

  • DEBUG

  • INFO

  • WARN

  • ERROR

  • FATAL

支持单级别或多级别过滤,明确过滤语义。

3. 关键词搜索

  • 支持搜索当前缓冲区日志。

  • 支持前端高亮。

  • 支持清空关键词。

  • 不使用不安全的 v-html 直接渲染日志内容。

  • 防止日志内容中的 HTML 或脚本被执行。

4. 暂停和恢复

区分两个概念:

  • 暂停自动滚动。

  • 暂停实时显示。

暂停实时显示时仍需保证恢复逻辑正确。

如果暂停期间日志超过前端缓存容量,应提示存在缺口并重新同步。

5. 自动滚动

  • 默认滚动到底部。

  • 用户手动向上滚动后暂停自动跟随。

  • 回到底部后恢复。

  • 新日志到达时不强制抢夺用户滚动位置。

6. 清屏

点击清屏只清空前端当前显示内容。

不得删除服务端日志。

7. 性能

  • 默认最多展示 10000 条。

  • 使用虚拟列表。

  • 避免每收到一条日志就进行昂贵的全量计算。

  • 高频日志采用批量更新。

  • 页面关闭后释放 EventSource。

  • 避免重复建立连接。

  • 断线重连后按 ID 去重。

  • 正确处理跨进程重启。

8. 状态显示

显示:

  • 已连接。

  • 连接中。

  • 已断开。

  • 正在重连。

  • 已暂停。

  • 缓冲区日志数量。

  • 当前实例 ID(可简化显示)。

9. 页面体验

支持桌面浏览器,兼容常见现代浏览器。

页面顶部提供:

  • 日志级别选择。

  • 搜索输入框。

  • 暂停/恢复。

  • 清屏。

  • 自动滚动开关。

  • 连接状态。

不需要业务系统提供任何 Vue 组件。

十一、Vue 静态资源打包

构建后的前端文件需要进入 Starter JAR。

推荐资源位置:

META-INF/resources/live-log/
├── index.html
└── assets/
    ├── index.js
    └── index.css

要求:

  1. 支持直接访问 /live-log。

  2. 支持 /live-log/。

  3. 支持静态资源加载。

  4. 支持 server.servlet.context-path。

  5. 支持配置自定义 Web 路径。

  6. 不覆盖业务系统已有的静态资源。

  7. 不使用全局通配路由影响业务接口。

  8. enabled=false 时页面和 API 均不可访问。

  9. JAR 部署时无需 Node.js。

  10. Maven 构建流程应能生成或使用前端产物。

需要说明前端开发模式与正式构建模式。

十二、配置系统

使用 @ConfigurationProperties。

建议配置:

live-log:
  enabled: false

  web:
    path: /live-log

  buffer:
    capacity: 10000
    max-entry-length: 32768

  logging:
    level: INFO
    include-stacktrace: true
    include-mdc: false

  sse:
    enabled: true
    heartbeat-interval: 20s
    max-connections: 10
    client-queue-capacity: 1000

  security:
    enabled: true
    local-only: true

要求:

  • 默认关闭。

  • 开启后必须有安全访问策略。

  • 配置支持校验。

  • 非法配置启动时给出明确错误。

  • 使用合理默认值。

  • 提供配置元数据,使 IDE 支持自动提示。

  • 支持用户自定义 Bean 覆盖部分默认实现。

  • 不允许通过关闭安全配置意外暴露公网日志接口而没有明显警告或保护。

十三、权限与安全

这是必须完成的核心模块。

定义扩展接口:

public interface LiveLogAccessChecker {
    boolean canAccess();
}

要求:

  1. 所有页面、API、SSE 请求都必须经过鉴权。

  2. 默认禁止未授权访问。

  3. 支持使用者自定义权限检查器。

  4. 可以接入 Sa-Token。

  5. 可以接入 Spring Security。

  6. 不强制依赖某一种权限框架。

  7. 未配置鉴权器时,默认仅允许安全的本地访问模式,且应明确其适用边界。

  8. 不允许仅通过伪造 X-Forwarded-For 绕过本地访问限制。

  9. 反向代理场景必须说明可信代理配置。

  10. 禁止通过 URL 查询参数传输长期 Token 或密码。

  11. SSE 与 REST 使用同一套权限策略。

  12. 权限拒绝应返回 401 或 403,而不是 500。

  13. 禁止前端直接显示后端异常中的敏感信息。

特别注意:

日志可能包含:

  • 用户信息。

  • 访问 Token。

  • 数据库连接信息。

  • SQL 参数。

  • 内部异常堆栈。

需要提供日志脱敏扩展点,支持在写入内存缓冲区之前进行敏感信息处理。

不得把日志内容当作可信 HTML。

十四、Spring Boot 自动配置

使用 Spring Boot 官方自动配置机制。

必须实现:

META-INF/spring/
org.springframework.boot.autoconfigure.AutoConfiguration.imports

要求:

  • 使用 @AutoConfiguration。

  • 使用 @ConditionalOnProperty。

  • 使用 @ConditionalOnClass。

  • 使用 @ConditionalOnMissingBean。

  • 避免与业务系统 Bean 冲突。

  • 不依赖业务项目的 ComponentScan。

  • 不影响已有 WebMvcConfigurer。

  • 不覆盖业务系统 SecurityFilterChain。

  • 支持优雅关闭。

  • 支持多次创建和关闭 Spring ApplicationContext 的测试场景。

  • 不重复安装 Appender。

  • 不泄漏静态引用和线程。

  • 不影响 Spring Boot Actuator。

十五、测试要求

必须编写自动化测试,而不是只提供手工验证。

单元测试

覆盖:

  • RingBuffer 容量限制。

  • 并发写入。

  • 日志 ID 唯一且递增。

  • 历史分页。

  • afterId 查询。

  • 缓冲区淘汰。

  • 超长日志截断。

  • 日志过滤。

  • 日志脱敏。

集成测试

覆盖:

  • Starter 自动配置。

  • enabled=false。

  • enabled=true。

  • Appender 注册。

  • Appender 卸载。

  • Log4j2 配置重载。

  • REST 历史查询。

  • SSE 连接。

  • SSE 心跳。

  • SSE 断线补发。

  • 缓冲区 gap 事件。

  • 最大连接数。

  • 未授权访问。

  • Spring Context 关闭后的资源释放。

并发压力测试

模拟:

  • 10 个 SSE 客户端。

  • 多个日志生产线程。

  • 高频日志写入。

  • 客户端连接与断开。

  • 慢客户端。

  • 客户端队列溢出。

  • 日志缓冲区持续覆盖。

重点验证:

  • 不死锁。

  • 不无限增长内存。

  • 不阻塞业务日志线程。

  • 不重复分配 ID。

  • 不发生无法解释的日志乱序。

  • 不泄漏线程和连接。

前端测试

至少覆盖:

  • 历史日志加载。

  • 实时日志追加。

  • 断线重连。

  • 日志 ID 去重。

  • 关键词搜索。

  • 级别过滤。

  • 暂停与恢复。

  • 自动滚动。

  • 清屏。

  • XSS 安全渲染。

十六、Demo 项目

提供独立的 live-log-demo。

要求:

  1. Spring Boot 4.x。

  2. Java 21。

  3. 使用 Log4j2。

  4. 引入 Starter。

  5. 配置开启日志控制台。

  6. 提供定时生成测试日志的功能。

  7. 包含 INFO、DEBUG、WARN、ERROR 日志。

  8. 包含异常堆栈。

  9. 包含长日志测试。

  10. 提供简单的管理员鉴权示例。

Demo 启动后应能直接打开浏览器查看日志。

十七、README 文档

必须包含:

  1. 项目介绍。

  2. 核心功能。

  3. 架构图。

  4. 环境要求。

  5. Maven 引入方式。

  6. application.yml 示例。

  7. 本地开发步骤。

  8. Maven 构建步骤。

  9. Vue 构建步骤。

  10. Spring Boot JAR 打包方式。

  11. 页面访问方式。

  12. API 文档。

  13. Sa-Token 接入示例。

  14. Spring Security 接入示例。

  15. 生产部署注意事项。

  16. Nginx SSE 反向代理配置。

  17. 性能和内存限制。

  18. 常见问题。

  19. 已知限制。

十八、验收标准

以下条件必须全部满足:

  • Maven 项目可以成功编译。

  • 所有模块依赖关系正确。

  • Starter 可以被独立 Spring Boot 项目引入。

  • 引入 Starter 不需要修改业务代码。

  • enabled=false 不注册 Appender、不暴露页面与 API。

  • enabled=true 自动安装日志采集组件。

  • 现有 Log4j2 文件和控制台输出不受影响。

  • 最近 10000 条日志正确保留。

  • 超过容量自动淘汰最旧日志。

  • 页面打开时能够加载历史日志。

  • 新日志能够实时推送。

  • SSE 断线重连能够补发保留范围内的日志。

  • 缓冲区已淘汰的日志能够产生 gap 提示。

  • 多客户端并发不影响日志生产。

  • 页面可以过滤日志级别。

  • 页面可以搜索日志。

  • 页面可以暂停和恢复。

  • 页面可以清屏。

  • 页面支持自动滚动。

  • 页面资源全部包含在 JAR 内。

  • 无需独立部署 Vue 服务。

  • 页面与 API 均受到权限保护。

  • 应用关闭后没有线程或连接泄漏。

  • 单元测试和集成测试通过。

  • Demo 可以独立运行。

  • README 完整。

十九、代码质量要求

  1. 使用 Java 21 现代语言特性。

  2. 使用合理的不可变数据结构。

  3. 遵循 SOLID 原则。

  4. 避免过度设计。

  5. 不引入无必要的依赖。

  6. 不使用 Lombok 作为核心模块的强制依赖。

  7. 核心代码提供必要的中文注释。

  8. 不允许空实现、伪实现和 TODO 占位。

  9. 不允许只写接口不实现。

  10. 不允许仅实现后端而遗漏前端。

  11. 不允许只给出代码片段,必须创建完整项目文件。

  12. 重要异常必须有清晰处理。

  13. 不得吞掉错误后假装成功。

  14. 日志采集组件不能递归记录自身异常。

  15. 不得使用无限队列和无限线程池。

  16. 不得在 Appender 中执行阻塞式网络操作。

  17. 不得把敏感信息写入调试日志。

  18. 所有接口路径必须避免与业务应用冲突。

二十、执行方式

请直接在当前工作目录创建项目并实现,不要只输出设计方案。

按照以下顺序执行:

阶段一:项目骨架

  • 创建 Maven 多模块工程。

  • 配置依赖管理。

  • 确认 Spring Boot 4.x 和 Log4j2 API 兼容性。

阶段二:核心日志引擎

  • 实现 LogEntry。

  • 实现 RingBuffer。

  • 实现 LogDispatcher。

  • 实现 Log4j2 Appender。

  • 完成并发测试。

阶段三:Spring Boot Starter

  • 实现自动配置。

  • 实现配置属性。

  • 实现动态 Appender 注册。

  • 实现 REST 和 SSE。

  • 实现权限扩展。

  • 完成集成测试。

阶段四:Vue 页面

  • 创建 Vue 3 + TypeScript + Vite 项目。

  • 使用 Element Plus 开发日志控制台。

  • 实现历史加载、SSE、过滤、搜索、暂停、清屏。

  • 完成前端测试。

阶段五:打包集成

  • 将 Vue 构建产物打包到 Starter JAR。

  • 配置静态资源路由。

  • 确认独立可执行 JAR 可以访问页面。

阶段六:Demo 和验收

  • 创建 Demo。

  • 执行 Maven 测试。

  • 执行前端测试。

  • 启动 Demo。

  • 验证完整功能。

  • 完善 README。

每个阶段完成后执行相应测试,发现问题立即修复。

不要在存在编译错误或测试失败的情况下宣称完成。

如果遇到版本不兼容,优先使用对应版本官方推荐 API,不要通过删除功能规避问题。

最终输出:

  • 项目目录结构。

  • 实际使用的技术版本。

  • 核心设计说明。

  • 已完成的功能。

  • 测试执行结果。

  • 构建命令。

  • Demo 启动命令。

  • 页面访问地址。

  • 已知限制。

最终目标:交付一个真正可以被其他 Spring Boot 项目通过 Maven 引入、配置开启、直接访问 Web 页面查看实时日志的高质量 Starter。

开发任务:Spring Boot Live Log Starter
https://haustlyb.cn//archives/kai-fa-ren-wu-spring-boot-live-log-starter
Author Administrator
Published at 十月 27, 2026