 tao.chenandClaude
|
9bcfe558cf
|
logging: tool.call.error/end 接入主 logger (双写终端 + spark-mcp.log)
之前所有 tool 调用的 error 和 end 事件只写进 per-tool 文件
(data/logs/tools/<ts>_<tool>_<id>.log), 主日志文件 spark-mcp.log 完全
看不到。tail -f spark-mcp.log 排查问题时形同虚设, 必须去找具体的
per-tool 文件才能看到错误。
修复: toolCallLogger struct 加 base *slog.Logger 字段, StartToolCall
把传入的 base 写进 struct. WithError 在记录错误的同时调 base.Error
("tool.call.error", tool, name, err), End 在写完 per-tool 文件后
调 base.Info("tool.call.end", tool, name, duration_ms, error).
base 走的是 main logger (multiHandler 包装), 自动同时写终端 (遵循
LOG_FORMAT, 默认 text) 和主日志文件 (永远 JSON). LOG_LEVEL 过滤对
这两条事件仍生效, 行为统一.
新增 3 个单元测试 (internal/logging/tool_call_test.go):
- TestStartToolCall_EmitsErrorAndEnd: 验证错误路径两条事件都进
主 logger (用 bytes.Buffer 捕获 slog 输出, 解码 JSON 校验字段)
- TestStartToolCall_NilBaseSafe: 验证 base=nil (测试场景) 不 panic
且 per-tool 文件仍写入
- TestStartToolCall_SuccessfulCall_EmitsEndOnly: 验证成功路径
只发 end 不发 error, duration_ms >= 0
附带: gofmt 重排 internal/logging/tool_call.go import 块 (按字母序)
未提交: spark-mcp-linux-amd64 (本地 build 产物, .gitignore 未拦,
需另决定); .env (gitignored 内容)
Co-Authored-By: Claude <noreply@anthropic.com>
|
2026-07-13 15:27:28 +08:00 |
|
 tao.chenandClaude
|
2537976722
|
rm: list_applications 加 limit/queue + 日志 fallback 链补 NM 直连
P0 (Python parity 缺口):
- rm.Client.ListApps 新增 queue + limit 查询参数
- list_applications MCP tool schema 暴露 queue (string) 和 limit
(number, default 100), handler 透传给 RM client
- 限流原因: 生产 RM 上无 limit 会拉回 N MB JSON 撞 MaxResponseBytes
- limit <= 0 不发送 query 参数, 跟 RM 默认行为一致; 老的调用方
(TestListApplications_EndToEnd 等) 不传参时行为不变
- 4 个旧 ListApps 测试调用点跟着更新, 加 3 个新测试:
TestListApps_WithLimit, TestListApps_WithQueue,
TestListApps_LimitZeroNoParam
P1.3 (Python fallback 行为补全):
- rm.Client.GetLogs 加第 4 步 fallback: 当前 3 步
(amContainerLogs/aggregated-logs/logs) 全失败时, 调 GetApp
解析 app.amContainerLogs 字段, GET 该 URL 直连 NodeManager
- 新 source 名 'amContainerLogs-direct' 区分 RM-level endpoint
- 提取 doBytesWithHosts(extraHosts...) 支持 per-call host 白名单,
NM host 动态加进 allowedHosts, SSRF 保护不破 (URL 是 RM 响应里
回来的, 不是 LLM 任意填的)
- 新增 TestGetLogs_FallbackToAMDirect (成功路径) 和
TestGetLogs_FallbackFailsWhenAMFieldMissing (amContainerLogs
字段为空时正常返回 error)
P1.4 (零代码改动 + 文档化):
- get_application_logs / get_application_status 工具 description
更新, 提示 LLM raw RM JSON 里包含 amContainerLogs 字段, 可在
aggregated-logs 全部失败时自己用 fetch_url 直连 NM
- get_application_status 函数体不变 (本就是透传 raw JSON)
验证:
- go build / go vet / go test 全部通过
- 5 个新测试全 PASS, 老的 TestListApplications_EndToEnd 仍 PASS
- 单 ListApps 调用点 (list_applications.go:81) 编译过
未提交: spark-mcp-linux-amd64 (本地 build 产物, 当前 .gitignore
没拦, 需另行决定)
Co-Authored-By: Claude <noreply@anthropic.com>
|
2026-07-13 15:15:21 +08:00 |
|
 tao.chenandClaude
