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
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
c5739d1a06
feat(alerts): 内置规则默认启用并绑定默认通道,开箱即用
...
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
- 新种规则 Enabled: true;启动时执行 SeedAlertRules(此前仅部署成功调用,存量环境拿不到升级)
- 存量一次性迁移:内置名单内且从未关联通道的规则补绑默认通道并启用;用户已自配通道的不动
- 管理员只需给「默认告警」通道填 Webhook 并启用;通道未就绪时命中只记发送历史(failed+原因),不影响规则评估
2026-10-29 13:14:05 +08:00
opsx
c08190458f
fix(alerts,db): 清理历史误种的 K8s 基础设施告警规则 + 数据迁移不留档
...
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
- seed 启动时一次性删除早期版本种入的「Kubernetes 节点 NotReady」「容器 OOMKilled」
(日志平台只关注应用日志,节点/容器状态告警归 Prometheus;源码早已移除该模板,但幂等只跳过不清理,旧库存量一直在)
- 数据文件迁移为 lokistack.json 后直接删除旧文件,不再留 .migrated-*.bak(测试同步)
2026-10-29 13:09:14 +08:00
opsx
7369a17598
feat(alerts): 数据库连接告警覆盖 MySQL/PG/Redis 主流报错;规则表单三字段对齐
...
=== 1. 「数据库连接失败」匹配模式 3 → 25 个 ===
原来只匹配 connection refused / reset by peer / too many connections,
漏掉了 PG 的 FATAL: too many clients、Redis 的 NOAUTH / WRONGPASS /
connection pool timeout 等实际最常见的报错。
按数据库分类补齐:
通用网络层
connection refused / connection reset by peer / broken pipe /
no route to host / cannot assign requested address /
connection timed out / i/o timeout / unexpected EOF /
server closed the connection unexpectedly
MySQL
too many connections / communications link failure /
driver: bad connection / could not create connection /
Access denied for user
PostgreSQL
FATAL: password authentication failed / sorry, too many clients /
terminating connection
Redis
NOAUTH / WRONGPASS / READONLY you can't write against /
CLUSTERDOWN / max number of clients reached
连接池(Java/Go 应用层最先炸的地方)
connection pool / connection is not available
**刻意不加**的(会匹配到几乎所有网络日志,等于没告警):
裸 "EOF"、"timeout"、"error"、"refused"、"deadlock"
阈值保持 1000/15min(模式变多不代表命中变多,都是真错误才命中)。
迁移 v9→v10 只替换"仍是旧默认查询"的规则,用户自定义过的不动。
=== 2. 规则表单三个字段没对齐 ===
现象:统计窗口(分) / 触发阈值(条) / 冷却(分) 三格并排,
但只有中间的「触发阈值」下方多了一行提示文字,
导致中间那格更高、提示文字悬在底部,看起来像没对齐。
修法:三格统一为「标签 + 输入框 + 一行提示(min-h-4 固定高度)」,
底边自然齐平;提示文案改为:
统计窗口 → 统计最近多少分钟
触发阈值 → 超过该条数才告警
冷却 → 冷却内不重复发送
(顺带把阈值提示从"0 = 出现即告警"改掉:默认阈值已无 0,0 反而是危险配置)
小屏改单列堆叠(grid-cols-1 sm:grid-cols-3)。
=== 实测(936a127b1d15)===
v10 迁移:告警规则 "数据库连接失败" 扩展匹配模式
线上规则:25 个模式,含 NOAUTH / too many clients,阈值 1000,冷却 240m
Pod = latest = v0.1 = 936a127b1d15
2026-10-29 03:56:07 +00:00
opsx
cb1ef1dff4
fix(alerts,analysis): 告警引擎稳定性 5 项修复;每日量接口去掉同步 Loki 查询(20s→10ms)
...
=== 一、告警引擎稳定性审查(引擎本身是异步的:ticker + goroutine)===
1) 【高】ticker 无重叠保护
ticker 每 1 分钟触发;一轮规则检查 8 条 × 20~30s = 2~4 分钟,远超一分钟。
原来每过一分钟就再开一轮 → 查询越堆越多,抢走页面查询的 Loki 资源,
每轮越来越慢,最终表现为"告警不响了"。
→ 新增 alertCheckRunning(atomic.Bool),上一轮未完成直接跳过本轮并记日志。
2) 【高】单条规则无超时
RunAlertCheck(context.Background()) 没有 deadline:Loki 一旦挂住,整轮永久运行,
叠加问题 1 会让引擎再也不启动新一轮(静默死亡)。
→ 每轮总超时 5 分钟(alertRoundTimeout)+ 单条规则 90s(alertRuleTimeout)。
3) 【中】panic 只在整个 tick 层 recover
一条规则 panic 会让本轮后续规则全部跳过。
→ per-rule recover,panic 记为一条 failed 投递记录,后续规则继续。
4) 【中】冷却记录每分钟写一条,把真实发送记录挤光
AlertDeliveries 只保留最近 50 条,而处于冷却期时每个 tick 都写一条 cooldown,
一小时内真实的"已发送"记录就全被挤掉了,发送历史没法看。
→ recordCooldownThrottled():同一规则 10 分钟最多写一条。附单测。
5) 规则串行本身保留(避免同时压垮 Loki),但配合 1) 才安全。
=== 二、每日日志量接口:20 秒 → 10 毫秒 ===
根因:GetDailyVolumeHistory 里**同步** await 一次"整天 index/stats"补抓当天数据,
那次查询超时 20s → 整个接口 20s → 前端超时 → 页面显示"每日日志量没数据";
更糟的是这条重查询还和页面的 histogram/stats 抢 Loki,导致那两个接口同时 502
(访问日志实证:daily-volume latency_ms 20000.997,stats/histogram 502)。
→ 接口改为**只读库**,不触发任何 Loki 查询;当天数据由后台每 30 分钟的
定时任务补(CaptureRecentDailyVolumes)。
→ 同时把整天 index/stats 的超时从 20s 提到 90s(370GB/天,20s 不够)。
实测:10ms。
=== 三、通知通道改名「默认告警」(schemaVersion v8→v9) ===
"lark 默认告警" / "默认通知通道(待配置 Webhook)" → 统一为「默认告警」。
只改名,不动 Webhook、不动 enabled:
首次部署创建的占位通道必须保持「空 Webhook + 禁用」,由管理员自己填,
否则会出现"已启用但空地址"的通道,告警一命中就全部投递失败。
=== 四、其它文案 ===
「每日日志量」副标题精简为「每天的日志总量,平台保留历史趋势」,
并移除「平台留存历史」徽标(用户反馈多余)。
=== 实测(303134c0c718)===
/logs/daily-volume:10ms(原 20000ms)
通道列表:id=1 name="默认告警" enabled=true hasWebhook=true
go test ./... 全绿(含新增 TestRecordCooldownThrottled)
2026-10-29 03:38:30 +00:00
opsx
607b67a2ed
fix(alerts,analysis,dashboard): 阈值再上调 + 告警风暴全局闸门;修 subtitle/门控/饼图 Top5
...
=== 1. 告警阈值第二轮上调(500~5000 这一档仍然太敏感)===
实测业务高峰期这些量级就是常态,阈值贴着基线等于"每天准点报警":
应用错误激增 50000 → 100000(冷却 120m → 240m)
ingress 5xx 500 → 2000 (冷却 240m)
ingress 4xx 5000 → 20000 (冷却 240m)
数据库连接失败 200 → 1000 (冷却 240m)
迁移 v7→v8,只改"仍等于旧默认值"的规则,用户手动调过的不动。
=== 2. 告警风暴抑制:新增全局闸门 ===
单条规则的 cooldown 只能防"同一条重复",挡不住"多条规则同时炸"。
实际踩过:一次存储抖动让 8 条内置规则同时命中,10 秒内群里刷了 8 条,
之后大家开始无视这个群 —— 告警疲劳比漏报更难挽回。
新增 overStormLimit():最近 1 小时内全平台成功发送数 ≥ 12 条时,
后续命中不再发送,只写一条状态为 cooldown 的发送记录并注明
"告警风暴抑制:最近 1 小时已发送 N 条(上限 12)",可见可追溯。
=== 3. 分析页 subtitle 仍是裸 key ===
中文语言包缺顶层 subtitle(英文包有),i18next 找不到就把 key 原样输出。
补齐:「按应用与命名空间看日志量、错误与趋势,找出最吵的业务」。
=== 4. 分析页三条"没有应用维度的数据"的真正原因 ===
「活跃应用」「应用日志量 Top 5」「应用日志量流图」都依赖 by-app 重查询,
而这条查询被**底部排行卡片的可见性**门控(rankingEnabled: rankingView.inView)——
用户不滚到底就永远不发请求,于是顶部三块永远是空的。
改为进页面就发(两阶段渲染:索引类指标先出,app 维度到货后补)。
懒加载只保留在真正位于底部的「每日日志量」「Ingress 分析」。
=== 5. 饼图改 Top 5 + 文案 ===
用户要求:应用日志量 Top 5 用饼图。TOP_SLICES 8 → 5,
标题改「应用日志量 Top 5」,副标题写明"其余归入其他"。
=== 6. 卡片顺序 ===
「每日日志量」从中间移到「应用排行」之后(更靠底部,慢慢加载)。
=== 7. 仪表盘 ===
整个「平台自检」卡片(含所有指标行)按用户要求移除。
=== 实测(2e8c88817b6a)===
v8 迁移:4 条规则阈值上调,日志齐全
当前阈值:FATAL>10 / panic>10 / OOM>5 / StackOverflow>5 /
应用错误>100000 / ingress 5xx>2000 / 4xx>20000 / DB 连接>1000
冷却:低频规则 120m,高频规则 240m
2026-10-28 23:43:14 +00:00
opsx
37e2f0febc
feat(analysis,alerts): 每日量落库看历史趋势、趋势图/饼图可读性、告警三分页
...
=== 1. 每日日志量必须落库(核心问题:Loki 只留 24 小时)===
实测:请求"近 7 天每日量",Loki 只返回 27 个**小时**桶,全部在最近 24h 内 ——
因为 retention_period=24h,更早的 chunk 已经被删了。
也就是说「固定近 7 天」这张卡片,过去一直是"6 天空白 + 1 天有数据",
用户看着像坏了,实际是数据物理不存在。
方案:平台自己留存历史。
- models.DailyVolumeSnapshot{Date(本地YYYY-MM-DD), SourceID, Bytes, Entries, Partial}
- services/daily_volume.go
CaptureDailyVolume 按天抓 index/stats 落库(幂等覆盖)
StartDailyVolumeCapture 启动 20s 后回补 + 每 30 分钟检查一次
GetDailyVolumeHistory 读库返回最近 N 天(今天会实时补抓)
- 保留 400 天(够看年度趋势),按 source+date 去重
- 前端可选 7 / 30 / 90 / 365 天,能看多长取决于平台积累多久
为什么用"每 30 分钟检查昨天有没有落库"而不是固定 00:10 定时:
平台可能整晚没运行,固定时点的定时器会直接错过;检查式回补不依赖平台在线时刻。
Partial 标记(关键,否则会误读):
- 当天未结束 → partial=true
- 待抓取日期的起点已超出 24h 保留期 → partial=true(Loki 里就没那么多数据)
实测:10-27 32.5GB/2.65亿条 partial=true(保留期外),
10-28 348GB/28.56亿条 partial=true(当天进行中)
=== 2. 修一个 Go 副本 bug(自己写的,靠实测发现)===
第一版用 `for _, snap := range db.DailyVolumeSnapshots` 后改 snap 字段,
range 拿到的是**副本**,改动不会写回切片 → 同一天永远保持首次抓取的值,
partial 也永不更新(实测发现 10-27 该是 true 却显示 false)。
改为 `for i := range ... { snap := &db.DailyVolumeSnapshots[i] }`。
=== 3. 趋势图可读性 ===
从"裸折线"换成"渐变面积图",并在图上方给出峰值 / 均值:
- 面积图能一眼看出"这一段整体比上一段高",折线只能靠对齐格子数
- 峰值/均值避免用户自己对刻度
- Y 轴与 tooltip 统一 formatBytes,"每桶体积"写进 subtitle
顺带确认:趋势图只画体积(字节),不再混入 error(条数)——单位不同不能同轴。
=== 4. 饼图:命名空间分布 → 应用日志量分布 ===
本环境的命名空间只有 astralx / log 两个,饼图没有信息量;
改成按应用看谁在刷日志(前 8 名 + 其他),才是运维真正要的答案。
=== 5. 告警页拆成三个 Tab ===
「告警规则 / 通知通道 / 发送历史」独立成分页(用 ui/tabs)。
之前通道是折叠块、历史堆在规则下面,规则一多就要滚很久才看得到。
发送历史增加空状态文案,不再是"空页面不知道有没有在发"。
=== 6. 内置规则关联默认通道 + 首次部署 webhook 留空的评估 ===
结论:**webhook 可以留空,但通道必须是禁用状态**。
- 若种子给的是"已启用 + 空地址"通道,规则一命中就必然投递失败,
发送历史堆满红色失败,反而让人以为平台坏了
- 所以首次部署建一个**禁用**的占位通道「默认通知通道(待配置 Webhook)」,
内置规则全部挂到它;管理员填好 Webhook 再启用即可,不用逐条关联
- 保存时加校验:启用则必须有非空 Webhook(返回明确原因,不是裸 500)
- schemaVersion v5→v6:把已有的"无通道"规则补挂到默认通道
实测:8 条规则全部已关联通道
=== 实测(v11-1028-2252 / 187062644c0f)===
/logs/daily-volume?days=7 → 2 天数据,partial 标记正确
规则 8 条全部有 channelIds
平台 ready、健康 ok
2026-10-28 22:54:12 +00:00
opsx
fa7ddd67c1
perf(analysis): 分析页按索引/内容分层,告警默认阈值抬高
...
=== 1. 分析页"一直转圈/请求超时(40000ms)"的真实原因 ===
三个问题叠加,逐个量化:
a) 首屏用空 namespace 发查询
页面初始 namespace='',等策略返回前就发出 `{namespace=~".+"}` 全集群查询,
策略到位后又查一次 → 一次访问跑两遍。
→ 加 namespaceReady 门控:解析完再发(effectiveSourceId)。
b) histogram 索引查询和内容查询抢同一个信号量
/logs/histogram 首选 index/volume_range(毫秒级),但仍要先抢重型令牌,
而令牌被 4 条 count_over_time(各 14~29s)占满 → 排队/429/超时。
→ 索引路径**不再占用重型令牌**(15s 独立超时),只有回退到
count_over_time 时才抢令牌。实测各跨度(15m/1h/6h/24h)均 0s。
c) 重查询条数过多
原来 4 条全局 count_over_time(total/error/warn)+ 2 条 by-app,
串行 1~2 分钟。现在只留 2 条 by-app:
- 全局总量已由 histogram(索引)提供
- 全局 error 由 errByApp 序列求和得出
- 全局 warn 放弃(优先级最低却要 20s)
实测 by-app 单条 26s,两条串行 ~52s;主图 0s 先出。
d) 日报 7 天 count_over_time(2.6TB 扫描)必然失败
→ 改走 /logs/histogram(索引)按自然日聚合,只出"每日总量",
应用维度交给下方 Top 应用表格(有自己的时间范围)。
实测 7 天跨度毫秒级。
=== 2. 告警默认阈值抬高(告警疲劳治理)===
验证时用 `{namespace="astralx"}` + 阈值 0 触发了一次:
15 分钟命中 3051 万条 —— 阈值 0 等于把告警变成日志流复读机。
新基线(15 分钟窗口,冷却统一 120 分钟):
致命日志 FATAL 0 → 10
Go panic 0 → 10
JVM OutOfMemoryError 0 → 5
StackOverflowError 0 → 5
应用错误激增 1000 → 50000(改名,原"error > 1000"名不副实)
ingress-nginx 5xx 100 → 500
ingress-nginx 4xx 1000 → 5000
数据库连接失败 50 → 200
迁移只改"仍等于旧默认值"的规则,用户手动调过的阈值不动。
设计原则写进 seed 注释:绝不用 threshold 0;宁可少报也不要让人对告警脱敏;
绝对阈值不跨环境通用,大集群必须按 app/namespace 收窄。
=== 实测(v6-1028-2218 / 0bf66199de66)===
规则 8 条,阈值=0 的规则数 0,冷却全部 120m
histogram astralx(15m/1h/6h/24h): 0s
by-app metrics astralx 15m: 26s,正常返回数据
2026-10-28 22:20:19 +00:00
opsx
95dcd9408c
fix(logs,analysis,alerts): 数据源不可达、分析页超时、告警规则混入基础设施项
...
=== 1. 主机模式数据源地址 0.0.0.0 → 主机真实 IP(查询页"永远加载中"的根因)===
现象:切换数据源后命名空间/App 下拉不动,一直显示"加载中…",控制台报
Get "http://0.0.0.0:3100/loki/api/v1/labels ": dial tcp 0.0.0.0:3100: connect: connection refused
根因:主机模式部署的 endpoint 记的是**容器监听地址** 0.0.0.0:3100,
而平台进程不在被采集主机上,0.0.0.0 只在本机有意义。
EnsureLogSourceForDeployment 把它原样写成了数据源 URL。
修法:
- 新增 reachableEndpoint():把 0.0.0.0 / [::] 换成关联主机的真实 IP
- schemaVersion v3→v4 迁移 fixUnreachableLogSourceURLs(),修正已有脏数据
- 实测:http://0.0.0.0:3100 → http://172.19.16.8:3100,该源 label 查询由 502 变 200
=== 2. 前端:区分"加载中"与"加载失败" ===
原来用 `loading={!options.length}` 表示加载中 —— 数据源不可达时列表永远为空,
于是界面永远转圈,把真实错误完全藏起来了(这次的 0.0.0.0 就是这样被掩盖的)。
改为独立的 namespaceLoading / namespaceError 两个状态:
- 切换数据源先清空旧 options(否则显示上一个源的命名空间,看着像"没反应")
- 失败显示"加载失败"并在旁边给「重试」按钮,不用刷新整页
=== 3. 日志分析页:主图改走索引接口(原来 5 条 count_over_time 全超时)===
实测 astralx(约 370GB/天)15 分钟窗口:
count_over_time → exec 29s + 排队 95s,超过 30s 护栏 → 502
index/volume_range → 0s
改为两阶段渲染:
- 总量趋势改用 /logs/histogram(内部 index/volume_range),**0s 出图**
- 错误/警告/app 维度仍需读日志内容,串行执行,先渲染主图再更新
- heavyQueryTimeout 30s → 90s(实测 error 维度查询 14s 可完成)
=== 4. 告警规则按日志平台定位收敛 ===
- seed 里删掉「Kubernetes 节点 NotReady」「容器 OOMKilled」:
这类属于 kube-state-metrics / Prometheus 的职责,用日志字符串匹配不可靠
- 迁移里清掉线上已存在的同类规则(3 条)
- 修 AlertRule / NotifyChannel 重复 ID(同 logSources 一样漏在 sequences 重建外)
=== 5. 告警页 UI ===
- 规则列表由"每条一张卡"改为紧凑表格(一屏看全,阈值可对齐比较)
- 通知通道(飞书/Lark/Webhook)从「系统设置」搬到告警页折叠区:
规则和"发到哪"是一件事的两半,分两页配容易漏配导致告警发不出去
=== 6. 权限收敛 ===
- /alerts 加 adminOnly:普通用户按查询授权只看「日志查询」,不再看到告警菜单
- 系统设置从侧栏移到右上角齿轮(低频平台配置,不占侧栏一位)
=== 7. 迁移设计教训(写进代码注释)===
v2 时把"告警去重 + 清基础设施规则"塞进 case 1,但线上库已到 v2,
那段代码永远不执行。**结构变更只要逻辑变了、目标库已达该版本,就必须再抬一版**,
不能改历史迁移分支。
=== 实测(v4-1028-2210 / 979bdb4a48e8)===
v4 迁移:数据源 URL 修正 http://0.0.0.0:3100 → http://172.19.16.8:3100
source 1 label:200,0s(astralx / log)
source 2 label:200,0s(不再 connection refused)
分析页 histogram astralx 15m:0s
分析页 metrics error astralx 15m:14s
告警规则:10 条(已无基础设施类)、ID 唯一
另清理 172.19.16.8 上 13 个残留容器,回收 6.1GB
2026-10-28 22:11:48 +00:00
opsx
f3733f0bfc
feat: 品牌统一 LokiStack + 全站中英 i18n + 用户批量删除 + 主题定时切换与浅色侧栏
...
- 品牌: Go 模块/数据文件/二进制/构建部署资产全部 opsx→lokistack;前端 localStorage 命名空间迁移(读旧写新,含按用户 id 前缀迁移);修复 nginx upstream 与 Makefile 引用已改名服务的断裂
- i18n: react-i18next 落地,common + 11 个页面域命名空间全站中英(菜单/顶栏/登录/列表页/表单/确认弹窗/状态徽章);设置页语言即时切换;修复词典自注册导致的循环导入白屏
- 用户管理: 批量删除(POST /users/batch-delete,不删自己/最后管理员,部分失败不阻断)+ 行复选/全选/批量工具条
- 主题: 浅色侧栏(中性灰激活态)、四态模式(浅色/深色/跟随系统/定时切换,按时区判定)、顶栏太阳月亮二态、设置页紧凑分段选择器
- UI: 登录记住用户名、CardActionButton 统一五页卡片操作钮、shadcn Badge 替换手写徽章、语义色修正
- 清理: 移除主机 Web 终端(前后端)、k8s-helm/Helm 遗留代码与字段、README 重写精简
- 修复: 侧栏与日志告警 order 重复、路由标题 i18n key 未翻译、词典双逗号等
2026-10-27 17:11:38 +08:00
opsx
4dda6e5ba8
fix(logs): 快捷 LogQL null 崩溃 + app 标签错位 + 查询授权「所有人」与默认策略
...
=== 一、快捷 LogQL 报 Cannot read properties of null (reading 'map') ===
根因:Loki 对无值的 label 返回 {"data":null},Go nil slice 序列化成 JSON null,
前端 setState(null) 后再 .map() / [...null] / .filter() 直接抛错。
表现为「不稳定」——切到某个没有该 label 值的范围就崩。
修复(前后端双保险):
后端 LokiLabels / LokiLabelValues 归一化 nil → []string{}
(LokiHistogram 原本就返回空切片,无需改)
前端 6 处调用点加 Array.isArray 防御:
QuickQueryTemplates ×3、QueryInput ×2、LokiLabelBrowser ×2
=== 二、选 astralx 只显示 2 个 app(不是权限问题)===
实测:
astralx 117 个 Deployment / 497 个 Pod
带 app 标签的 Pod 只有 2 个(cex-promotion-web / cex-web-h5)
其余 115 个 Deployment 的 Pod 模板没打 app,Kuboard 打的是 k8s.kuboard.cn/name
Loki 里 service_name / container 各有 79 个值(Promtail 从容器名生成)
修复:QuickQueryTemplates 的「app」候选改为三级回退 app → service_name → container,
并用 appLabel 状态记住实际生效的标签名,pod 收窄与 generate() 都用它,
保证生成的 LogQL selector 真能查到数据。
=== 三、查询授权:支持「所有人」+ 内置默认策略 ===
1. 后端 policyGroupAccess:userIds 里的 0 作为哨兵值表示「所有人」(anyone / *),
匹配任意用户(原来只能逐个指定用户 ID)
2. 种子 seedDefaultPolicy():首次启动且尚无任何策略组时,创建
「默认策略(所有人 · default 命名空间)」(labels: namespace=default,userIds: [0])。
管理员可在「查询授权」里把命名空间改成实际业务命名空间(如 astralx),
对该组所有用户立即生效。
3. 前端 PolicyGroupsPage:新增「所有人(anyone)」一键按钮(与具体用户互斥),
列表与编辑区显示「所有人」,校验文案同步更新。
验证:
GET /logs/label/nonexistent_xyz/values → {"data":[]}
GET /logs/label/service_name/values?query={namespace="astralx"} → 79 个
GET /logs/policy-groups → 1 条:默认策略(所有人 · default 命名空间)所有人
镜像:lghost/lokistack:latest + v0.1 = sha256:88a4ba626f62
2026-10-27 01:19:06 +00:00
opsx
3c27e58a73
feat(security): 移除 admin123 硬编码默认密码 + 编译加 -trimpath
...
安全加固(降低二进制泄露/逆向的信息面):
1. 初始密码随机化
- 首次启动生成 16 位随机密码(大小写+数字,排除 0/O/1/l/I 易混淆字符)
- 写入数据卷 initial-admin-password.txt(0600)并打印到首次启动日志
- admin 首次改密后自动删除该文件(seed.CleanupInitPassword)
- 支持 ADMIN_INIT_PASSWORD 环境变量指定(自动化部署 / 固定密码场景)
- 生成失败直接 Fatal 退出,不再降级到公开默认口令
2. 移除硬编码 admin123
- main.go 不再打印 "Default login: admin / admin123"
- 二进制内 admin123 命中:2 → 0
3. -trimpath
- build.sh / run.sh 编译加 -trimpath
- 二进制内 /app/backend/ 源码路径命中:66 → 0
4. 文档
- README 新增「第 4 步:获取管理员初始密码」
(docker compose exec / logs / docker cp / named volume 四种方式 + K8s 对应命令)
- .env.example 补 ADMIN_INIT_PASSWORD
- kubernetes/deployment.yaml 加 env 注释说明
验证(strings 对比加固前后二进制):
admin123 2 → 0
/app/backend/ 66 → 0
initial-admin-password.txt / ADMIN_INIT_PASSWORD / CleanupInitPassword 均存在
2026-10-26 17:01:09 +00:00
logan
2d73661dd1
feat: complete Loki query, insights, settings and deployment workflows
...
Add the Loki query UI, access policies, ingress insights, alert and registry settings, and their backend APIs. Include the related Kubernetes deployment and collector updates required by the integrated application.
Validated with go test ./..., npm run build, and npm run lint.
2026-10-25 21:28:32 +08:00
logan
f9c6c1d826
feat: opsx-loki 全面升级 — 前端重构/用户与LDAP/部署向导/日志查询
...
基于 WEB-UI-Development-Guide 标准的整体升级,并更名 LokiDeploy → opsx-loki。
前端(Gin+React+shadcn/ui):
- 按 02/07 章重构:页面域化拆分(无超 400 行文件)、PageContainer/ListQuery、
反馈分级(成功静默/失败 toast/危险确认)、401 单飞刷新+队列重放
- 暗色模式(next-themes)+ 语义 Token(--primary 品牌色/success/warning/info)
- 部署向导(状态推导四步:环境→存储→Loki→采集,内嵌表单闭环)
- 日志查询页:LogQL 标签构建器/拖拽直方图/日志上下文/Live Tail/查询历史
- 按用户+标签策略的查询授权(服务端强制合并策略)
后端(Go+Gin+JSON DB):
- 简单用户管理(仅 admin,无 RBAC)+ TokenVersion 会话吊销 + 登录 IP 限流
- LDAP 接入:配置(AES 加密存储/hasPassword 脱敏)/测试连接/批量导入/登录
- 存储配置测试连接(SigV4 零依赖)+ 桶不存在自动创建
- Loki 三模式部署修复:SSH 密钥认证、3.x 配置模板、ruler 对象存储嵌套块、
凭证解密、孤儿 deploying 状态恢复、Grafana 部署(可选默认关)+面板导入
- DaemonSet 采集纯 YAML(去 helm 依赖)+ DNS 自愈回退 ClusterIP + 集群名标签
- 日志查询代理:cluster-svc 经 kube-apiserver proxy/url 直连 + cursor 翻页
- 统一 log 命名空间;部署就绪探活;Grafana 访问地址自动记录
修复:run.sh 增量编译检测、Sanitized 脱敏补全、LokiDeployment Update 白名单、
健康检查 CreatedAt 零值等 10+ 存量 bug。
数据兼容:DB 沿用旧 lokideploy.json(新名优先);localStorage 一次性迁移;
HKDF 加密前缀保留(已加密凭证不受影响)。
2026-10-24 13:20:12 +08:00
Logan.Li and Claude
327e282356
refactor: 前后端目录结构模块化 + v2 优化移植与缺陷修复
...
前端:
- src/srv/api → src/api,按域分文件夹(auth/cluster/host/storage/deployment/collector)
- 新增 http.ts 引擎(http.get/post/put/delete),域模块改用语义化调用
- index.html 增加 favicon(匹配应用 logo 的 emerald + Activity 脉冲)
后端分层增强(保留包名):
- 新增 repository/:从 models 拆出 JsonDB 持久化层(InitDB/GetDB/Shutdown/RequestSave)
- 新增 dto/:从 controllers 抽出各域请求契约(带 binding 校验)
- 新增 pkg/crypto、pkg/jwt:从 utils 拆出安全原语(外部 jwt 别名 jwtv5 避免冲突)
- models 只留领域实体 + sanitizer;utils 只留 gin/应用相关(response/errors)
v2 优化移植与缺陷修复:
- 移植密钥分离/SSH TOFU/并发写安全/Loki 生产级配置/Docker 加固
- 修复 deployment.go 并发丢更新、Helm values 重复键、EncryptField 哨兵、loki-gateway 端点等审计缺陷
- 实现真正的优雅关停(main.go http.Server + signal + repository.Shutdown)
- 修复登录契约:后端返回 accessToken,前端 auth.ts/Login.tsx 对齐
- 补 crypto/jwt/repository 单元测试(含并发写回归)
验证: go build/vet/test 全绿;npm run build 通过;登录→鉴权→优雅关停冒烟通过
Co-Authored-By: Claude <noreply@anthropic.com >
2026-06-30 10:46:26 +08:00
Logan.Li and Claude
2a93de600d
feat: LokiDeploy 初始提交 - 轻量级 K8s Loki 部署平台
...
Go(Gin) + React(Vite + shadcn/ui + Tailwind) 前后端分离,全中文 UI
- 集群管理:Kubeconfig / Token 双接入,kubectl + helm 部署
- 主机管理:SSH 密钥 / 密码双认证,CPU/内存/磁盘使用率监控,SSH 错误中文友好提示
- 存储配置、部署管理、系统设置
- Docker 镜像内置 kubectl + helm,开箱即用
- run.sh 一键启停(start/stop/restart/status)
Co-Authored-By: Claude <noreply@anthropic.com >
2026-06-29 17:03:57 +08:00