首页
/ OmniRoute 仪表盘导航重构实战:Monitoring 与 Costs 分区结构与源码实现解析

OmniRoute 仪表盘导航重构实战:Monitoring 与 Costs 分区结构与源码实现解析

2026-09-07 17:32:31作者:丁柯新Fawn

Monitoring & Costs(监控与成本)是 OmniRoute 网关仪表盘中最常被使用、也最容易因条目膨胀而变得难以导航的两类功能。本文基于 MONITORING_SECTIONS.md 记录的分区设计(对应 Group B / plan 16),系统梳理新版侧边栏的顶层分区顺序、独立出来的 Costs 一级分区、重组后的 Monitoring 三分组结构,并从仓库源码层面验证 Activity 与 Audit Log 的数据边界、HIGH_LEVEL_ACTIONS 白名单机制、旧路径重定向与 i18n 回退策略。读完你既能按新导航快速定位成本与监控功能,也能理解这套侧边栏定义的实现骨架,便于后续扩展自己的可见性/成本类模块。

高层面导航:分区顺序与侧边栏骨架

Group B 改造后,Dashboard 侧边栏的顶层分区(Section)按固定顺序排列,其定义全部收敛在 sections.tsSIDEBAR_SECTIONS 中:

Home
Providers        (OmniProxy 分区内,含 Endpoints、API Keys、Combos、Quota 等)
Analytics
Costs            ← 新增一级分区(Group B, plan 16)
Monitoring       ← 重组(Group B, plan 16)
Dev Tools
Agentic Features
Other Features
Configuration
Help

从源码结构看,每个分区对应 types.ts 中的 SidebarSectionId 联合类型(home | omni-proxy | analytics | costs | monitoring | devtools | agentic-features | other-features | configuration | help),分区可携带 visibility: "debug" 标记(如 Dev Tools)用于调试环境,也可声明 featureFlagKey(如 Radar 条目用 RADAR_ENABLED 做特性开关门控)。

顶层分区顺序是可通过设置调整的——sidebarVisibility.ts 提供了 applySectionOrder() / applyItemOrder()sidebarSectionOrder / sidebarItemOrder 持久化键;同时内置 5 个预设(all / essentials / minimal / developer / admin),对应 SIDEBAR_PRESETS,例如 admin 预设会额外展开 costs-pricingcosts-budgetcosts-quota-shareactivityauditaudit-mcpaudit-a2a 等运维条目,而 essentials 只保留核心路径。

Costs:独立的一级分区

成本类功能从原先嵌套在 Monitoring > Costs Parameters 的位置提升为独立一级分区,路由前缀统一为 /dashboard/costs/

条目 URL 说明
Overview(概览) /dashboard/costs 聚合成本看板(从 Analytics 迁入)
Pricing(定价) /dashboard/costs/pricing 按模型区分的价格表
Budget(预算) /dashboard/costs/budget 预算阈值与告警
Quota Sharing(配额共享) /dashboard/costs/quota-share Quota Share 池与用量
Plan Config(计划配置) /dashboard/costs/quota-share/plans 按 provider 的计划覆盖配置

Rationale(设计动机):Pricing、Budget、Quota Sharing 原本藏在 Monitoring > Costs Parameters,导致用户必须先进入可观测性工具才能触达成本管理。把它们提到一级分区,能让成本治理在不动用监控链路的前提下被直接发现。

sections.ts 中,成本类条目进一步细化为 COSTS_ITEMS(含 costscosts-pricingcosts-budgetcosts-free-tiersfree-provider-rankings 以及带 RADAR_ENABLED 特性的 radar),其中 costs-quota-share(指向 /dashboard/costs/quota-share)同时出现在 OmniProxy 分区,便于在配额管理语境中直达配额池。对应页面源码位于 costs/page.tsx/dashboard/costs/page.tsx)、costs/budget/page.tsx/dashboard/costs/budget/page.tsx)、costs/pricing/page.tsx/dashboard/costs/pricing/page.tsx) 与 costs/quota-share/page.tsx/dashboard/costs/quota-share/page.tsx)。