|
bf2640d8fd
|
admin: /admin HTML 公开可访问,让 token 弹窗真正能触发
上一轮 (90eba22) 把 admin 页改成 token 弹窗模式,但 webHandler 还
挂在带 AdminAuth 的 group 里。结果无 token 访问 /admin 拿到的不是
HTML,而是 {"error":"missing bearer token"} 的 401 JSON,弹窗
变成死代码。
修复: 拆出 gPublic group,只放 webHandler (GET /admin 和 /admin/)。
API 路由 (/clusters*, /audit) 和 OpenAPI docs (/docs, /docs/spec)
继续受 AdminAuth 保护 (后者暴露内部 API 结构,不该公网可见)。
HTML 自身的 token 输入流不变 — 弹窗仍然在客户端拦截 401、清旧 token、
记录 pendingRetry、保存新 token 后自动重试。
补一个 TestAdminWeb_NoTokenReturnsHTML 锁定新契约:
- GET /admin 无 token -> 200 + text/html (含 token-modal 元素)
- GET /admin/ 同上
- GET /admin/clusters 无 token -> 401 (回归保护)
- GET /admin/clusters good-token -> 200 (回归保护)
旧 TestMount_RequiresAuth 测的全是 API 路径, 不受影响, 全绿。
验证:
- go build / go vet / go test 全部通过
- 端到端 curl 复现用户报告场景: /admin 无 token -> 200 + 弹窗 HTML
- API + docs 鉴权行为不变
Co-Authored-By: Claude <noreply@anthropic.com>
|
2026-07-13 14:16:49 +08:00 |
|
 tao.chenandClaude
|
90eba221d4
|
admin: token 输入改为弹窗模式 (modal)
把 header 内嵌的 token 输入框 + Save 按钮拆掉,改用原生 <dialog>
弹窗。三种触发场景: 首访无 token 自动弹、API 401 自动弹 (清旧 token
后弹带错误信息)、用户主动点 Set Token 按钮弹。无有效 token 时阻止
Escape 关闭 (cancel 事件 preventDefault), 防止误操作丢失输入。
localStorage 键名 adminToken 不变, 零迁移成本。401 路径在 api()
内部清 token + 弹窗 + 记录 pendingRetry 闭包, 用户保存新 token 后
自动重试失败请求。
设计取舍:
- 选原生 <dialog> 而非自造 div + JS, 自带 modal/背板/焦点陷阱/a11y
- 选 <form> + preventDefault 而非 method='dialog', 避免自动关闭
- CSS 全部复用现有 dark theme 变量, 0 视觉割裂
- 0 新依赖 (纯 HTML5 + 原生 JS)
验证:
- go build / go vet / go test 全部通过
- 端到端 curl 确认新元素嵌入、旧元素删除、401/200 路径正常
- router_test.go 无回归 (HTML 改动不涉及 Go)
Co-Authored-By: Claude <noreply@anthropic.com>
|
2026-07-13 14:08:16 +08:00 |
|
 tao.chenandClaude
|
7f8960823b
|
config: GIN_MODE 改为环境变量配置 + Load() 自动加载 .env
main.go 硬编码 gin.ReleaseMode 改成读 cfg.GinMode(默认 release),
方便生产/调试切换 debug/release/test。Load() 开头先调 loadDotenv
(".env"): 缺文件静默跳过,shell env 优先于 .env,跳过注释/空行/
无 '=' 行并 slog.Warn。仅用标准库,不引新依赖。
验证:
- go build / go vet / go test 全部通过
- shell env 覆盖 .env (LISTEN_ADDR=:19090 覆盖 .env 的 :18080)
- 仅 .env 时正确加载 (监听 18080, GIN_MODE=debug 输出 [GIN-debug])
- 无 .env 且无 shell env 时清晰报错 ADMIN_TOKENS is not set
Co-Authored-By: Claude <noreply@anthropic.com>
|
2026-07-13 13:48:35 +08:00 |
|
tao.chen
|
1dfef0f598
|
init
|
2026-07-10 10:19:28 +08:00 |
|