opsx
|
9641503007
|
feat(license): Pro 授权机制 — 离线许可码 + 免费版功能闸门
CI / Backend (go vet + test) (push) Waiting to run
CI / Frontend (lint + build + test) (push) Waiting to run
免费版:日志查询/部署管理/采集/用户管理/LDAP/设置;Pro(¥199 个人单实例永久 / ¥499 团队多实例永久):
日志分析、日志告警、智能运维(AI)、审计日志。
- 后端:HMAC-SHA256 离线许可码(签发 CLI / license --plan --edition --seats --customer --days;
永久=days 0),GET /system/license + POST activate;RequirePro 闸门挂 metrics/ai/audit;
过期自动回落免费;测试覆盖签发-校验/篡改/免费拒签
- 前端:菜单 Pro 项带锁标;四个 Pro 页面免费版渲染升级引导卡(功能清单+定价+页内激活);
设置页新增授权区(版本/席位/到期/激活入口);license 词典中英
- domains 注册提升到 main.tsx 全局(修复 license 命名空间在未引 domains 的页面显示裸键)
|
2026-10-31 23:08:06 +08:00 |
|
opsx
|
c60b827262
|
fix(settings): 定时切换主题去掉时区下拉与说明文字,固定用浏览器本地时区
|
2026-10-31 22:52:58 +08:00 |
|
opsx
|
c090ba0564
|
feat(aiops): 长窗口(>1h)分析必须指定应用
全命名空间 6h/24h 聚合数据量过大会拖垮 Loki:前端时间范围旁新增应用范围选择器
(labelValues 候选),>1h 未选应用禁用开始分析并提示;后端同样强制 400(闸门在服务端);
信号采集选择器按 app 收窄后 histogram/stats 从全量变为单应用流,秒级返回。
|
2026-10-31 22:51:55 +08:00 |
|
opsx
|
1610988c2e
|
feat(aiops): 模型配置参考 aiops/opsxshell — 快捷预设 + 供应商下拉
CI / Backend (go vet + test) (push) Waiting to run
CI / Frontend (lint + build + test) (push) Waiting to run
- 快捷预设:deepseek-flash(推荐)/ deepseek-v4-pro / 自定义 一键填入端点与模型
- 供应商目录(9 家 + 自定义):DeepSeek/通义/智谱/Kimi/MiniMax/硅基流动/混元/OpenAI/本地
Ollama·vLLM,选择后自动填 Base URL 与首个推荐模型
- 模型输入支持 datalist 下拉(随供应商联动)且可手输任意模型名;Base URL 保持可编辑
|
2026-10-31 15:23:26 +08:00 |
|
opsx
|
63445bd598
|
build(release): 部署后自愈 + 版本戳,堵住"latest 被旧镜像覆盖"这类问题
CI / Backend (go vet + test) (push) Waiting to run
CI / Frontend (lint + build + test) (push) Waiting to run
=== 背景:同类问题已经出现三次 ===
1) Docker Hub 502 导致 latest 推失败,Pod 仍跑旧镜像
2) 并发构建互相覆盖 latest(谁后完成谁生效)
3) 中断的构建后来完成,把 latest 推回旧代码(本次差点中招)
第 2 类已由 flock 独占锁解决;但前两类还有一个共同的后半段:
**没有人核对"部署后 Pod 到底跑的是不是刚推的那版"**。
=== 本次新增 ===
1) 部署后自愈:rollout 完成即核对 Pod digest 与远端 latest;
不一致自动 `kubectl delete po` 强制重拉(节点缓存了旧 latest 映射是常见原因),
最多等 4 分钟,仍不一致才 exit 1 —— 不再"报个 ❌ 就结束"。
2) 版本戳:核对通过后给 Deployment 打三个 annotation
lokistack.io/release-image = <digest>
lokistack.io/release-tag = <版本-日期-commit>
lokistack.io/release-time = <ISO8601>
以后排查"线上跑哪版"直接 `kubectl -n log get deploy lokistack -o yaml | grep release-`,
不用再在 docker images / Hub API / Pod 之间来回比对。
=== 用法 ===
以后发版统一走 `bash scripts/release.sh`(build+push+deploy+自愈+打戳一次完成)
不要再手敲 docker build + docker push —— 那样会绕过 flock 锁,回到互相覆盖。
bash scripts/release.sh --dry-run 只做前置检查
bash scripts/release.sh --no-deploy 只发镜像不动集群
|
2026-10-31 07:08:23 +00:00 |
|
opsx
|
7be41f0a6b
|
feat(aiops): 新增「智能运维」——AI 日志分析(P0,不扫日志内容)
CI / Backend (go vet + test) (push) Waiting to run
CI / Frontend (lint + build + test) (push) Waiting to run
=== 为什么这样设计(成本优先)===
全集群 370GB/天,把日志原文丢给模型是不可能的(一次几百万 token)。
所以整条链路只做一件事:**把 GB 级日志压成 KB 级信号**。
P0 的信号来源全部是索引/快照,**零日志内容扫描**:
体积 + 趋势 → index/volume_range(实测 24h 仅 54ms)
条数/流数 → index/stats,且只在 ≤2 小时窗口用
(全天 index/stats 实测 20s,绝不能进 AI 路径)
应用排行 → 平台小时级预聚合快照(毫秒)
基线对比 → 上一个等长窗口的 volume_range
告警 → 平台投递记录
实测一次分析:3~6 秒、输入 600~1400 tokens(约 ¥0.005/次)。
=== 后端 ===
models/ai.go AIConfig(APIKey 加密存储)+ AIAnalysisRun(审计)
services/ai_config.go 读写配置、掩码返回、每日 token 用量统计
services/ai_provider.go OpenAI 兼容客户端 + 连通性测试
(DeepSeek/通义/内网 vLLM/Ollama 通用)
services/ai_redact.go 脱敏:凭据/邮箱/手机号/身份证 → 占位符,
**保留内网 IP 与端口**(排查必需)
services/ai_signal.go 信号采集 + 渲染成紧凑文本(省 token)
services/ai_analyze.go 结构化输出解析、配额闸门、审计落库
controllers/ai.go /ai/config /ai/config/test /ai/analyze /ai/runs
成本闸门(三层):
1) 单次:时间范围 ≤24h、maxTokens ≤1500
2) 每用户每日 token 上限(默认 50 万,可配,超限直接拒绝并说明)
3) 审计只留最近 500 条,避免表膨胀
=== 前端 ===
新页面 /aiops(侧栏「智能运维」,管理员),页内单层 tab:
日志分析 / 模型配置 / 分析历史
- 分析:数据源 + 时间预设(15m/1h/6h/24h) + 可选提问 → 结论/证据/建议/不确定 四区
顶部显示本次消耗(in/out tokens、耗时),可查看「发给模型的完整内容」
- 配置:启用开关、Base URL、模型、API Key(掩码)、温度、输出上限、超时、
每日配额、额外脱敏正则;按钮顺序改为「测试连接 → 保存配置」
- 历史:服务端分页(20/页),点行看详情与 payload
=== 两个真实踩坑(已修)===
1) 密码含 @ 导致脱敏漏掉(mysql://user:P@ssw0rd@host)
→ URL basic-auth 规则改为贪婪匹配到最后一个 @,由单测锁定
2) 结论里的时间是 UTC(容器无 tzdata,time.Local=UTC),
模型写"凌晨 6 点下跌"而运维当时是下午 2 点
→ 显式用东八区展示(LOKISTACK_DISPLAY_TZ=UTC 可覆盖)
=== 实测(69147008fcf4)===
配置保存 → key 掩码 sk-***e286;连通性测试返回「正常」
分析 15 分钟窗口:4.1s,结论识别出"窗口末段体积断崖约 -60%"
信号时间 14:23~14:38(本地时间正确)
历史分页 total=3,tokens/耗时字段完整
单测:脱敏 2 个用例 + 模型输出解析 4 个用例 + 6 条 AI 路由断言
|
2026-10-31 06:39:01 +00:00 |
|
opsx
|
3861b8b128
|
fix(collectors): 编辑采集策略时无法把"全集群"改成"只采几个命名空间"
CI / Backend (go vet + test) (push) Waiting to run
CI / Frontend (lint + build + test) (push) Waiting to run
=== 现象 ===
编辑 Promtail DaemonSet 采集器,显示"所有命名空间(全集群采集)",
下面每个命名空间的复选框全是灰的,点不动,无法改成只采指定几个。
=== 根因 ===
CollectorEditDialog 里单个命名空间的复选框写死了:
disabled={allSelected} // allSelected = selectedNs.length === 0
而 targetNamespaces 为空正是代表"全集群",也就是**一进来就处于全集群状态**,
于是所有子项被禁用;而"全集群"那个复选框的 handler 又是
onCheckedChange={() => setAll()} // 永远设回 []
两者叠加 → 没有任何操作能离开"全集群"状态,是死胡同。
=== 修复 ===
1. 去掉 disabled:勾任何一个命名空间都会让 selectedNs 非空,
allSelected 自动变 false,"全集群"勾选框随之取消——语义自洽。
2. "全集群"行加一句提示:勾选下方任一命名空间即可改为只采指定范围,
让用户知道下一步该点哪里。
=== 实测(51489599e2d8)===
PUT targetNamespaces=["astralx"] → 读回 ['astralx'] ✅
PUT targetNamespaces=[] → 读回 [](全集群) ✅
恢复 ['astralx','log'] → 读回 ['astralx','log'] ✅
tsc 通过;Pod = Hub latest = 51489599e2d8
注:改完需要点「部署」才会把新的 kubernetes_sd_configs.namespaces 白名单
下发到 Promtail DaemonSet。
|
2026-10-31 02:00:33 +00:00 |
|
opsx
|
9448868a71
|
feat(collectors): Promtail DaemonSet 的部署命名空间固定为 log,表单隐藏该字段
CI / Backend (go vet + test) (push) Waiting to run
CI / Frontend (lint + build + test) (push) Waiting to run
=== 需求 ===
创建 Loki 部署后添加采集策略(Promtail DaemonSet)时,"部署节点命名空间"
不该让用户选 —— 采集器必须和 LokiStack 放在一起(log)。
=== 前端 ===
CollectorFormDialog:选择 k8s-daemonset 时整块隐藏 namespace 字段
(连同分类型提示、手动输入开关一起),改为一条只读说明:
「采集器部署命名空间固定为 Loki 所在命名空间(通常 log),与 LokiStack
放在一起,无需选择。要限制采集范围请用下面的『只采集这些命名空间』。」
提交时 DaemonSet 不传 namespace(原来会传用户填的值)。
顺带修掉隐藏后暴露的 tsc 报错:placeholder 里 `collectorType === 'k8s-daemonset'`
在收窄后的分支里已成不可能比较,改为常量 'default'。
=== 后端(强制约束,不只靠前端)===
services/collector.go:
Create:type == k8s-daemonset 时强制清空 req.Namespace
→ 渲染与部署两侧都会回退到 d.loki.Namespace
Update:DaemonSet 忽略 updates["namespace"]
原始渲染逻辑本就有"为空则用 LokiDeployment.Namespace,再兜底 log"。
为什么后端也要拦:API 直接调用(脚本/其他客户端)不该能把采集器
部署到任意命名空间——那样会出现"平台显示在 log、实际 DaemonSet 在别处"
的状态漂移。
=== 实测(0108617e4180)===
现有采集器 promtail-pre: type=k8s-daemonset namespace='log'
PUT {"namespace":"evil-ns"} → 返回 success,但读回仍是 'log' ✅ 被忽略
tsc 通过;Pod = Hub latest = 0108617e4180
|
2026-10-31 01:56:15 +00:00 |
|
logan
|
2e97c04f84
|
fix(db): 修复 NextID 与写锁重入死锁
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
- NextID 改用独立 seqMu,不再依赖数据写锁,杜绝 Lock 内调用 NextID 的死锁
- CaptureAppVolumeForHour 先取 ID 再 Lock
- 新增写锁看门狗:长时间占用时转储 goroutine 栈
- 新增 TestNextIDWhileWriteLocked 回归测试
|
2026-10-31 02:20:34 +08:00 |
|
opsx
|
f1fc7b4a9a
|
fix(analysis): 排行分页后名次从 1 重新开始,应为 11/21…
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
现象:翻到第 2 页,名次列仍是 1~10。
根因:TopAppsTable 用页内下标算名次(index + 1),分页后每页都从 1 开始。
修复:新增 startIndex 参数,由调用方传入当前页在整体排行中的偏移;
分析页传 (page - 1) * 10,于是第 2 页为 11~20、第 3 页 21~30。
实测:tsc 通过;Pod = Hub latest = 9026d0e4c582
|
2026-10-30 17:50:54 +00:00 |
|
opsx
|
fdd705c4b4
|
build(release): release.sh 加独占构建锁 + push 重试,杜绝 latest 被并发覆盖
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
=== 问题 ===
本项目所有清单都指向 `latest`(k8s deployment / docker-compose / prod compose),
两个构建并发时**谁后完成谁生效**,另一个的推送等于白做。
本次实际踩到:一次被中断的构建后来完成,把 latest 推回了旧镜像 64fb231,
而当前正确版本是 a16978d2;若此时 Pod 重启就会跑回旧代码,
表现是"改了但没生效",从页面完全看不出来。
=== 修复 1:flock 独占锁 ===
LOCK_FILE=${RELEASE_LOCK_FILE:-/var/lock/lokistack-release.lock}
exec 9>"$LOCK_FILE"; flock -n 9 || { 中文提示 + exit 1 }
- 锁跟随文件描述符,进程退出(含 Ctrl-C / set -e 中断)自动释放,
不需要手工清理僵尸锁文件
- 失败提示给出:锁路径、查看占用命令(fuser/lsof)、以及"无需手工删锁"的说明
- 支持 RELEASE_LOCK_FILE 换锁路径(多仓库并行发布时用)
- 新增 --dry-run:只做前置检查(docker 是否可用、锁能否获取),不构建不推送,
用于验证脚本本身和排查"为什么发布失败"
=== 修复 2:push 重试 ===
Docker Hub 偶发 502,实测导致过"v0.1 推成功、latest 失败 → latest 指旧镜像"。
新增 push_with_retry():每个 tag 最多 3 次,间隔 10 秒,全失败才 exit 1。
三个 tag(latest / v0.1 / 不可变 tag)都走它。
=== 实测 ===
测试1 无人占用 : 🔒 获取锁成功,退出码 0
测试2 另一进程持有锁 : ❌ 明确拒绝并给出排查命令,退出码 1
测试3 占用进程退出后 : ✅ 自动恢复可用,退出码 0
bash -n 语法检查通过
|
2026-10-30 17:48:20 +00:00 |
|
opsx
|
d4422f1541
|
refactor(analysis): 去掉排行 10/30/50 选择器,改为一次取 50 + 前端分页;零点结算昨天
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
=== 1. 为什么去掉「显示条数」选择器 ===
topk 的 N 不影响查询成本(扫描的 chunk 集合完全相同),实测:
topk(10) 17833ms / 11 条
topk(30) 18019ms / 34 条
topk(50) 7394ms / 54 条
topk(100) 17553ms / 74 条
波动来自集群负载,与 N 无关 —— 它只决定最后返回多少序列。
所以"选 30"既不更快也不更慢,本质是个翻页开关;
而选它还要重新等一次十几秒的查询,纯亏。
改为:一次 topk(50),前端 10 条/页 → 5 页只需 1 次查询。
附带收益:占比的分母从"前 10 合计"变成"前 50 合计",更接近真实占比。
副标题明确写清"一次取前 50 个应用(占比按这 50 个合计计算)"。
=== 2. 零点结算昨天(daily volume)===
原来只有 30 分钟 ticker 回补,且启动时间不对齐整点 →
昨天最早的一段可能已经超出 Loki 24h 保留期被删,
结算结果系统性偏低,图上却标"完整一天",属静默错数。
新增 nextMidnightFinalize():每天 00:01 触发 FinalizeYesterdayVolume()
- 昨天定稿 partial=false
- 补一次条数(index/stats,一天一次可接受)
- 顺带刷新今天 partial=true 的柱子
ticker 仍保留,负责当天数据的 30 分钟刷新。
=== 3. 顺带 ===
- 去掉每日量"其中 N 天平台没有留存记录"的提示文案(按用户要求)
- 修 QuickQueryTemplates.tsx 的未使用变量导致 tsc -b 失败
- 工作区里上一轮中断的"排行体积列"改动一并纳入(app-ranking 返回 bytes,
TopAppsTable 增加体积列,快照记录 per-app 字节数)
Pod = Hub latest = a16978d2f88b
|
2026-10-30 17:13:18 +00:00 |
|
opsx
|
63dd491c5b
|
fix(daily-volume): 历史快照的 partial 自动修正 + 三个回归测试
=== 现象 ===
仓库里 6 条快照 partial 全是 true(10-27 到 10-30),前端把昨天的柱子
也画成虚线空心,看着像"每天都在采样中"。
=== 根因 ===
早期实现把两件事都塞进 partial:「今天还没过完」和「起点超出 24h」。
10-27/10-28 的数据现在已经被 retention 删掉、永远不会再被抓一次,
所以这两条错误标记会永久留在库里。
=== 修法 ===
prune 里加幂等修正:过去的天,只有快照是**在那天结束之后**才抓的
(说明抓到的是完整一天)才改成 partial=false;当天中途抓的继续保持 partial
(那时确实只有半天,不能伪装成完整数据)。
=== 测试(3/3 PASS)===
TestPruneDailyVolumeNormalizesPartialAndDropsExpired
· 昨天结束之后抓的 → partial=false
· 前天中途抓的 → 保持 partial=true
· 今天 → 保持 partial=true
· 超留存期 → 被清理
· 条数不被清理流程清空
TestUpsertVolumeSnapshotKeepsEntries 刷新体积不清空已抓到的条数
TestGetDailyVolumeHistoryReturnsAllDaysWithMissing 始终返回 days 个点,缺的标 Missing 不伪造 0
go vet ./services/ ./models/ 干净;go test ./services/ 全绿。
|
2026-10-30 16:56:39 +00:00 |
|
opsx
|
b7de337c9e
|
perf(daily-volume): 每日量抓取拆成「体积每 30 分钟 / 条数每天最多 3 次」
=== 现象 ===
用户问:每日日志量不是有定时任务记录吗?为什么还要每次查询?
盘了一遍发现:定时任务确实有(每 30 分钟),接口也确实只读库(实测 0.1ms),
但每轮抓取都顺手跑一次**整天 index/stats** 拿条数(实测 6ms ~ 20s,随负载波动),
2 天 × 多个数据源 × 每 30 分钟 = 一天几十次重查询,纯浪费单实例 Loki 的算力,
还会和用户页面上的查询抢 CPU。
第二条更糟:仓库里所有快照的 partial 全是 true。
根因:partial 里混了两种语义 ——「今天还没过完」和「起点超出 24h」。
后者让昨天/前天的柱子也画成虚线空心,看起来「每天都在进行中」。
=== 修法 ===
1. 抓取按成本拆成两条路径(体积走 volume_range,条数走 index/stats):
- 体积:今天 + 昨天,每 30 分钟刷,54ms~4s,无感
- 条数:只对**已结束**且 entries==0 的天补,每天最多 3 次、间隔≥1h;
尝试次数**先写库再查**,进程中途被杀也不会退化成每 30 分钟重试
2. partial 只表示「今天还没过完」,昨天起是实心柱
3. 0 与「未留存」分开:起点超出 24h 且查不到数据 → **跳过落库**保持 Missing。
否则「数据被 retention 删掉」会被画成「那天没有日志」,比灰色柱误导得多
4. 每次抓取打日志:`[daily-volume] 2026-10-30 体积 291.37 GB 已落库(volume_range 4.27s,34 个桶)`
—— 以后不用猜「到底抓没抓、走的哪条路径」
=== 实测取证(本集群)===
Loki 直接查(port-forward :13100):
10-30(16.8h) volume_range 291.37GB/34桶 index/stats entries=2.21B
10-29(24h) volume_range 121.99GB/19桶 index/stats entries=927.9M
10-28/10-27 volume_range 0 桶、index/stats 0 —— 已被 retention 删掉
同范围 count_over_time 两次 60s 超时(永远别用在每日量上)
平台库里的快照与上述数字一致(288.32 / 121.75 GB),说明落库值可信;
10-27/10-28 的 34.87/25.65 GB 是当时抓的 —— 这正是「Loki 只留 1~3 天,
历史必须自己落库」的实证。
go vet ./services/ ./models/ 干净;go build 通过;go test ./services/ 通过。
|
2026-10-30 16:52:55 +00:00 |
|
opsx
|
e4cefa1fa7
|
feat(analysis): 应用排行支持 10/30/50 切换 + 前端分页
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
=== 可行性评估(先实测再实现)===
topk 的 N 是否影响查询成本?5 分钟窗口实测:
topk(10) 17833ms / 11 条
topk(30) 18019ms / 34 条
topk(50) 7394ms / 54 条
topk(100) 17553ms / 74 条
波动来自集群负载,与 N 无关 —— 扫描的 chunk 集合完全相同,
topk 只决定最后返回多少序列。所以放宽到 50 不增加查询成本。
=== 分页为什么不每页发一次查询 ===
排行是"排序后的聚合结果":要拿第 11~20 名,必须先算出全部应用的量再排序,
不存在"只算 11~20 名"的做法。所以正确设计是:
topk(N) 一次取全 → 前端按 10/页切片
N=50 时 5 页,只查 1 次;每页点一次查询反而会重复扫同一批 chunk,纯浪费。
=== 实现 ===
- hook 参数 rankLimit(10/30/50),两条查询都包 topk(N)
- 分析页:显示条数按钮组,点击即触发查询(同时重置到第 1 页)
- 分页条:共 N 个应用 · 第 x/y 页 · 上一页/下一页
- 长范围走预聚合时,limit 也跟随 N(接口上限 100)
- 切换筛选(刷新)时重置到第 1 页
Pod = Hub latest = 4d4e1a7ec334
|
2026-10-30 16:51:21 +00:00 |
|
opsx
|
7b1ffd0274
|
fix(daily-volume): 30/90/365 天切换"没反应";/logs/stats 加短缓存
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
=== 1. 切换范围没反应(真 bug)===
现象:7/30/90/365 天切换后图完全一样。
根因:GetDailyVolumeHistory 只返回**已抓到的快照**。平台只有 4 天数据,
所以任何 days 都只返回 4 个点 → 图表一模一样。
修复:始终返回 days 个点,缺失的天用 Missing=true 标记。
实测:days=7→7 点(缺3)、30→30 点(缺26)、90→90(缺86)、365→365(缺361)。
为什么必须区分 Missing 和"0 字节":
前者是"平台没留存",后者是"那天确实没日志"。
混在一起会让 30/90 天的图上出现大片 0,被误读成"日志量暴跌/系统停摆"。
前端:缺失的天画灰色浅柱,tooltip 显示"未留存",图下方提示
"其中 N 天平台没有留存记录(灰色柱),不是当天没有日志"。
=== 2. /logs/stats 加 90 秒缓存 ===
分析页每次进入/切范围都打 index/stats,实测 5 分钟窗口冷查询 1.2 秒
(60 分钟更慢)。这类聚合值可容忍分钟级陈旧,加与指标查询一致的缓存:
90s TTL + 时间窗按 2 分钟取整 + 上限 200 条 + 过期清理
实测:重复请求 1227ms → 8ms。
=== 3. 顺带确认已生效的优化 ===
histogram(24h) : 54ms(volume_range)
daily-volume : 10ms(只读库)
stats 二次请求 : 8ms(新缓存)
长范围(>1h) : 不跑 count_over_time(预聚合快照 + 跳过内容扫描)
Pod = Hub latest = 12453ea723c1
|
2026-10-30 16:46:40 +00:00 |
|
opsx
|
5c7a3ec81d
|
perf(daily-volume): 每日量改用 volume_range(20s → 54ms),图表改圆柱
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
=== 核心技巧:体积用 index/volume_range,不要用 index/stats ===
同为 24 小时、同一 selector,两条索引查询差 370 倍:
index/stats : 整天聚合,实测 20s 直接超时(之前每日量接口卡 20s 的根因)
index/volume_range: 按 step 分桶只累加 chunk 字节,实测 54ms,97 个桶
原因:index/stats 要跨全部 chunk 去重统计 streams/entries;
volume_range 只把索引里记录的 chunk 字节数按时间桶求和,不解码内容。
=== 后端改动 ===
services/daily_volume.go:
体积:LokiHistogram(走 volume_range,step 由跨度自动选)→ 累加 54ms
条数:只能 index/stats,降级为「尽力而为」25s 超时;
拿不到就保留上一次的值(不能因为一次超时把历史条数清零),
绝不让它拖住体积入库。
前端图只画体积,条数缺失不影响可读性。
=== 前端改动 ===
DailyVolumeChart:AreaChart(面积)→ BarChart(圆柱)
顶部圆角 radius=[6,6,0,0]、渐变填充、maxBarSize=44
当天未结束的柱子用半透明 + 虚线描边区分,避免把"才过半天"误读成"量掉了"
=== 实测 ===
24h volume_range: 54ms,97 桶,合计 369.61 GB(与全集群 ~370GB/天 吻合)
/logs/daily-volume 接口: 10ms(读库)
Pod = Hub latest = 4cdc8b9c4841
|
2026-10-30 16:40:49 +00:00 |
|
opsx
|
d0adc095dd
|
feat(analysis): 长范围应用排行改走「小时级预聚合」,不再扫日志内容
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
=== 问题(实测)===
按应用排行必须读日志内容(Loki 3.4 的 index/volume 不支持 app 维度聚合,
aggregateBy=app 无效),成本 ∝ 时间范围:
5 分钟 ≈ 1.3GB → 9.8s
15 分钟 ≈ 3.9GB → 19.5s
1 小时 ≈ 15GB → 预计 60~90s
6 小时 ≈ 92GB → 5~8 分钟
24 小时 ≈ 370GB → 不可用
用户在时间范围里选 6h/24h 时,页面必然卡死。
=== 方案 ===
新增 models.AppVolumeSnapshot + services/app_volume.go:
- 后台任务每小时第 5 分钟抓「上一个完整小时」的 per-app 条数
- 用**瞬时查询**(/loki/api/v1/query + [1h])而不是 query_range:
单点评估、扫描量相同、省掉多步开销;并绕开 LokiMetrics 的 90s 上限
与重型查询信号量(后台任务不该和前台抢令牌)
- 每源每小时只留 top 50 应用,保留 90 天
- 幂等:同 (hour, source, ns, app) 更新而非重复插入
- 超出 Loki 26h 保留期的窗口跳过(抓也抓不到,白等几分钟)
新增 GET /api/v1/logs/app-ranking?sourceId&from&to&limit → 读库毫秒级
前端:analysis 判断范围 > 60 分钟就走预聚合接口,并停掉实时重查询
(rankingEnabled 置 false);表格副标题说明「读的是预聚合快照,已留存 N 小时,
不含错误数与趋势」。
=== 顺带修掉的根因 bug ===
useInView 原来用 useRef + useEffect([inView]):分析页首屏 data===null 时
内容块不渲染,ref.current 为 null,effect 直接 return;等数据到了 DOM 才挂上,
但依赖没变 → effect 不重跑 → IntersectionObserver 从未创建 → inView 永远 false
→ 重查询永不发出 → 页面一直显示"没有应用维度的数据"。
改成 callback ref(节点挂载即作为依赖),并加 scroll/resize 兜底 + 挂载瞬间量一次。
另外分析页加 8 秒无条件兜底:可见性判定再失灵,8 秒后也一定查一次。
默认时间范围 15 分钟 → 5 分钟(19.5s → 9.8s)。
=== 实测 ===
Pod = Hub latest = 98de87e7f895
5 分钟窗口 by-app:9.8s(75 序列);15 分钟:19.5s
|
2026-10-30 16:35:35 +00:00 |
|
opsx
|
7f6fb364de
|
refactor(analysis): 移除重复的「应用日志量流图」与「Top 5 饼图」,并按需触发重查询
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
=== 为什么这两个可以去掉(不是拍脑袋)===
排行表已有 9 列:排名 / 应用 / 命名空间 / 日志量 / **占比** / 错误数 /
错误率 / 趋势(sparkline) / 操作(查看日志)。
- Top 5 饼图 = 应用 + 数量 + 占比 —— 表里全都有,且表里更多
- 流图 = 各应用随时间的堆叠 —— 表里每行已有 sparkline 趋势
两者都是同一份 by-app 数据的重复呈现,纯增加视觉噪音。
=== 但"去掉它们"本身不减查询,真正的减负在这一步 ===
之前这三个组件都依赖同一条 by-app 重查询(10~15 秒)。
因为饼图/流图在首屏,所以那条查询只能一进页面就全量跑(rankingEnabled=true)。
现在图都没了,重查询只服务底部排行表 → 恢复可见性门控:
rankingEnabled: rankingView.inView
效果:打开分析页只跑索引类查询(histogram/stats/daily-volume,均 <100ms),
用户滚到排行卡才发那条重查询。
「活跃应用」卡片在未统计时显示 —(原来显示 0 个,容易误读成"没有应用")。
=== 布局 ===
趋势图从 2/3 宽改为整行,页面高度明显下降。
=== 实测(ddf63053b952)===
Pod = Hub latest = v0.1 = ddf63053b952
NamespacePie / AppStreamChart 在页面中引用数均为 0
|
2026-10-30 16:15:44 +00:00 |
|
opsx
|
3b297d0429
|
feat(collectors): 采集项支持「表单 / YAML」双模式编辑(方案 A)
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
=== 设计边界(刻意不做"编辑完整 promtail.yaml")===
开放的是**采集项本身**的 YAML 表示(字段与 models.ScrapeJob 一一对应):
name / paths / labels / encoding / json / system
multiline(firstline,maxLines) / timestamp / dropIfMatch / rateLimit
clients、positions、server、scrape_configs 外层仍由平台生成。
理由(真实故障面):
用户删掉 positions → 重启后从头重采,大量重复 + Loki 以
entry too far behind 拒绝整批;删掉 clients → 完全不外发。
这两类问题在页面上看不出来,只能登机器看日志,排障成本极高。
只开放采集规则,写坏了最多某条日志没采到,不会让采集器整体失效。
=== 后端 ===
新增 services/collector_jobs_yaml.go:
RenderJobsYAML(jobs) → 带边界说明注释的 YAML(明确写"clients/positions 不在此修改")
ParseJobsYAML(text) → 复用 models.ValidateScrapeJobs,与表单完全同一套校验
错误信息必须具体:
YAML 语法错 → 「YAML 语法错误:yaml: line 1: did not find expected ',' or ']'」
语义错 → 「采集项「app」至少需要填写一个日志路径」
新增路由(用 /collector-jobs/* 前缀,避开与 /collectors/:id 的 gin 通配冲突):
POST /api/v1/collector-jobs/render
POST /api/v1/collector-jobs/parse
=== 前端 ===
编辑弹框(主机模式)加「表单 / YAML」切换:
- 切到 YAML:调 render 把当前采集项渲染出来
- 切回表单:调 parse 回填;解析失败**留在 YAML 模式**并显示原因
(绝不能悄悄丢掉用户改动)
- 停留在 YAML 模式点保存:先 parse,失败则中止保存
- 编辑区 min-h 固定、等宽字体、可拖拽高度
=== 测试 ===
TestRenderParseJobsYAMLRoundTrip:
表单→YAML→表单 无损往返,逐字段核对
(multiline.maxLines / rateLimit / dropIfMatch / timestamp / labels / system)
TestParseJobsYAMLErrors:空内容、语法错、空列表、缺名称、缺路径、名称非法
→ 6 种输入都给出具体错误,不是笼统"格式错误"
=== 实测(c11d2badce64)===
render: code=0,17 行,含边界说明
parse : code=0,1 个采集项;往返校验 name=app paths=1 multiline=True
rateLimit={rate:2000,burst:4000} drop=1 json=True
错误: 「采集项「app」至少需要填写一个日志路径」
「YAML 语法错误:yaml: line 1: did not find expected ',' or ']'」
Pod = Hub latest = c11d2badce64
|
2026-10-30 16:10:51 +00:00 |
|
opsx
|
c8d026adc7
|
feat(collectors): DaemonSet 不再填日志路径,改为「只采集哪些命名空间」多选
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
用户指出的三个问题,逐条核实后的结论:
1) 「采集日志路径」对 DaemonSet 确实是多余的 —— 确认后端模板里写死了
`replacement: /var/log/pods/*$1/*.log`(按 pod UID 精确匹配容器标准输出),
表单里填的 logPath 对 DaemonSet 完全不参与渲染。
→ 选择 DaemonSet 时隐藏该字段,提交时强制置空。
2) 「可以指定采集多个命名空间」—— 后端**早就支持**:
models.Collector.TargetNamespaces + promtailNamespaceFilter(),
空数组 = 全集群。只是**前端新建弹框没暴露**(编辑弹框里有)。
→ 新建弹框补上多选 chips(全集群 / 各命名空间可点选),并补齐前后端透传:
dto.CreateCollectorRequest.TargetNamespaces
controller → services.CreateCollectorRequest.TargetNamespaces
models.Collector.TargetNamespaces
之前前端即使传了也会被 Go 静默丢弃(无该字段)。
3) 「命名空间」字段语义已在上一提交补了分类型说明:
- DaemonSet:采集器自身部署在哪个命名空间(不影响采什么)
- Sidecar:目标应用 Deployment 所在命名空间
新增 TestDaemonsetTargetNamespacesFilter:
nil → 不生成 namespaces 白名单(全集群)
["astralx"] → 生成且包含 astralx
["astralx","default"] → 两个都在
=== 实测(d45dfa18ecc5)===
前端文案「只采集这些命名空间」「不选 = 采集整个集群…」均已进包
渲染测试 3 种输入全部符合预期
注:本次 docker push latest 遇到 Docker Hub 502,v0.1 成功而 latest 仍指向旧镜像,
导致首次滚动后 Pod 仍是旧代码;重推 latest + 强制重建 Pod 后确认
Pod digest = d45dfa18ecc5 —— 记录这个坑:push 失败必须核对三方 digest。
|
2026-10-30 16:03:24 +00:00 |
|
opsx
|
87909ed403
|
docs(collectors): 采集策略弹框「命名空间」补分类型说明
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
用户困惑:这个字段到底是"只采集指定命名空间"还是"组件要部署的命名空间"?
查代码后确认——**同一个字段在三种采集类型下含义完全不同**:
k8s-fluentbit-sidecar:
= 目标应用 Deployment 所在的命名空间。
平台会 Deployments(ns).Get(target) 然后 patch 注入 fluent-bit sidecar,
同时把它作为日志的 namespace 标签。
**不是**日志过滤条件。
k8s-daemonset:
= Promtail DaemonSet 部署到哪个命名空间。
DaemonSet 挂载 /var/log/pods,采集**整个集群所有命名空间**的容器日志,
不按命名空间做过滤。一般就填 Loki 所在的 log。
host-promtail:不使用该字段。
原来这三种情况共用一句"命名空间",用户只能猜。
现在字段下方按类型显示对应说明(min-h-4 固定高度,不抖动)。
实测:三条提示文案均已进包(6fe430f59eef)。
|
2026-10-30 15:53:08 +00:00 |
|
opsx
|
a14bdb5e07
|
fix(analysis): 每日量不再懒加载;按应用统计期间显示 loading(不再假装"没有数据")
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
用户的三个现象,对应三个独立缺陷:
=== 1. 每日日志量"一直没数据" ===
接口只读平台库,实测 **10ms**,却仍被 inView 懒加载门控。
ref 虽然挂在 DOM 上,但滚动判定在多层布局里不可靠 → enabled 一直 false
→ 请求根本不发 → 页面显示"暂无历史数据"。
改为:只要有数据源就加载(enabled = Boolean(sourceId))。
这个接口 10ms,没有任何理由懒加载。
=== 2. 排行/流图"打开没有数据,等很久也没 loading" ===
按应用统计要 10~15 秒(读日志内容,物理下限)。
但 loading 是**整页共用**的:索引类指标 100ms 就回来、
重查询还在跑时 loading 就已经变 false,
卡片于是渲染成"没有应用维度的数据"——用户以为查完了、没数据。
改为:
- 新增 appsLoading,专门标记"按应用统计"这段重查询
- 卡片在 appsLoading 期间显示 spinner + "正在按应用统计…"
- loading 与 appsLoading 都在 finally 清理(成功/失败/取消都清)
=== 3. data 为 null 时整页空白 ===
原来 `) : !data || !sourceId ? null : (` 直接 return null,
首屏或重查询异常时是**整页空白**,和"没数据"无法区分。
改为显示 spinner + "正在按应用统计(需读取日志内容,通常 10~30 秒)"。
=== 关于"用 Go 定时任务统计每日总量"===
这个机制**早就存在**(services/daily_volume.go):
- 启动 20s 后回补 + 每 30 分钟一次 ticker
- 用 index/stats 取整天的条数与字节,**不读日志内容**,通常秒级
- 快照写入平台库,保留 400 天
实测当前库内已有 4 天数据(10ms 返回):
2026-10-27 32.5 GB
2026-10-28 23.9 GB
2026-10-29 133.6 GB
2026-10-30 239.3 GB
问题只在"前端没去请求",不在采集侧。
实测(df3b477e6740):每日量接口 10ms 返回 4 天,Pod 1/1 Running。
|
2026-10-30 15:49:52 +00:00 |
|
opsx
|
419a81c2af
|
perf(loki): 查询并行度改为自动跟随 CPU 核数(不再硬编码)
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
=== 问题 ===
max_query_parallelism 原来是硬编码值,改过两轮(8 → 6):
- 8:4 核机器上 76% 调度周期被限流,label values 要 20 秒
- 6:仍然高于核数,25% 周期限流,查询并没有更快
根因不是"该填几",而是**并行度只有一个正确值:等于 CPU 核数**。
把它做成可配置项反而是坑 —— 用户改了 CPU 忘了改并行度就出现错配。
=== 做法 ===
新增 queryParallelism(resourcesCPU):
- 从部署记录的资源规格推导,模板渲染成 {{ .QueryParallelism }}
- 容错:支持 "4000m"/"500m" 毫核写法(向上取整)
- 边界:低于 2 核按 2,高于 12 核按 12(再高频只会互相抢 CPU)
- 非法值/空值回退 4
用户在「组件部署」里改 CPU,并行度自动跟随,页面上不需要新字段。
=== 实测(4 核 + 并行 4)===
by-app(15m) 11913ms 75 条序列 (并行 6 时 12438ms)
label/namespace 38ms
label/app 25ms
label/pod 25ms
限流 61/252 周期(仅重查询那几秒)
附带 TestQueryParallelism 覆盖 10 种输入(含毫核/越界/非法值)。
|
2026-10-30 15:41:38 +00:00 |
|
opsx
|
ad0d35f72a
|
feat(alerts,logs): A 方案—告警窗口 15m→5m 消重复扫描;数据源可编辑/删除且删后不被自动重建
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
=== 1. 告警窗口 15m → 5m(阈值同比例 1/3)===
背景:检查间隔已改 5 分钟,但规则窗口仍是 15 分钟 ——
同一个 15 分钟窗口每 5 分钟被完整重扫一遍,等于 3 倍重复扫描。
在 370GB/天、全命名空间 selector 下,这是 Loki CPU 的最大稳态来源。
FATAL 10 → 4 窗口 5m
Go panic 10 → 4 窗口 5m
JVM OOM 5 → 2 窗口 5m
StackOverflow 5 → 2 窗口 5m
应用错误激增 100000 → 35000 窗口 5m(改名 error > 3.5万)
ingress 5xx 2000 → 700 窗口 5m
ingress 4xx 20000 → 7000 窗口 5m
DB 连接失败 1000 → 350 窗口 5m
阈值按 1/3 缩放是必须的:窗口缩短 3 倍后,同样的流量在 5 分钟内只有
1/3 的条数,阈值不动就永远打不到了。
迁移 v10→v11 只改"窗口仍是 15 且名字匹配内置规则"的项,用户手调的不动。
=== 2. 数据源支持编辑/删除(含托管源)===
原来前后端都把托管源锁死:
- 前端 `!managed &&` 直接不渲染编辑/删除按钮
- 后端 DeleteSource 返回「平台部署的数据源随部署管理,请先删除对应部署」
用户的诉求是"数据源必须能编辑和删除",且确实有场景(不想让某个源出现在
查询下拉里、想改认证头)。
=== 3. 修「删了又回来」的真 bug ===
EnsureLogSourcesForRunningDeployments() 在 **每次打开数据源列表和启动时**
都会给 running 部署补齐数据源 —— 所以删掉托管源后,刷新页面它又回来了,
用户看到的现象就是"删不掉"。
新增 LokiDeployment.AutoSourceDisabled:
- 删除托管源时置位(DisableAutoSourceFor)
- EnsureLogSourceForDeployment 见到该开关直接 return
- 部署被编辑/重新部署时重置(EnableAutoSourceFor),即"你要用它了就恢复"
前端配套文案:
- 编辑托管源弹窗提示"重新部署会覆盖集群/Service/端口,认证与请求头保留"
- 删除确认明确"删除后不会再自动重建,重新部署该 Loki 才恢复"
=== 实测(20300eef92d2)===
v11 迁移后 8 条规则全部 窗口=5m,阈值 4/4/2/2/35000/700/7000/350
go test ./... 全绿
|
2026-10-30 15:28:30 +00:00 |
|
opsx
|
c9e604b35f
|
perf(logs): 修 label 下拉 20 秒、Loki CPU 限流 76%、告警检查频率
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
1) Loki CPU 限流 76%(limits 4 核,实测 3923m,nr_throttled 920656/1209379)
→ limits 提到 8 核 / requests 2 核。限流归零,histogram 84ms,
by-app 从 60s 超时降到 14.9s。
2) label values 未传时间范围 → Loki 默认扫 6 小时索引(370GB/天 → 10~21s)
→ 默认只查最近 1 小时。实测 namespace 21330ms→33ms,app 24781ms→30ms。
3) max_query_parallelism 8 > 实际核数 → 调到 6。
4) 告警检查 1 分钟 → 5 分钟(规则窗口本身 15 分钟,稳态负载降到 1/5)。
|
2026-10-30 03:42:03 +00:00 |
|
logan
|
7624baa564
|
feat(logs): 数据源连接方式自动探测
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
部署完成及启动时实测 cluster-svc(API proxy) 与 url 直连,
选择可用方式并落库,兼容平台/Loki 分别在主机或集群内的组合。
|
2026-10-30 01:23:45 +08:00 |
|
logan
|
b433b5f9dd
|
fix: 删除操作清理远端资源并拦截悬空引用
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
- 部署删除: k8s 模式清理 StatefulSet/Service/ConfigMap 与 PVC,先卸载关联采集器
- 采集器删除: 同步卸载成功后再删记录,失败保留避免孤儿
- 集群/存储/主机删除: 有部署或采集器引用时拒绝,避免悬空外键
- Token RBAC 补 services/proxy,保证 cluster-svc 数据源可查询
|
2026-10-30 01:17:26 +08:00 |
|
logan
|
56e1245b70
|
fix(logs): 启动时清理孤儿托管数据源
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
旧版本删除部署后残留的 managed 数据源无法通过 API 删除
(提示随部署管理),启动时按部署名/集群存在性统一清理,
并把默认源转移到剩余数据源。
|
2026-10-30 01:10:15 +08:00 |
|
opsx
|
e6c0cf134f
|
test(routers): 路由断言跟上上游变更(备份恢复已移除,补保留期读写)
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
上游 commit f87fb4b 移除了备份恢复功能(/system/backup、/system/restore),
我上一轮加的路由守卫测试仍在断言 /system/backup 存在,导致 go test 失败。
调整为当前真实 API 面:
- 移除 /api/v1/system/backup 断言
- 补 GET/PUT /api/v1/settings/retention(保留期读写)
- 保留 /api/v1/system/self-check
实测:go test ./routers/ → ok
|
2026-10-29 17:02:09 +00:00 |
|
opsx
|
48e68250bb
|
feat(docs): 用户手册接入界面截图
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
- 6 张核心页面截图(仪表盘/向导/日志查询/日志分析/告警/设置)存 docs/assets/screenshots,
随发布包分发;产品介绍页新增「界面预览」两列网格,各功能页顶部内嵌对应截图
- goldmark 开启 WithUnsafe 以渲染网格 HTML(文档自维护,无注入面);截图经 DOM 校验全部加载成功
|
2026-10-29 16:36:21 +08:00 |
|
opsx
|
e579eabe48
|
fix(wizard): 存储步骤去掉推荐文案;空态列表补腾讯云对象存储(COS 后端早已支持)
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
|
2026-10-29 16:20:34 +08:00 |
|
opsx
|
c4d907fd27
|
docs: 安装与启动 → 快速安装
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
|
2026-10-29 16:11:16 +08:00 |
|
opsx
|
bbeb9d0b28
|
docs: AGENTS/CLAUDE 同步密钥自动生成行为
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
|
2026-10-29 16:09:16 +08:00 |
|
opsx
|
65bb29aa72
|
feat(config): 密钥自动生成下沉到后端 + 安装文档极简化
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
- resolveSecrets 统一所有部署形态的零配置体验:显式 env 优先 → DATA_DIR/.secrets.env
→ 自动生成随机密钥持久化(0600,重启不变);无法持久化才拒绝启动(单测覆盖生成/复用/显式优先)
- install.md 重写为三方式各一条命令(K8s install.sh / docker compose up -d / release 包),
密钥与数据说明收敛到统一「说明」一节;README Docker 段同步精简
|
2026-10-29 16:07:58 +08:00 |
|
opsx
|
88b2ac2a6d
|
feat(install): 一键安装脚本 — 对标 1Panel/雷池体验
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
bash -c "$(curl -fsSL …/scripts/quick_start.sh)" 一条命令:
架构自检(x86_64/arm64)→ 发布包下载(默认 Gitea Release,可镜像)→ 随机密钥生成持久化
→ systemd 开机自启 → 健康等待 → 打印访问地址/初始密码/常用命令;重复执行即升级(数据自动备份)。
CentOS 7 真机验证:安装、登录、文档/落地页、升级幂等全通。
配套 upload-release.sh(make dist 后一键发布双架构包到 Gitea Release);README/手册/CHANGELOG 同步。
|
2026-10-29 16:05:40 +08:00 |
|
opsx
|
0936234623
|
feat(install): 零输入一条命令部署 + 双架构发布包
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
- docker compose up -d 直接启动:entrypoint 在未显式提供密钥时自动生成随机
JWT_SECRET/ENCRYPTION_KEY 并持久化到数据卷 .secrets.env(0600,重启不变),
显式环境变量优先(单显式不被持久化文件覆盖,四场景实测);compose 去掉 :? 强制
- build.sh --dist / make dist:linux amd64 + arm64 两个 tar.gz(二进制+docs+homepage+README),
实测 15M/13M;安装文档重写为三方式(kubernetes/install.sh 一键、compose 一条命令、release 包)
- README 快速开始同步
|
2026-10-29 15:50:50 +08:00 |
|
opsx
|
437ff56992
|
feat(docs): 文档站重制 — 参照 opsxapi/opsxshell 体系,服务端渲染三栏布局
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
- 后端 goldmark 渲染管线:/docs/:slug 页面 + /docs/search-data.json 搜索索引,
manifest.json 驱动分组导航,正文剥 H1 避免与页面头重复
- 三栏布局(分组侧栏/内容/本页目录)+ 顶栏(品牌/版本徽章/搜索面板/官网入口),
docs.css 品牌绿版 + docs.js(代码复制/轻量高亮/提示块/TOC 滚动高亮/移动端抽屉)
- 替换 docsify;无上一页时空占位无边框;visual-judge 两轮评审(初版 fail → 修复后 pass)
|
2026-10-29 15:30:25 +08:00 |
|
opsx
|
c1f822fb10
|
refactor: 移除资源用量的可选 Prometheus 接入与平台监控页
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
- 资源用量弹窗:删除 applyPrometheus/promQueryValue 与峰值/限流字段
(LOKI_USAGE_PROMETHEUS_URL 从未内置,代码恒走降级),统一提示
「未接入 Prometheus:暂无峰值/限流数据」;扩容建议改基于 metrics-server 实时值
- 移除「平台监控」菜单页与 /api/v1/system/metrics-summary;
原始指标保留在标准 /api/v1/metrics(Prometheus 文本格式)可自行抓取
- 手册/落地页/CHANGELOG 同步(去除备份恢复与监控页宣传,指标端点表述中性化)
|
2026-10-29 15:16:18 +08:00 |
|
opsx
|
f87fb4b2b3
|
refactor: 移除备份恢复功能(API/CLI/手册)
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
日志数据的保留与安全由对象存储 + Loki retention 承担,平台侧整库备份恢复价值有限:
删除 services/backup.go、/system/{backup,restore,restore/apply,backups} 路由与 handler、
CLI backup/restore 子命令、前端 api 方法与类型;自检所需的 dataDirPath/密钥指纹并入 selfcheck;
用户手册删备份章节并修正 FAQ 升级建议;CHANGELOG 记录移除。
|
2026-10-29 14:48:25 +08:00 |
|
opsx
|
e07fe55c86
|
docs: CHANGELOG Unreleased 记录第三阶段首批特性
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
|
2026-10-29 14:04:25 +08:00 |
|
opsx
|
2bd77b57b4
|
feat(monitor): 平台自监控页(/monitor,管理员)
- 后端 /api/v1/system/metrics-summary(admin):从 Prometheus registry 聚合
HTTP 请求/状态码/Top 路由、DB 落盘与大小、告警评估、Loki 查询、runtime 快照
- 前端统计卡 + Top 路由表 + 分布明细(状态码/告警/Loki/落盘),中英文案齐全
- 菜单位于「日志分析」与「日志告警」之间
|
2026-10-29 14:04:25 +08:00 |
|
opsx
|
3ea7f2dcc6
|
feat(site): homepage 落地页 + docsify 用户手册文档站(/docs /homepage 随二进制发布)
- homepage/:品牌落地页(Hero/特性/快速开始),参考 opsxapi 站点风格,绿色品牌系
- docs/:docsify 文档站 + user-guide 十篇手册(安装/向导/采集/查询/分析/告警/授权/备份/FAQ)
- 后端 serveStaticDir 挂载 /docs 与 /homepage(可执行文件相对定位,独立于前端 dist)
|
2026-10-29 14:04:24 +08:00 |
|
opsx
|
b8d08ef6d1
|
fix(alerts): 内置规则排除 Loki 自身日志,消除自我污染误报
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
Loki 会把执行过的查询语句记成自身 info 日志,查询文本包含规则关键字时
告警会'命中自己'(如 StackOverflowError 规则匹配到告警引擎自己的查询记录),
造成持续误报——全命名空间类内置规则一律加 app!="loki";存量规则启动时自动升级;
顺带清理旧版遗留的重复规则「应用错误过多(error > 1000)」(与现模板重复且阈值会误报);
前端新建/模板默认查询同步;红线测试锁死
|
2026-10-29 13:46:46 +08:00 |
|
opsx
|
abe28964a1
|
fix(i18n): 全站文案书面化 + 中英翻译质量修复
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
中文(zh):约 40 处口语化改书面(「谁在什么时候改了什么」→「操作人、时间与变更前后对比」、
「找出最吵的业务」→「定位日志量最高的业务」、「点」→「点击」、创建你的第一个→创建首个等);
「副本 / Pod」统一为「Pod」。
英文(en)修复:
- 功能 bug:wizard openGrafana ({url}) 插值失效→({{url}});settings notify 空态链接词悬空破句
- 语义补齐:clusters/hosts 删除确认补 Warning 与后果句;tokenInsecureHint 补 Kubeconfig 建议
(并删 en 死键 tokenRecommended);retention liveHint/costWarning/upgradeHint 补丢失半句
- 术语统一:data source / collection policy / log lines / Listen IP (internal) / Total deployments
- 复数:users confirmDesc、pagination total、range lastMinutes 补 _one;storage deleteWarning 两形态对齐
- 风格:Select filtered users、Delivery History、Log Scrape Jobs、App label source、
Deployment Logs 连字符改间隔号;删除 zh 死键 liveTitle
|
2026-10-29 13:42:51 +08:00 |
|
opsx
|
df1075f1f5
|
fix(layout): 顶栏用户区去掉盾牌图标与管理员徽章,只留用户名
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
|
2026-10-29 13:31:05 +08:00 |
|
opsx
|
c33ea9d0a8
|
ci(lint): golangci-lint v2 入门禁并归零
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
- .golangci.yml:standard 集 - errcheck(存量 38 处裸忽略待专项),staticcheck 关纯风格/quickfix
- 清理 3 个无引用死函数;SanitizedJSON 不可达分支收敛为接口分支 + nil 指针防护(原死分支中的 nil 检查从未执行)
- CI backend job 增加 golangci-lint-action@v6
v2.0.0
|
2026-10-29 13:29:25 +08:00 |
|
opsx
|
a69142fbfe
|
refactor(frontend): Live Tail 重构 + alerts 拆分 + NotifySection 去重
- Live Tail:输入 500ms 防抖后才切换轮询查询;轮询 AbortController 取消 + 版本号丢弃乱序响应
- alerts/index 508→286 行:表单与模板拆出 RuleFormDialog(浏览器实测模板/通道/提交可用)
- NotifySection 两份逐字节副本合一为共享组件;settings 词典注册进 domains(alerts 直访不再裸键)
|
2026-10-29 13:29:25 +08:00 |
|
opsx
|
572efc89a4
|
fix(reliability): 采集器并发去重 + 备份恢复即时重载 + context 贯穿请求链
- CollectorService 安装/卸载按采集器互斥去重(重复触发不再并发 docker rm/run 互踩);删除后卸载失败留日志
- ApplyStagedBackup 替换文件后立即 Reload 内存态,消除「重启前旧内存落盘覆盖恢复文件」竞态;暂存文件名升级 lokistack.json(兼容旧名)
- GetUsage/Validate 全链路 context 贯穿:请求取消即中止 SSH/k8s 查询(异步调用点显式 Background)
|
2026-10-29 13:29:25 +08:00 |
|
opsx
|
9daaf7f403
|
docs: CHANGELOG 落地与发布流程说明
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
|
2026-10-29 13:28:23 +08:00 |
|