opsx
5d530036e6
feat(logs): 分页显示总页数(新增 /logs/stats,走 index/stats 只读索引)
...
用户反馈:底部只有「上一页 第 1 页 下一页」,看不到末尾/总页数。
原因:日志结果是 Loki 游标分页(cursor = 纳秒时间戳),本身不返回总数,
前端只能知道"有没有下一页",算不出总页数。
解法:新增 POST /api/v1/logs/stats
→ 调 Loki /loki/api/v1/index/stats(只读 TSDB 索引里的 chunk 元数据)
→ 返回 {streams, chunks, bytes, entries}
→ 前端用 entries / limit 得到总页数
实测成本极低:1h 51ms、24h 30ms(3.28 亿条 / 44.2 GB)。
改动:
1. backend: services.LokiStatsFor + controllers.LogsController.Stats + 路由 /logs/stats
2. frontend: logsApi.stats;查询成功后拉取总数(复用同一 AbortController,
失败静默不影响日志展示);计算 totalPages 传给结果面板
3. LogResultsPanel: 有总数时显示「第 N / M 页」,否则维持「第 N 页」
4. i18n: 新增 results.pageOfTotal(中英)
镜像:lghost/lokistack:latest + v0.1 = sha256:41d6576ec232
2026-10-28 16:02:35 +00:00
opsx
de376a1284
perf(logs): 日志量统计改用 index/volume_range(快 ~1300 倍)+ 查询护栏 + 真实错误提示
...
=== 一、现象 ===
- /logs 页「正在统计整个时间范围的日志量」24 小时查询转圈 5 分钟不出结果
- /analysis 页默认 1 小时也一直「加载中...」
- 期间 Loki 被 OOMKilled(2Gi) → Pod not Ready → Service 无端点 → 全站查询 502
=== 二、根因(实测数据) ===
同一 query {namespace="astralx", app="cex-ipublic-gateway"}:
24h count_over_time[15m] step=15m → 53.7s 后连接断开(算不完)
24h count_over_time[1h] step=1h → 60.1s 失败
24h index/stats(只读索引) → 1.3s → bytes 44.9GB / entries 3.33亿 / chunks 2474
24h index/volume_range step=1h → 111ms → 25 个点
1h index/volume_range step=5m → 115ms → 13 个点
原因:count_over_time 必须**下载并解码所有 chunk**;volume_range 只读 TSDB 索引里的
chunk 元数据(字节数),根本不碰日志内容。该 app 一天就有 3.33 亿条 / 44.9 GB。
=== 三、改造 ===
1. LokiHistogram 改用官方 /loki/api/v1/index/volume_range(带 step)
- 返回单位是「字节」,bucket 带 unit=bytes,前端格式化为 KB/MB/GB
- 老版本 Loki 没有该端点时自动回退 count_over_time(unit=entries)
2. 查询护栏(防止单条查询拖垮单实例 Loki)
- 统计范围上限 7 天,超出直接 400「统计范围过大(27.0 天),最多支持 7 天」
- 重查询单独 30s 超时(原来 120s)
- 全局并发重查询上限 2,超出立刻 429「请稍后重试」(不排队)
- /logs/metrics(analysis 页)共用同一套护栏
3. 前端
- 发起新查询前 abort 上一次请求(原来只用版本号丢弃结果,旧请求仍在后端跑)
- histogram/query 支持 signal;超时 40s/60s(原 125s)
- 错误不再统一显示「日志量统计失败」,按 429/400/502/超时给不同文案
- 时间线按 unit 格式化(字节 → GB),i18n 去掉「条」
4. Loki 侧官方优化(此前 limits_config 只有 retention_period)
- query_range: align_queries_with_step + cache_results + embedded_cache 100MB
- limits_config: max_query_parallelism 8(默认 32,单实例过高)
- 已用 `loki -verify-config` 校验通过(config is valid)
=== 四、实测(平台 API) ===
1 分钟 0.02s 2 桶
1 小时 0.05s 61 桶 3.8 GB
6 小时 0.04s 73 桶 12.3 GB
24 小时 0.04s 97 桶 41.8 GB ← 改造前 53.7s 失败
7 天 0.05s 37 桶 58.2 GB
27 天 0.01s 400「最多支持 7 天」
镜像:lghost/lokistack:latest + v0.1 = sha256:9fa1c4597533
2026-10-28 15:54:55 +00:00
opsx
16306a9532
feat(logs): metrics 指标代理端点(admin) + 快捷查询选中 App/Pod 即插入并执行
...
- POST /logs/metrics:LogQL 指标查询代理,[$step] 占位符按跨度自适应步长,返回多序列(httptest 假 Loki 单测)
- 快捷查询:选中 App/Pod 即写入输入框并立即查询,面板保持打开支持 Pod 级联;命名空间仅级联筛选不插入,切换时清理失效标签
- 删除冗余的「查询该范围日志」「指定副本日志」按钮;Ingress 按钮仅在选择 ingress 命名空间/app 时显示
- /logs 支持 ?q= 预填自动执行(表格「查看日志」跳转入口)
- 清理无引用死组件 LogResults/LogHistogram
2026-10-28 22:43:57 +08: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
e006fc1a0e
fix(promtail): app 标签通用回退 + 跳过僵尸 Pod + SecretKey 不下发 + 采集命名空间可选
...
=== 一、astralx 只采集到 2 个 app(核心问题)===
实证:用户的 Deployment Pod 模板只有 k8s.kuboard.cn/name 标签,
没有 app / app.kubernetes.io/name。原模板的 app 只从这两个标签取,
所以 115 个服务的 app 全是空值,Loki 里 app 只剩零星 2 个。
修复:app 四级回退,全部基于 Kubernetes 原生元数据(跨集群通用):
1) app.kubernetes.io/name 标准约定
2) app 常见简写
3) __tmp_controller_name Pod owner(ReplicaSet) 去 hash → Deployment 名
(__meta_kubernetes_pod_controller_name 由
Promtail 直接从 K8s API 读取,任何集群都有,
不依赖 Kuboard/Rancher 等第三方工具注入的标签)
4) pod name 兜底,保证 app 永不为空
同时修复 PromtailHelmValues 模板同样的 app 逻辑,
并修正其 __meta_kubernetes__pod_name 双下划线笔误。
验证:astralx 的 app 值从 2 个 → 73 个。
=== 二、15 分钟 27 万条日志的真相 ===
排查结论:不是重复采集(positions 存 hostPath /run/promtail,Pod 重启不丢)。
真实原因:cex-openapi-gateway 残留 347 个 Evicted + 37 个 Error 的僵尸 Pod,
只有 1 个 Running。这些 Pod 的日志文件仍在 /var/log/pods/ 下,
Promtail 会把它们的历史异常堆栈(Reactor at reactor.core.publisher...)
全量采集,造成 27 万条的假象并污染存储。
修复:relabel_configs 首条加 drop 规则:
- source_labels: [__meta_kubernetes_pod_phase]
regex: (Succeeded|Failed)
action: drop
(两个模板都加)
=== 三、SecretKey 不再下发给前端 ===
安全要求:避免任何登录用户点「显示」按钮就能拿到对象存储 SK。
- StorageConfig.Sanitized(): secretKey 返回空串,仅保留 hasSecretKey 标记
(accessKey 仍明文返回,便于管理员核对用的是哪个 AK)
- 测试连接:StorageTestRequest 新增 id 字段,secretKey 留空时后端用
库里保存的凭据解密补齐(新建存储仍强制填写)
- 前端编辑时 SecretKey 一律留空 = 不修改,placeholder 显示
「已保存 · 留空则不修改」,测试时带上 id
=== 四、采集器支持指定命名空间 ===
- Collector 新增 TargetNamespaces []string,对应 promtail 的
kubernetes_sd_configs.namespaces.names(为空=全集群)
- PromtailDaemonsetYAML 新增 promtailNamespaceFilter 生成白名单
- service.Update 支持 targetNamespaces(兼容 []string 与逗号分隔字符串)
- 前端 CollectorEditDialog 增加「采集命名空间」输入(逗号分隔)
镜像:lghost/lokistack:latest + v0.1 = sha256:05b1505aedae
2026-10-27 03:30:25 +00:00
opsx
cf54be3f7d
fix(logs): 「所有人」策略保存被拒 + 快捷 LogQL namespace 空且不认默认策略
...
=== 一、保存策略组报「用户ID无效或重复」===
validatePolicyGroup 里 `if id == 0 || seen[id]` 直接把「所有人」哨兵当非法。
修复:
- 新增常量 AnyoneUserID = 0(与 policyGroupAccess、前端 ANYONE 对齐)
- 0 跳过用户存在性校验,但必须独占:与具体用户混选时报
「「所有人」不能与具体用户同时选择」
- 重复检查独立出来,报错带具体 ID
=== 二、快捷 LogQL 的 namespace 下拉总是空的 ===
两个叠加原因:
1. 用的是原生 <datalist>,只在输入时才提示、样式弱,看着像"下拉是空的"
2. 候选只来自 Loki 实际值 —— 而默认策略配的 default 命名空间里没有业务 Pod,
Loki 里根本没有这个 label 值,所以永远不出现;前端也不会拿策略值当默认选中
修复:
后端新增 GET /api/v1/logs/my-scope?sourceId= → {labels, unrestricted}
(services.UserAccessLabels 暴露当前用户在数据源上的授权 labels;
admin 返回 unrestricted=true 但仍带上策略 labels 供 UI 做默认值)
前端:
- logsApi.myScope()
- QuickQueryTemplates 用策略里的 namespace 作为初始选中值
- namespaceOptions = 策略值 ∪ Loki 实际值(去重,策略值优先)
- namespace/app/pod 三个 <datalist> 全部换成 SearchableValueSelect
(点击即展开、可搜索,placeholder 显示「请选择(共 N 个)」)
验证:
PUT /logs/policy-groups/1 {userIds:[0]} → 200 ✅
POST userIds:[0,2](混选) → 400「「所有人」不能与具体用户同时选择」✅
GET /logs/my-scope?sourceId=1 → {"labels":{"namespace":"default"},"unrestricted":true} ✅
bundle: my-scope 1 处、datalist 残留 0 处 ✅
镜像:lghost/lokistack:latest + v0.1 = sha256:ad659f564665
2026-10-27 02:59:33 +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
9f7c522157
feat: K8s 部署清单、Token 接入加固与日志/设置页优化
...
- kubernetes/: 30Gi PVC、单副本 Recreate、Secret/Service/NodePort/Ingress 清单与部署文档
- 数据安全: kubeconfig/token 统一加密存储,启动迁移历史明文,DB 0600
- Token 接入: 命名空间级最小权限提示、长期 Token、自签证书 TLS 兼容
- 部署: 命名空间级 Token 下跳过 Namespace patch/枚举,节点信息容错
- 日志页: namespace → app → pod 选择顺序与作用域收窄
- 设置页: 拆分为通用/告警/LDAP/镜像源四个 tab
- 弹框: 统一 max-h 滚动与长命令换行,修复内容溢出
2026-10-25 23:44:07 +08: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
673b2c60c8
feat: 新增「部署客户端」日志采集器模块
...
三种采集器(host-promtail / k8s-daemonset / k8s-fluentbit-sidecar),每种关联已部署 Loki:
- host-promtail:SSH 安装 Promtail(复用 deployBinary)
- k8s-daemonset:helm 安装 Promtail DaemonSet(复用 deployHelm)
- k8s-fluentbit-sidecar:kubectl patch 注入 Fluent Bit sidecar
含 Collector 数据模型、三个部署器、配置模板、CRUD API、前端页面。
附带 UI 优化:ErrorBoundary、部署卡片浏览器访问按钮、菜单名称调整。
Co-Authored-By: Claude <noreply@anthropic.com >
2026-06-29 19:26:41 +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