Monitoring:重组为「Activity + 三个分组」

重组后的 Monitoring 分区把 Activity 提到分组最顶部,其后跟随 3 个分组(Group):

Monitoring
├── Activity             ← 时间线信息流(顶层条目)
├── Logs group
│   ├── Logs (all)
│   ├── Proxy Logs
│   └── Console Logs
├── Audit group
│   ├── Audit Log
│   ├── MCP Audit
│   └── A2A Audit
└── System group
    ├── Health
    └── Runtime

sections.ts 中可看到该结构的精确表达:MONITORING_ITEMS 先放入 activity,随后依次展开 LOGS_GROUPAUDIT_GROUPSYSTEM_GROUP 三个 SidebarItemGroup(注意 getSectionItems() 会把 group 内的 items 摊平,用于隐藏项计算)。侧边栏图标强调色映射见 sidebarVisibility.ts 中的 SIDEBAR_ICON_ACCENTS(如 logs-activity: #60A5FAcosts: #FB923Caudit: #F43F5E)。

相对旧结构的变化对照

改造前 改造后
Activity 是 Logs 内的一个 tab,渲染的就是 Audit Log Activity 成为独立信息流(/dashboard/activity
Monitoring 中带 Costs Parameters 分组 已迁至独立 Costs 分区
扁平列表:Logs、Activity(logs)、Audit、Health、Runtime、Pricing、Budget、Quota 结构化 3 分组 + 独立 Costs 分区

Activity 与 Audit Log:两种语义、一个数据底座

改造后两者彻底区分。区分点可用下表快速记忆:

维度 Activity(/dashboard/activity Audit Log(/dashboard/audit
用途 面向用户的事件信息流(“最近发生了什么”) 合规 / 安全审计日志
数据来源 GET /api/compliance/audit-log?level=high GET /api/compliance/audit-log?level=all
展示形式 时间线、按天分组、人类可读动词 + 图标 密集分页表格,50 条/页
筛选 事件类型分类 动作、严重级别、操作者、时间范围
导出 不支持 JSON 导出
操作者筛选 不适用 支持按 actor 过滤
展示事件 仅高层级动作(白名单) 全部审计事件

值得强调的是两者共享同一数据底座——Audit Log API audit-log/route.ts 通过 level 查询参数区分返回集合,Activity 只消费 level=high 子集,Audit Log 消费 level=all 全量。换句话说:Activity 是白名单过滤后的“人话时间线”,Audit Log 才是完整的事实记录,二者天然互补而非替代。

HIGH_LEVEL_ACTIONS:Activity 的「顶层动作白名单」

哪些事件会进入 Activity 时间线,由 highLevelActions.ts 中的 HIGH_LEVEL_ACTIONS 白名单唯一决定。白名单覆盖了以下类别(Action 字符串与仓库内 logAuditEvent() 实际发射名严格对齐,源码注释明确要求“不要用自造的干净名字”):

  • Provider 增删改查/测试类provider.credentials.*(created / applied / updated / revoked / batch_revoked / batch_updated / bulk_created / bulk_imported / imported)以及 provider.validation.ssrf_blocked
  • API Key 生命周期:同步令牌 sync.token.created / sync.token.revoked
  • 认证登录登出auth.login.success / auth.login.failed / auth.login.locked / auth.logout.success
  • 设置变更settings.update / settings.update_failed
  • 敏感操作service.reveal_api_key
  • Quota 池与计划变更(Group B 新增):quota.pool.created / quota.pool.updated / quota.pool.deleted / quota.plan.updated / quota.store.driver_changed

名单之外的事件(例如细粒度的内部操作)只会出现在 Audit Log,不会污染 Activity 时间线。判定函数 isHighLevelAction(action) 底层用 Set 做常量级查找:

const SET: ReadonlySet<string> = new Set<string>(HIGH_LEVEL_ACTIONS);
export function isHighLevelAction(action: string): boolean {
  return SET.has(action);
}

新增一个高层级动作的正确姿势

若要让某类事件进入 Activity 时间线,需要按以下步骤走代码路径(白名单是代码而非数据库配置,因此必须走 PR 流程):

  1. 打开 highLevelActions.ts,先全局 grep logAuditEvent 确认上游事件发射名是否已存在;
  2. 把真实 action 字符串追加进 HIGH_LEVEL_ACTIONS 数组(严禁使用“美化过”的别名,否则列表与实际事件永远对不上);
  3. 同步在 activityIcons.tsACTIVITY_ICONS 中为该 action 注册图标与动词 i18n key,如:
    "quota.pool.created": { icon: "pie_chart", i18nKeyVerb: "quotaPoolCreated" },
    
    getActivityIcon() 对未注册的动作会回退到通用 info 图标与 genericEvent 动词,保证渲染不崩溃;
  4. 若上游发射名将来变化,须同时原子化更新发射点与白名单(源码注释明确强调这一点)。

Activity 页面的前端实现由 activity/page.tsx/dashboard/activity/page.tsx)(强制 dynamic 渲染)与其客户端组件 ActivityFeedClient 承担,时间线聚合逻辑在 src/lib/audit/timeline.ts

兼容旧路径:/dashboard/logs/activity 永久重定向

为避免破坏既有书签与集成,旧路径 /dashboard/logs/activity 通过 logs/activity/page.tsx/dashboard/logs/activity/page.tsx) 内的 permanentRedirect()HTTP 308 永久重定向至 /dashboard/activity

import { permanentRedirect } from "next/navigation";

export default function LogsActivityRedirect() {
  permanentRedirect("/dashboard/activity");
}

同时,旧侧边栏 ID logs-activity保留在 HIDEABLE_SIDEBAR_ITEM_IDS(见 types.ts)但移出 SIDEBAR_DEFINITIONS(sections.ts)。这样做的目的是兼容用户侧已持久化的隐藏项/排序配置(hiddenSidebarItemssidebarItemOrder 等设置键,常量定义见 sidebarVisibility.tsHIDDEN_SIDEBAR_ITEMS_SETTING_KEY 等),避免用户旧预设中引用的旧 ID 在规范化时被当作非法项丢弃——normalizeHiddenSidebarItems() 只会保留白名单内 ID,若从 HIDEABLE_SIDEBAR_ITEM_IDS 中删掉 logs-activity,老配置就会被静默清掉。

国际化:命名空间与多语言回退

Group B 新增的所有 UI 文案都走 next-intl,新增命名空间如下:

命名空间 key 覆盖内容
sidebar.costsSection Costs 分区标签
sidebar.activity Activity 侧边栏条目
sidebar.logsGroup Logs 分组标签
sidebar.systemGroup System 分组标签
sidebar.costsOverview Costs 概览条目
activity.* Activity 页面全部文案(标题、动词、筛选、空状态)

i18n 的真实性语言(source-of-truth locales)为 pt-BR 与 en,其余 41 个语言通过 next-intl 的 fallback 机制回退到英文(配置位于 src/i18n/config.ts)。前端组件侧的 fallback 也有一层兜底:sections.ts 中每条 SidebarItemDefinition 均带 labelFallback / subtitleFallback,用于翻译缺失时直接展示字面量,避免出现空标签。

关键实现文件速查

小结

本次重构的本质,是把「成本治理」与「可观测性」两类心智模型解耦:Costs 独立成区让预算与配额管理前置可及,Monitoring 以 Activity 时间线打头并收敛为 Logs / Audit / System 三组,使安全审计、日志排障、健康观测各归其位。Activity 与 Audit Log 共用一套审计数据底座却呈现两种视图,靠 HIGH_LEVEL_ACTIONS 白名单与 level 参数完成取舍,兼顾“易读”与“完整”。对开发者而言,若要扩展监控或成本模块,只需沿着侧边栏定义、白名单常量、图标映射与 i18n 命名空间四条代码链路做增量修改,即可让新功能无缝接入这套导航体系。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388