diff --git "a/docs/1.18.0/design/\346\227\245\345\277\227\346\224\257\346\214\201\347\273\206\347\262\222\345\272\246\350\277\224\345\233\236\346\224\271\351\200\240_\350\256\276\350\256\241.md" "b/docs/1.18.0/design/\346\227\245\345\277\227\346\224\257\346\214\201\347\273\206\347\262\222\345\272\246\350\277\224\345\233\236\346\224\271\351\200\240_\350\256\276\350\256\241.md"
new file mode 100644
index 0000000000..a1ba5cecc6
--- /dev/null
+++ "b/docs/1.18.0/design/\346\227\245\345\277\227\346\224\257\346\214\201\347\273\206\347\262\222\345\272\246\350\277\224\345\233\236\346\224\271\351\200\240_\350\256\276\350\256\241.md"
@@ -0,0 +1,130 @@
+# 阶段2:设计方案文档
+
+## 1. 总述
+
+### 1.1 需求与目标
+
+**项目背景**:在大模型分析场景中,当前获取用户任务日志接口会返回所有(info、error、warn)任务日志,导致大模型处理文件数量过多。为了优化大模型处理效率,需要对 filesystem 模块的 openLog 接口进行增强,支持根据指定的日志级别返回对应的日志内容。
+
+**设计目标**:
+1. 实现 openLog 接口的日志级别过滤功能
+2. 支持 all、info、error、warn 四种日志级别
+3. 保持向后兼容性,缺省情况下返回全部日志
+4. 确保实现的正确性、性能和可靠性
+
+## 2. 技术架构
+
+**技术栈**:
+- 开发语言:Java (服务端), Scala (客户端SDK)
+- 框架:Spring Boot
+- 存储:文件系统
+
+**部署架构**:
+与现有 filesystem 模块部署架构一致,无需额外部署组件。
+
+## 3. 核心概念/对象
+
+| 概念/对象 | 描述 |
+|-----------|------|
+| LogLevel | 日志级别枚举类,定义了 ERROR、WARN、INFO、ALL 四种级别 |
+| FsRestfulApi | filesystem 模块的 RESTful 接口实现类 |
+| OpenLogAction | 客户端 SDK 中调用 openLog 接口的 Action 类 |
+| filterLogByLevel | 新增的日志过滤方法 |
+
+## 4. 处理逻辑设计
+
+### 4.1 接口参数变更
+
+**原接口签名**:
+```java
+public Message openLog(
+ HttpServletRequest req,
+ @RequestParam(value = "path", required = false) String path,
+ @RequestParam(value = "proxyUser", required = false) String proxyUser)
+```
+
+**新接口签名**:
+```java
+public Message openLog(
+ HttpServletRequest req,
+ @RequestParam(value = "path", required = false) String path,
+ @RequestParam(value = "proxyUser", required = false) String proxyUser,
+ @RequestParam(value = "logLevel", required = false, defaultValue = "all") String logLevel)
+```
+
+### 4.2 日志过滤逻辑
+
+```
+输入: log[4] 数组, logLevel 参数
+|
+v
+logLevel 为空或 "all"? --> 是 --> 返回原始 log[4]
+|
+v (否)
+根据 logLevel 创建新数组 filteredResult[4],初始化为空字符串
+|
+v
+switch(logLevel.toLowerCase()):
+ case "error": filteredResult[0] = log[0]
+ case "warn": filteredResult[1] = log[1]
+ case "info": filteredResult[2] = log[2]
+ default: 返回原始 log[4] (向后兼容)
+|
+v
+返回 filteredResult[4]
+```
+
+### 4.3 数据结构
+
+日志数组索引与日志级别对应关系:
+
+| 索引 | 日志级别 | LogLevel.Type |
+|------|----------|---------------|
+| 0 | ERROR | LogLevel.Type.ERROR |
+| 1 | WARN | LogLevel.Type.WARN |
+| 2 | INFO | LogLevel.Type.INFO |
+| 3 | ALL | LogLevel.Type.ALL |
+
+## 5. 代码变更清单
+
+### 5.1 FsRestfulApi.java
+
+**文件路径**: `linkis-public-enhancements/linkis-pes-publicservice/src/main/java/org/apache/linkis/filesystem/restful/api/FsRestfulApi.java`
+
+**变更内容**:
+1. `openLog` 方法添加 `logLevel` 参数
+2. 添加 Swagger API 文档注解
+3. 新增 `filterLogByLevel()` 私有方法
+
+### 5.2 OpenLogAction.scala
+
+**文件路径**: `linkis-computation-governance/linkis-client/linkis-computation-client/src/main/scala/org/apache/linkis/ujes/client/request/OpenLogAction.scala`
+
+**变更内容**:
+1. Builder 类添加 `logLevel` 属性(默认值 "all")
+2. 添加 `setLogLevel()` 方法
+3. `build()` 方法中添加 logLevel 参数设置
+
+## 6. 非功能性设计
+
+### 6.1 安全
+
+- **权限控制**:确保用户只能访问自己有权限的日志文件(复用现有逻辑)
+- **参数校验**:对请求参数进行合理处理,无效参数不抛异常
+
+### 6.2 性能
+
+- 日志级别过滤对接口响应时间的影响可忽略不计(< 1ms)
+- 过滤逻辑在内存中完成,无额外 I/O 操作
+
+### 6.3 向后兼容
+
+- 缺省情况下返回全部日志,与原有行为一致
+- 无效 logLevel 参数返回全部日志,确保服务不中断
+- 现有调用方无需修改代码即可继续使用
+
+## 7. 变更历史
+
+| 版本 | 日期 | 变更人 | 变更内容 |
+|-----|------|--------|----------|
+| 1.0 | 2025-12-26 | AI Assistant | 初始版本 |
diff --git "a/docs/1.18.0/requirements/\346\227\245\345\277\227\346\224\257\346\214\201\347\273\206\347\262\222\345\272\246\350\277\224\345\233\236\346\224\271\351\200\240_\351\234\200\346\261\202.md" "b/docs/1.18.0/requirements/\346\227\245\345\277\227\346\224\257\346\214\201\347\273\206\347\262\222\345\272\246\350\277\224\345\233\236\346\224\271\351\200\240_\351\234\200\346\261\202.md"
new file mode 100644
index 0000000000..d5ba14f796
--- /dev/null
+++ "b/docs/1.18.0/requirements/\346\227\245\345\277\227\346\224\257\346\214\201\347\273\206\347\262\222\345\272\246\350\277\224\345\233\236\346\224\271\351\200\240_\351\234\200\346\261\202.md"
@@ -0,0 +1,125 @@
+# 阶段1:需求分析文档
+
+## 一、需求背景
+
+在大模型分析场景中,当前获取用户任务日志接口会返回所有(info、error、warn)任务日志,导致大模型处理文件数量过多。为了优化大模型处理效率,需要对 filesystem 模块的 openLog 接口进行增强,支持根据指定的日志级别返回对应的日志内容。
+
+## 二、需求描述
+
+### 2.1 需求详细描述
+
+| 模块 | 功能点 | 功能描述 | UI设计及细节 | 功能关注点 |
+|-----|--------|----------|--------------|------------|
+| filesystem | 日志级别过滤 | 在 openLog 接口中添加 logLevel 参数,支持指定返回的日志级别 | 不涉及 | 确保参数类型正确,默认值设置合理 |
+| filesystem | 多种日志级别支持 | 支持 logLevel=all,info,error,warn 四种取值 | 不涉及 | 确保所有取值都能正确处理 |
+| filesystem | 默认值处理 | 缺省情况下返回全部日志(相当于 logLevel=all) | 不涉及 | 确保向后兼容性 |
+| filesystem | 向后兼容 | 不影响现有调用方的使用 | 不涉及 | 现有调用方无需修改代码即可继续使用 |
+
+### 2.2 需求交互步骤
+
+1. 用户调用 `/openLog` 接口,指定 `path` 参数和可选的 `logLevel` 参数
+2. 系统解析请求参数,获取日志文件路径和日志级别
+3. 系统读取日志文件内容,根据指定的日志级别过滤日志
+4. 系统返回过滤后的日志内容给用户
+
+### 2.3 模块交互步骤
+
+```
+用户 → filesystem模块 → openLog接口 → 日志文件 → 日志过滤 → 返回结果
+```
+
+**关键步骤说明**:
+1. 用户调用 openLog 接口,传入 path 和 logLevel 参数
+2. openLog 接口验证参数合法性,解析日志级别
+3. 系统读取指定路径的日志文件
+4. 系统根据日志级别过滤日志内容
+5. 系统将过滤后的日志内容封装为响应对象返回给用户
+
+**关注点**:
+- 需关注无效 logLevel 参数的处理,应返回默认日志(全部日志)
+- 需关注日志文件过大的情况,应返回合理的错误信息
+- 需关注权限控制,确保用户只能访问自己有权限的日志文件
+
+## 三、接口文档
+
+### 3.1 接口基本信息
+
+| 项 | 说明 |
+|----|------|
+| 接口URL | /api/rest_j/v1/filesystem/openLog |
+| 请求方法 | GET |
+| 接口描述 | 获取指定路径的日志文件内容,支持按日志级别过滤 |
+
+### 3.2 请求参数
+
+| 参数名 | 类型 | 必填 | 默认值 | 说明 |
+|--------|------|------|--------|------|
+| path | String | 是 | 无 | 日志文件路径 |
+| proxyUser | String | 否 | 无 | 代理用户,仅管理员可使用 |
+| logLevel | String | 否 | all | 日志级别,取值为 all,info,error,warn |
+
+### 3.3 响应参数
+
+| 参数名 | 类型 | 说明 |
+|--------|------|------|
+| status | String | 响应状态,success 表示成功,error 表示失败 |
+| message | String | 响应消息 |
+| data | Object | 响应数据 |
+| data.log | String[] | 日志内容数组,按以下顺序排列:
1. 第0位:ERROR 级别的日志
2. 第1位:WARN 级别的日志
3. 第2位:INFO 级别的日志
4. 第3位:ALL 级别的日志(所有日志) |
+
+### 3.4 请求示例
+
+```bash
+# 请求所有日志
+curl -X GET "http://localhost:8080/api/rest_j/v1/filesystem/openLog?path=/path/to/test.log"
+
+# 请求特定级别的日志
+curl -X GET "http://localhost:8080/api/rest_j/v1/filesystem/openLog?path=/path/to/test.log&logLevel=error"
+```
+
+### 3.5 响应示例
+
+**请求所有日志的响应**:
+```json
+{
+ "status": "success",
+ "message": "",
+ "data": {
+ "log": [
+ "2025-12-26 10:00:02.000 ERROR This is an error log\n",
+ "2025-12-26 10:00:01.000 WARN This is a warn log\n",
+ "2025-12-26 10:00:00.000 INFO This is an info log\n",
+ "2025-12-26 10:00:00.000 INFO This is an info log\n2025-12-26 10:00:01.000 WARN This is a warn log\n2025-12-26 10:00:02.000 ERROR This is an error log\n"
+ ]
+ }
+}
+```
+
+**请求 ERROR 级别日志的响应**:
+```json
+{
+ "status": "success",
+ "message": "",
+ "data": {
+ "log": [
+ "2025-12-26 10:00:02.000 ERROR This is an error log\n",
+ "",
+ "",
+ ""
+ ]
+ }
+}
+```
+
+## 四、关联影响分析
+
+- **对存量功能的影响**:无,该功能是对现有接口的增强,不会影响其他功能
+- **对第三方组件的影响**:无,该功能仅涉及 filesystem 模块内部逻辑
+
+## 五、测试关注点
+
+- 验证不同日志级别参数的处理是否正确
+- 验证缺省情况下是否返回全部日志
+- 验证无效日志级别参数的处理是否正确
+- 验证大小写不敏感是否正确
+- 验证权限控制是否有效
diff --git a/linkis-public-enhancements/linkis-pes-publicservice/src/main/java/org/apache/linkis/filesystem/restful/api/FsRestfulApi.java b/linkis-public-enhancements/linkis-pes-publicservice/src/main/java/org/apache/linkis/filesystem/restful/api/FsRestfulApi.java
index 0cf8d8334f..2eee67ab0c 100644
--- a/linkis-public-enhancements/linkis-pes-publicservice/src/main/java/org/apache/linkis/filesystem/restful/api/FsRestfulApi.java
+++ b/linkis-public-enhancements/linkis-pes-publicservice/src/main/java/org/apache/linkis/filesystem/restful/api/FsRestfulApi.java
@@ -1390,20 +1390,26 @@ public Message getSheetInfo(
@ApiOperation(value = "openLog", notes = "open log", response = Message.class)
@ApiImplicitParams({
@ApiImplicitParam(name = "path", required = false, dataType = "String", value = "path"),
- @ApiImplicitParam(name = "proxyUser", dataType = "String")
+ @ApiImplicitParam(name = "proxyUser", dataType = "String"),
+ @ApiImplicitParam(
+ name = "logLevel",
+ dataType = "String",
+ value =
+ "Log level, values: all,info,error,warn or comma-separated combinations like error,info,warn")
})
@RequestMapping(path = "/openLog", method = RequestMethod.GET)
public Message openLog(
HttpServletRequest req,
@RequestParam(value = "path", required = false) String path,
- @RequestParam(value = "proxyUser", required = false) String proxyUser)
+ @RequestParam(value = "proxyUser", required = false) String proxyUser,
+ @RequestParam(value = "logLevel", required = false, defaultValue = "all") String logLevel)
throws IOException, WorkSpaceException {
if (StringUtils.isEmpty(path)) {
throw WorkspaceExceptionManager.createException(80004, path);
}
String userName = ModuleUserUtils.getOperationUser(req, "openLog " + path);
LoggerUtils.setJobIdMDC("openLogThread_" + userName);
- LOGGER.info("userName {} start to openLog File {}", userName, path);
+ LOGGER.info("userName {} start to openLog File {}, logLevel: {}", userName, path, logLevel);
if (proxyUser != null && Configuration.isJobHistoryAdmin(userName)) {
userName = proxyUser;
}
@@ -1419,6 +1425,8 @@ public Message openLog(
> ByteTimeUtils.byteStringAsBytes(FILESYSTEM_FILE_CHECK_SIZE.getValue())) {
throw WorkspaceExceptionManager.createException(80033, path);
}
+ // 解析日志级别,支持多级别组合
+ Set targetLevels = parseLogLevels(logLevel);
try (FileSource fileSource =
FileSource$.MODULE$.create(fsPath, fileSystem).addParams("ifMerge", "false")) {
Pair