LogSseController(日志 SSE 推送)¶
为管理控制台「日志查看器」前端提供 Server-Sent Events(SSE) 实时日志推送:按调用方提供的应用名 / 主机 / 端口定位服务器日志文件(文件名约定 <appName>@<host>_<port>.log),以 500ms 为周期轮询文件增量并把新增行作为 message 事件推送给客户端,直到连接超时(600 秒)、客户端断开或读取异常。
- 类级基址:
${myapps.context-path.manager:}/console(完整路径:{manager-context}/console<相对路径>) - Tag:(控制器未声明
@Tag) - 控制器源码:
obpm-manager/src/main/java/cn/myapps/manager/websocket/console/LogSseController.java - 公共说明:
- 控制器**不**继承
BaseAuthTimeController,方法返回 Spring MVC 的SseEmitter(非**统一Resource,**非 JSON 文本)。响应Content-Type由 Spring MVC 设置为text/event-stream。 - 日志根目录取
Environment.getInstance().getLogRootPath()下的service子目录;若目标日志文件不存在,控制器会调用SecurityFile.resolveFile(...)解析后**自动创建空文件**。 - 单连接独享一个单线程
ScheduledExecutorService,初始延迟 0、固定周期 500ms 调用Tail.print();连接完成 / 超时 / 出错时关闭对应执行器。 - 文件增量读取基于
RandomAccessFile,首次定位时若文件大于 50KB 则从末尾回退 50KB 开始(Tail.lastPos);每行以ISO-8859-1读出后再用UTF-8重解码以避免中文乱码。 - 鉴权说明见 index.md「鉴权说明」(adminToken JWT)。
/console/***不在**鉴权白名单中,仍需 adminToken(与同包的LogConsoleController一致)。
1. 实时追踪日志(SSE 流)¶
按 appName@host_port.log 定位日志文件,建立 SSE 长连接,并以 500ms 周期推送新增日志行。
- 接口类型:REST 资源(流式响应,
text/event-stream) - 请求方式:
GET - 请求路径:
/tail(完整:{manager-context}/console/tail) - 鉴权:是(需管理员 adminToken,详见 index.md「鉴权说明」)
- Tag:(控制器未声明
@Tag)
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| appName | query | string | 是 | 应用名(与日志文件名前缀对应,如 obpm-runtime) |
| host | query | string | 是 | 主机(与日志文件名段对应,如 192.168.1.10) |
| port | query | string | 是 | 端口(与日志文件名段对应,如 8083) |
注:三个参数拼出文件名
<appName>@<host>_<port>.log(如obpm-runtime@192.168.1.10_8083.log),文件位于日志根目录的service子目录下。
请求示例¶
GET /console/tail?appName=obpm-runtime&host=192.168.1.10&port=8083 HTTP/1.1
Accept: text/event-stream
Cache-Control: no-cache
响应¶
- 状态码:200(连接建立成功)
- Content-Type:
text/event-stream(由 Spring MVC 写入) - 响应体:SSE 事件流,长连接保持至超时(600 秒)或异常。控制器内抛异常时被包装为
RuntimeException抛出(由 Spring 默认异常处理)。
SSE 事件结构(每行一条):
| 字段 | 说明 |
|---|---|
id: |
事件 id,取发送时刻的毫秒时间戳(System.currentTimeMillis()) |
event: |
事件名,固定为 message |
data: |
日志行原文(一条 data: 对应一行日志) |
注:SSE 协议约定事件之间以空行分隔;每 500ms 推送周期会把自上次读取位置起新增的所有行各自作为一条事件发出。
成功示例(连接建立后持续推送):
HTTP/1.1 200 OK
Content-Type: text/event-stream
id:1717624800123
event:message
data:2026-08-05 10:00:00 INFO o.s.b.w.embedded.tomcat.TomcatWebServer - Tomcat started on port 8083
id:1717624800456
event:message
data:2026-08-05 10:00:01 INFO c.m.r.RestSecurityHandlerInterceptor - access token validated
...
Resource,无业务错误码回写。常见异常情形:
| 情形 | 表现 |
|---|---|
| adminToken 缺失 / 失效 | ManagerSecurityFilter 直接返回 HTTP 401,无响应体 |
| 文件路径解析失败 / IO 异常 | 控制器把异常包装为 RuntimeException 抛出,由 Spring 默认异常处理(HTTP 500,无统一 Resource 体),SSE 连接无法建立 |
| 推送过程中读文件异常 | emitter.completeWithError(e) 结束 SSE 流;执行器随后关闭 |
注:
SseEmitter超时时间硬编码为600_000L(600 秒);超时后执行器自动 shutdown,客户端如需继续接收须重新建立连接。原代码中尚有注释掉的「每秒推送服务器时间」示例实现,与生产路径无关。