This is an automated email from the ASF dual-hosted git repository.

wu-sheng pushed a commit to branch blog/horizon-ui-cn-translations
in repository https://gitbox.apache.org/repos/asf/skywalking-website.git

commit a58ec325fd64633f0293e9975072880c9ae15911
Author: Wu Sheng <[email protected]>
AuthorDate: Mon Jun 29 00:46:14 2026 +0800

    docs(blog): add Chinese Horizon UI translations
---
 .../index.md                                       |  91 ++++++++++++
 .../index.md                                       |  85 ++++++++++++
 .../index.md                                       |  74 ++++++++++
 .../index.md                                       | 152 +++++++++++++++++++++
 .../index.md                                       |  91 ++++++++++++
 .../2026-06-22-horizon-ui-trace-explorer/index.md  |  92 +++++++++++++
 .../index.md                                       |  69 ++++++++++
 .../zh/2026-06-23-horizon-ui-log-explorer/index.md |  67 +++++++++
 8 files changed, 721 insertions(+)

diff --git a/content/zh/2026-06-21-horizon-ui-dashboards-and-mqe/index.md 
b/content/zh/2026-06-21-horizon-ui-dashboards-and-mqe/index.md
new file mode 100644
index 00000000000..c5937f6a30d
--- /dev/null
+++ b/content/zh/2026-06-21-horizon-ui-dashboards-and-mqe/index.md
@@ -0,0 +1,91 @@
+---
+title: "认识 Horizon UI · 2/17:会适配实体的仪表盘"
+date: 2026-06-21
+author: 吴晟
+description: "Horizon UI 系列第二篇:它的仪表盘如何由 MQE 
表达式驱动,如何隐藏不适用于当前实体的组件并在服务端跳过查询,以及如何把 1 显示成 OK、把 4.51e4 显示成 45.1k。"
+tags:
+  - Metrics
+  - Cloud Native
+---
+
+*本文翻译自英文原文:[Meet Horizon UI · 2/17: Dashboards That Adapt — MQE, Smart 
Widgets, and Numbers Humans Can 
Read](/blog/2026-06-21-horizon-ui-dashboards-and-mqe/),发布日期沿用原文日期。*
+
+这是 [Apache SkyWalking Horizon 
UI](/zh/2026-06-21-skywalking-horizon-ui-introduction/) 系列的第二篇。第一篇介绍了控制台和按 
Layer 组织的导航;这一篇讲你每天最常停留的界面:**仪表盘**。
+
+Horizon 里的每个仪表盘,本质上都是同一台机器:一个组件网格,每个组件都是一条由 BFF 解析并发往 OAP 的 **MQE 
表达式**。它值得单独写一篇,不只是因为能展示数字,而是因为它围绕数字做了很多实际工作:不适用于当前实体的组件会被隐藏,相关查询也完全不会发出;编码值和原始字节数会被渲染成人能读懂的形式;页面上所有图表都绑定到同一个游标;你还可以从一条慢
 SQL 记录直接跳到产生它的 Trace。下面逐项看。
+
+## 每个组件都是一条 MQE 表达式
+
+Layer 仪表盘是一个紧凑的 **12 列网格**:行高 120px,空隙会自动回填,避免墙一样的组件块出现洞;宽度低于约 1100px 
时会折叠成单列。每个格子是五类组件之一,而组件类型取决于 MQE 表达式返回数据的 *形状*:
+
+- **`card`**:表达式收敛为单个标量,比如 `latest(...)`、`avg(...)`、`service_sla/100`。显示一个大数字。
+- **`line`**:时间序列;每个表达式一条线,混合单位时可以使用双 Y 轴,比如左侧吞吐、右侧时延。
+- **`top`**:来自 `top_n(endpoint_cpm, 20, des)` 的排行列表,带一个小标签切换器,可以在 Traffic / 
Slow / Successful Rate 之间切换排序。
+- **`record`**:记录型输出,比如慢数据库语句或慢缓存命令:文本行加数值。
+- **`table`**:带标签的 `latest(...)` 指标,每组 label 一个表格行,比如每个服务的 pod phase、node 
condition、deployment replicas。
+
+你不需要手工选择图表类型;写好 MQE,合适的组件会自己渲染。而且每个层级都使用同一套网格系统。Layer 模板里的 
`dashboards.<scope>` map 会为 **service**、**instance** 和 **endpoint** 
页面携带不同的组件集合,所以向下钻取时,整个仪表盘会换成正确的 
scope。(这些都运行在[第一篇](/zh/2026-06-21-skywalking-horizon-ui-introduction/)介绍的 BFF 
层;浏览器不直接访问 OAP。)
+
+## 会适配当前实体的仪表盘
+
+这里有一个会改变仪表盘使用感受的能力。组件可以带一个 **`visibleWhen`** 
条件。如果条件不成立,组件不渲染;更关键的是,**它的查询也不会执行**。
+
+条件有两类:
+
+- **MQE metric**:只有表达式 *有值* 时展示组件(`op: exists`),或者只有值超过阈值时展示(`gt` / 
`lt`)。组件可以拿自己的指标做自我开关:JVM 组件带 `"visibleWhen": { "kind": "mqe", "expression": 
"instance_jvm_cpu", "op": "exists" }`,所以它们会出现在 Java 实例上,在 Go 实例上消失。
+- **Entity attribute**:在 Instance scope 上,根据选中实例的属性开关,比如 `language eq 
JAVA`,或者某个属性是否存在。
+
+因为条件在 **服务端** 计算,非 JVM 实例不只是把 JVM 格子藏起来;BFF 根本不会把这些查询发给 OAP。用同一个 Instance 
仪表盘打开一个 JVM 服务和一个非 JVM 服务,你看到的是一个模板在适配当前实体,而不是两套手工维护的页面。
+
+![图 1:Java 服务的 Instance 仪表盘,因为 `instance_jvm_cpu` 有数据,JVM 
组件组(CPU、heap、GC、threads、classes)会展示。](/screenshots/horizon-0.7.0/p02-dashboards-01-instance-jvm.webp)
+图 1:JVM 实例上会渲染 JVM 组件,因为它们的 `visibleWhen` 条件成立。</br>
+
+![图 2:同一个 Instance 仪表盘打开在 Go 的 rating 服务上,JVM 组件组不存在,网格已经重排;这些组件的查询没有发往 
OAP。](/screenshots/horizon-0.7.0/p02-dashboards-02-instance-go.webp)
+图 2:同一个仪表盘打开在 Go 实例上,JVM 组件不存在,查询也没有执行。一个模板,按实体适配。</br>
+
+## 数字要让人看得懂
+
+原始指标不一定是可读指标。Horizon 的组件会处理三类过去常让运维人员在脑子里换算的值:
+
+- **`enum`**:用 value→label map 把编码型 gauge 变成文字。`1/0` 成功指标会显示成 **`OK`** / 
**`Failed`**,而不是裸数字。label 可以按 locale 翻译。
+- **`duration`**:以秒为单位的指标会显示成人能理解的时间差,比如 **`5m 20s ago`**;在坐标轴上会压缩成 `5m` / 
`2h`。
+- **SI suffixes**:图表坐标轴和 tooltip 上的大数会显示成 
**`45.1k`**、**`1.34M`**、**`2.5G`**,而不是 `4.51e4`。坐标轴刻度和 hover 值使用同一套写法。
+
+![图 3:折线图的 Y 轴和十字线 tooltip 都使用紧凑 SI 后缀(45.1k、1.34M),刻度和 hover 
值保持同一写法。](/screenshots/horizon-0.7.0/p02-dashboards-03-si-suffix-axis.webp)
+图 3:高密度字节数和计数序列使用紧凑 SI 后缀,坐标轴和 tooltip 保持一致。</br>
+
+![图 4:两个 BanyanDB 卡片:"Last Sync" 通过 enum map 把编码 1 显示成 OK,"Time Since Last 
Sync" 通过 duration 格式把秒数显示成 "5m 20s 
ago"。](/screenshots/horizon-0.7.0/p02-dashboards-04-enum-duration-cards.webp)
+图 4:`enum` 和 `duration` 格式在 BanyanDB 生命周期卡片上的效果:`OK` 代替 `1`,"5m 20s ago" 
代替秒数。</br>
+
+## 把整个网格当成同一条时间线读
+
+页面上所有 `line` 图共享 **同一个 hover 游标**。指向吞吐图上的第 32 分钟,时延图、错误率图和每个 sparkline 格子上的第 
32 分钟也会一起亮起。这个契约在图表 wrapper 
层强制执行,任何组件都不能退出,所以页面读起来是一组围绕同一时刻协同的视图,而不是十几个互不相关的图。多序列 tooltip 是固定对齐的表格,展示每条序列的 
**title**(不会显示原始 MQE),所有值在同一列右对齐。
+
+![图 
5:同步十字线扫过吞吐、错误率和时延面板,一个游标、同一个时刻,所有图表对齐。](/screenshots/horizon-0.7.0/p02-dashboards-05-synced-crosshair.webp)
+图 5:一个游标跨过页面上所有折线图,所以你可以在所有图上同时读同一瞬间。</br>
+
+## 从慢记录一键跳到 Trace
+
+`record` 组件,比如 Slow Statements、Slow Commands、Slow Database 
Statements,是采样记录列表。每一行如果带 trace id,行首会出现一个 **jump-to-trace** 图标,点击即可打开对应 Trace 
的瀑布图。它按 **trace id** 解析,而不是按 Layer 解析,这点很重要:Virtual Database / Cache / MQ 服务上的 
Slow Statements 属于另一个 Layer 上的 *caller*,虚拟目标 Layer 自己没有 traces 标签页,但跳转仍然能落到正确 
Trace。语句文本本身也支持 **点击复制**。
+
+![图 6:Slow Statements record 组件。每条带 trace id 的采样行都有 jump-to-trace 
图标,语句文本可点击复制,其中一行显示 copied 
闪烁状态。](/screenshots/horizon-0.7.0/p02-dashboards-06-record-jump-to-trace.webp)
+图 6:从慢语句跳到执行它的 Trace。按 trace id 解析,所以即使虚拟 Layer 自己没有 traces 标签页也能工作。</br>
+
+## 固定并对比多个实体
+
+有时只看一个实体不够。Horizon 允许你 **锁定多个服务、实例或 endpoint,甚至来自不同服务的实体,并在当前页面内直接比较**。可以从选择器或 
instance/endpoint 列表固定实体;当前正在查看的实体始终属于对比组,会标记为 `CURRENT`,并继续驱动顶部 
header。每个固定实体都有自己的颜色。之后每个组件都会内联对比:line 组件为每个实体叠加一条序列,card 为每个实体显示一行,`top` 和 
`record` 组件增加按实体切换的标签页,table 增加 Entity 
列。持久的对比栏会保持这个实体组,不受底层列表分页或当前查看实体变化影响;每个实体单独发起请求,所以一个实体慢,不会把其他实体拖成空白。
+
+![图 7:对比来自不同服务的两个实例:app(标记 CURRENT)和 rating。在 Load、Latency、Success Rate 
折线组件中按颜色叠加显示,上方有对比栏。](/screenshots/horizon-0.7.0/p02-dashboards-07-pinned-entities.webp)
+图 7:锁定实体,甚至跨服务锁定,所有折线组件都会按颜色叠加;对比栏保持实体组,CURRENT 实体仍然驱动 header。</br>
+
+## 时间选择器驱动整个仪表盘
+
+顶部时间范围会驱动页面上的所有内容:header KPI 条、组件主体,以及 BanyanDB 分层 hot/warm/cold 存储里的 **Cold** 
pill 完整流程。过去落地页和拓扑路由固定在最近 60 分钟,所以选择 "12 days ago" 
后仍然会悄悄展示近期数字;现在时间选择器在所有地方都生效。上游控制变化时,每个依赖它的格子会明确重置并显示 "Reading data..." 提示,而不是在 
spinner 下面留着旧值。
+
+## 下一步去哪里
+
+需要强调的是,这是一套系统。同样的五类组件、同样的 MQE、同样的条件开关,会渲染每个 Layer 的仪表盘:上面的 JVM 面板、BanyanDB 
生命周期卡片、mesh 服务上的百分位时延,以及专门为 Envoy AI Gateway(token 
throughput、time-to-first-token)或 GenAI virtual layer(per-model estimated 
cost)设计的面板。不同 Layer 之间变化的是 MQE,不是机制。
+
+上面讲的是 *阅读* 体验。每个组件的 MQE、`visibleWhen` 条件、格式,以及每个 scope 的网格,都可以从 **Layer 
dashboards** 管理界面编辑。但这个创作流程(draft → preview → publish,以及可内联/展开的 MQE 
编辑器)会在后续文章里单独展开。字段级参考可以看文档里的 [dashboard 
widgets](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/components/dashboard-widgets/)
 和 
[charts](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/components/charts/)。
+
+下一篇:**topology and service dependency**,把 Horizon 在这里用图表展示的同一批数据,画成一张可以走进去看的地图。
diff --git a/content/zh/2026-06-21-horizon-ui-deployment-and-banyandb/index.md 
b/content/zh/2026-06-21-horizon-ui-deployment-and-banyandb/index.md
new file mode 100644
index 00000000000..5c89f253fe9
--- /dev/null
+++ b/content/zh/2026-06-21-horizon-ui-deployment-and-banyandb/index.md
@@ -0,0 +1,85 @@
+---
+title: "认识 Horizon UI · 4/17:Deployment 标签页与 BanyanDB 自观测"
+date: 2026-06-21
+author: 吴晟
+description: "Horizon UI 系列第四篇:Deployment 标签页把拓扑地图转向单个集群服务内部,展示它自己的实例;BanyanDB 
则按真实的角色和层级建模,让 SkyWalking 终于能像观测其他系统一样观测自己的数据库。"
+tags:
+  - Cloud Native
+  - Storage
+---
+
+*本文翻译自英文原文:[Meet Horizon UI · 4/17: The Deployment Tab & BanyanDB 
Self-Observability](/blog/2026-06-21-horizon-ui-deployment-and-banyandb/),发布日期沿用原文日期。*
+
+这是 [Meet Horizon UI](/zh/2026-06-21-skywalking-horizon-ui-introduction/) 
系列的第四篇。[第三篇](/zh/2026-06-21-horizon-ui-topology-and-dependency/)画的是服务 *之间* 
的地图。这一篇把同一套地图 **转向内部**,画到一个集群服务 *内部* 的实例上,并用它解决 SkyWalking 过去一直没有很好展示的问题:把 
**自己的存储引擎** BanyanDB 按它真实的集群形态建模出来。
+
+## Deployment 标签页:一个服务自身实例的地图
+
+服务地图回答“谁调用这个服务”。新的按 Layer 配置的 **Deployment** 标签页回答另一个问题:“*这个* 
服务是怎么部署的,它自己的实例之间又是怎么通信的?”选择一个服务后,这个标签页会把它的实例画成节点,并画出实例之间的调用关系。你已经在服务地图里见过的平移/缩放画布、健康
 ring 节点、边流动动画和每条调用的指标侧栏都会复用,只是 scope 收缩到单个服务内部。
+
+它不是一团扁平节点云,关键在三点:
+
+- **实例渲染成六边形,并组合成 pod。** 一个 pod 的 **main** container 是完整六边形,**sibling** 
containers 会作为更小的六边形贴在它边上。所以主进程和 sidecar 会读成一个单元,跨 pod 的 sidecar 
链接也会连到它真正所属的小六边形上。
+- **Pod 按你选择的规则聚到带标签的 box 里。** 规则可以是单个实例属性(role)、多个属性组合(比如 `node_role` + 
`node_type`),也可以是名称正则。这样一组混合角色节点会读成每个角色一个 box,而不是一团云。
+- **布局是分层的。** 每个 cluster box 会按调用深度摆放 pod:source 在左,被调用对象在右,所以 
upstream→downstream 链条可以从左到右读;拖动任意 pod 后,它所属的 box 会重新流式布局,保持内容都被包住。
+
+边按 **(source-role → target-role)** pair 建 
key,所以每类链接展示自己的指标,而不是共享一组扁平指标。主指标会直接印在边上,完整指标则进入 **Flows** 子标签页,每种 role-pair 
对应一张对齐表。它默认关闭,和服务地图一样,完全从 **Layer dashboards admin → Deployment scope** 配置。
+
+## 像观测其他系统一样观测 BanyanDB
+
+这套机制是为一个明确场景准备的。SkyWalking 的原生数据库 **BanyanDB** 是一个集群化、按角色和 tier 组织的系统,而过去 
SkyWalking 很难把它作为一个整体观测清楚。新的 **BanyanDB** Layer 位于 **Self-Observability** 下,并配合 
OAP 后端 SWIP-15,把通过 BanyanDB FODC proxy 抓到的指标建模成完整部署:
+
+- 整个 **cluster** 是一个 **Cluster**(service);
+- 每个 container 是一个 **Container**(instance),并携带 `container_name` **role** 和 
`node_type` **tier** 属性;
+- 每个存储 **Group** 是一个 **endpoint**。
+
+所以其他 Layer 中通用的 Service / Instance / Endpoint 脊柱,在 BanyanDB 这里就变成 **Cluster / 
Container / Group**。叠在上面的 Deployment 标签页,会直接画出这个数据库集群自身。
+
+![图 1:BanyanDB 的 Deployment 标签页。容器按 role/tier box 分组(liaison、data 
hot/warm/cold),以六边形 pod 形式展示,并带 role-pair 调用边和每个 role 自己的健康 ring 
指标。](/screenshots/horizon-0.7.0/p04-deployment-01-banyandb-deployment.webp)
+图 1:SkyWalking 观测自己的数据库:BanyanDB 集群按角色和 tier 绘制,并展示 pod 之间的 liaison→data 与 
lifecycle→data 边。</br>
+
+### Cluster、Container、Group
+
+每个 scope 都有专门设计的仪表盘:
+
+- **Cluster** 仪表盘是整个数据库的战情室:write / query / error-rate KPI、CPU / memory / disk 
capacity、吞吐和错误趋势,以及 **Containers by Role** 表。
+- **Container** 仪表盘会 **适配选中容器的 role**。每个容器都有 CPU / memory / Go runtime 
资源面板;**liaison** 会增加 ingestion、query、gRPC errors、tier-2 publish pipeline 和 
write-queue depth;**data** 节点会增加 storage totals、merge / compaction、inverted 
index、subscribe queue 和 retention;**lifecycle** sidecar 会显示 migration cycles 和 
last-run time / status。角色专属面板按容器 role 属性开关,所以你只会看到当前节点适用的内容。
+- **Group** 仪表盘按 **data model** 拆分:measure、stream、trace、property。因为一个 BanyanDB 
group 只存储一个 catalog,只有匹配该模型的面板会渲染:`measure` group 显示 write-rate / query-latency 
/ merge 面板,`property` group 显示 index-write / term-search / series 面板,以此类推。
+
+<figure 
style="display:flex;flex-wrap:wrap;gap:1.1rem;align-items:center;margin:1.5rem 
0;">
+<img src="/screenshots/horizon-0.7.0/p04-deployment-02-cluster-dashboard.webp" 
alt="BanyanDB Cluster 仪表盘:write/query/error KPI、CPU/memory/disk capacity,以及 
Containers by Role 表。" 
style="max-height:320px;max-width:100%;width:auto;border-radius:4px;">
+<figcaption style="flex:1 1 
240px;color:#5f6b7a;font-size:.92em;line-height:1.6;">图 2:Cluster 
scope,一眼看完整个数据库,并按角色列出所有容器。</figcaption>
+</figure>
+
+打开 *同一个* Container 仪表盘到两个不同 role 上,最容易看出 role-gating 的效果:
+
+<figure 
style="display:flex;flex-wrap:wrap;gap:1.1rem;align-items:center;margin:1.5rem 
0;">
+<img 
src="/screenshots/horizon-0.7.0/p04-deployment-03-container-dashboard.webp" 
alt="data/liaison 节点的 Container 仪表盘,在共享 CPU / memory / Go-runtime 资源面板上方显示角色专属的 
ingestion / storage 面板。" 
style="max-height:320px;max-width:100%;width:auto;border-radius:4px;">
+<figcaption style="flex:1 1 
240px;color:#5f6b7a;font-size:.92em;line-height:1.6;">图 3:data/liaison 
Container,在共享资源面板之上展示 ingestion、query、storage 和 compaction 面板。</figcaption>
+</figure>
+
+<figure 
style="display:flex;flex-wrap:wrap;gap:1.1rem;align-items:center;margin:1.5rem 
0;">
+<img 
src="/screenshots/horizon-0.7.0/p04-deployment-03-container-lifecycle-dashboard.webp"
 alt="同一个 Container 仪表盘打开在 lifecycle sidecar 上,只展示 migration-cycle 和 last-run 
面板。" style="max-height:320px;max-width:100%;width:auto;border-radius:4px;">
+<figcaption style="flex:1 1 
240px;color:#5f6b7a;font-size:.92em;line-height:1.6;">图 4:同一个仪表盘打开在 lifecycle 
节点上,只显示 migration 面板。同一模板,按 role 开关。</figcaption>
+</figure>
+
+**Group** scope 则给每个 storage catalog 一个自己的页面:
+
+<figure 
style="display:flex;flex-wrap:wrap;gap:1.1rem;align-items:center;margin:1.5rem 
0;">
+<img src="/screenshots/horizon-0.7.0/p04-deployment-04-group-dashboard.webp" 
alt="Group 仪表盘:某个 storage catalog 的按 data model 配置的面板。" 
style="max-height:320px;max-width:100%;width:auto;border-radius:4px;">
+<figcaption style="flex:1 1 
240px;color:#5f6b7a;font-size:.92em;line-height:1.6;">图 5:Group scope,一次查看一个 
storage catalog,它的面板按 group 的 data model 开关。</figcaption>
+</figure>
+
+### 认识 role pair 的边,以及 Flows 表
+
+Deployment 标签页中,容器之间的调用边会从 SWIP-15 instance-relation families 中拿到 
**role-pair-specific** 指标:**liaison → data** 边展示 write / query / part-sync 吞吐和 
p99;**liaison → liaison** 边展示 write-forward 和 control;**lifecycle → data** 边展示 
tier-migration volume / rate / p99。每条边最多内联显示三项属于该 pair 的指标,选中边面板保留完整 
client-vs-server 拆分,**Flows** 子标签页则把每条边按 role-pair 展开成一组对齐表。
+
+![图 6:Flows 子标签页。每条 container-to-container 边按 
role-pair(liaison→data、lifecycle→data 
等)展开成一张对齐表。](/screenshots/horizon-0.7.0/p04-deployment-05-flows-table.webp)
+图 6:Flows,把同样的 role-pair 边显示成可排序表格,每个 pair 一个区块。</br>
+
+这里有两个前提。边和角色专属面板假设你运行的是一个真实的 **集群化** BanyanDB;单进程 standalone 实例只会显示共享资源和 Go 
runtime 面板,其余面板会在集群角色开始上报后亮起来。尤其是 container-to-container 边,还需要 OAP 构建暴露 
`SERVICE_INSTANCE_RELATION` scope;在那之前,Deployment 标签页仍然会画完整 inventory,只是 pod 
之间没有边。
+
+## 配置出来的,不是写死的
+
+上面这些不是一张手工写死的 "BanyanDB screen"。聚类规则、每个 role 的节点指标、role-pair 边指标,都在 Layer 
template 中作为一个自包含块存在,可以从 **Layer dashboards admin → Deployment scope** 编辑,并随模板 
export/import 一起携带。它和其他 Layer 背后的配置驱动模型一样,后续文章会完整展开。
+
+下一篇:**3D Infrastructure Map**。同一个部署,以及所有其他 Layer,会从页面上抬起来,进入一张展示完整系统全貌的 WebGL 
视图。
diff --git a/content/zh/2026-06-21-horizon-ui-topology-and-dependency/index.md 
b/content/zh/2026-06-21-horizon-ui-topology-and-dependency/index.md
new file mode 100644
index 00000000000..f82fdfac4d8
--- /dev/null
+++ b/content/zh/2026-06-21-horizon-ui-topology-and-dependency/index.md
@@ -0,0 +1,74 @@
+---
+title: "认识 Horizon UI · 3/17:拓扑与服务依赖"
+date: 2026-06-21
+author: 吴晟
+description: "Horizon UI 系列第三篇:一套由模板驱动、可为每个 Layer 
重绘的拓扑引擎,降噪过滤器,从调用下钻到实例,endpoint 依赖图,以及跨 Layer 的 Smartscape 叠加视图。"
+tags:
+  - Cloud Native
+  - Tracing
+---
+
+*本文翻译自英文原文:[Meet Horizon UI · 3/17: Topology & Service 
Dependency](/blog/2026-06-21-horizon-ui-topology-and-dependency/),发布日期沿用原文日期。*
+
+这是 [Meet Horizon UI](/zh/2026-06-21-skywalking-horizon-ui-introduction/) 
系列的第三篇。[第二篇](/zh/2026-06-21-horizon-ui-dashboards-and-mqe/)讲的是如何把服务读成仪表盘上的数字;这一篇讲如何把服务读成一张
 **地图**:谁调用谁,调用有多重,以及同一个逻辑服务在不同上报 Layer 中是什么样子。
+
+SkyWalking 拓扑背后的调用数据是一份,但 Horizon 从中画出的 *视图* 不止一种。它有每个 Layer 
自己的服务地图,可以从单条调用下钻到背后的实例,可以看 endpoint 级依赖图,也可以用跨 Layer 
叠加视图把一个服务的多张面孔连起来。它们共用同一套引擎,只是回答的问题不同。(Deployment 标签页,也就是单个集群服务 *内部* 实例的地图,以及 
WebGL 3D 地图,都足够大,会在接下来的文章里单独讲。)
+
+## 一套拓扑引擎,按 Layer 重绘
+
+打开任意 Layer 的 **Topology** 标签页,你会看到一张从左到右排列的层次化服务地图:`User` 
存在时位于最左侧,每个服务按调用深度落在不同列里;同一列内部则保留图遍历到它们时的顺序,所以主调用链可以自上而下读。每个服务都是一个 
**六边形节点**,节点上展示的所有东西都来自这个 Layer 的配置,没有写死逻辑:
+
+- 六边形 **边框** 承载节点的 **ring** 指标,用类似 SLA 的健康色带展示(绿色 → 红色);
+- 组件 **图标** 放在六边形内部,和 Trace 瀑布图使用同一套图标,所以 PostgreSQL 节点像 PostgreSQL,Kafka 节点像 
Kafka;
+- 节点头部数字,也就是 **center** 指标,带单位显示在六边形 **上方**;
+- 服务 **名称** 显示在节点 **下方**,**secondary** 指标(默认是时延)显示在名称下面;
+- 每条 **边** 都带调用吞吐的 **RPM chip**,使用服务端指标,缺失时回退到客户端指标。
+
+这里需要强调一点:上面这些都只是 **General Layer 的内置默认配置**。节点的 center / ring / secondary 
指标,以及边指标,都位于 **Layer dashboards admin → Topology scope**,本质上是带单位和角色的 MQE 
表达式。所以你可以把任意槽位指向另一条指标,同一套引擎就会为另一个 Layer 画出不同地图,或者按你的方式重画当前 
Layer。(这些选择会像其他模板内容一样,跟着 Layer template 的 export/import 走。)
+
+![图 1:单个 Layer 的服务地图。六边形节点用边框表示 SLA 健康色带,节点上方显示主指标,内部显示组件图标,下方显示名称,每条边带 RPM 
chip。](/screenshots/horizon-0.7.0/p03-topology-01-service-map.webp)
+图 1:一套由模板驱动的拓扑引擎:带健康色带的六边形节点、带 RPM chip 的边、真实组件图标;图上的每个指标都按 Layer 配置。</br>
+
+## 削掉噪声
+
+真实拓扑通常很吵。一张密集地图里会混入 OAP 没法完整识别的推测节点,比如裸露的 `rcmd:80`、未接入探针的地址。Horizon 的 
**Filter** 控件可以关掉这些噪声,同时保留真实依赖。它会自动推导一个 facet:**按 Layer 分组**,展示方式和侧边栏一致。每一行都有 
Layer 自己的图标和本地化名称,比如 *Virtual Database*、*Java Agent*,还会有一个 **Others** 桶,用来收纳 
OAP 无法分类的节点,以及一个独立的 **User** 开关。取消勾选 *Others* 后,未接入探针的杂点和悬空边会消失,而数据库、缓存和队列(各自的 
`VIRTUAL_*` 行)仍然留在图上。过滤在客户端执行,行会在每次刷新时重新推导,所以不会陈旧。
+
+![图 2:拓扑 Filter。一个自动推导出的按 Layer facet(每行带 Layer 图标和名称)、一个 Others 桶,以及 User 
开关,用来从密集地图里去掉推测节点。](/screenshots/horizon-0.7.0/p03-topology-02-filter-denoise.webp)
+图 2:一键降噪,去掉无法解析的 "Others" 节点,同时保留真实依赖。</br>
+
+当某个 Layer 的服务落在 OAP service group 里,地图上的 service-focus 选择器也会按这些 group 分组。点击 
group header 可以 **批量选中或清空该组里的所有服务**,所以你能一次聚焦一张繁忙地图中某个团队负责的那一片。
+
+![图 3:感知 group 的服务选择器。服务按 OAP `Service.group` 分组,点击 group header 可一键聚焦或清空整个 
group。](/screenshots/horizon-0.7.0/p03-topology-03-group-selector.webp)
+图 3:从地图选择器里一次聚焦整个 service group。</br>
+
+## 从一条调用下钻到实例
+
+服务到服务的边是一条聚合调用;它背后是真实实例在和真实实例通信。点击地图上的一条调用并选择 **Instance map →**,Horizon 
会画出这层关系:客户端服务的实例在左列,服务端服务的实例在右列,中间是实例级调用,并带有客户端→服务端方向动画。它复用服务地图上的所有能力:健康 ring 
节点、每条调用的 client/server 指标侧栏、带 **Open instance dashboard** 的节点 popover,并且按 Layer 
自己的词汇标注列名,比如 Kubernetes 上叫 *Pods*,data plane 上叫 *Sidecars*。两个服务选择器是 **感知关系** 
的:server 列表来自当前 client 的 callees,client 列表来自当前 server 的 
callers;每次改动其中一个,另一个都会重新推导。
+
+![图 4:Instance 
map。客户端服务实例在左,服务端服务实例在右,中间是实例级调用,并带每条调用的指标侧栏。](/screenshots/horizon-0.7.0/p03-topology-04-instance-map.webp)
+图 4:从一条聚合调用下钻到背后的实例到实例流量。</br>
+
+## 按 endpoint 走完整请求链
+
+服务拓扑回答“哪些服务调用了这个服务”。**API dependency** 标签页回答更尖锐的问题:“哪些 *endpoint* 调用了这个 
endpoint,它又调用了哪些 endpoint”。选择一个 endpoint 后,图会按方向分列:callers 在左,焦点 endpoint 
在中间,callees 在右。它同样用 SLA 色边框、每条边上的 RPM 和时延,以及最重边标签。选中节点后会出现一个 **+** handle,一键拉入 
*它自己* 的 callers 和 callees,所以你可以一跳一跳走完整链路,而不是一次淹没在整张图里。拖开节点后,外跳链接(**Open 
endpoint**、**Service →**)会在新标签页打开,保留你正在探索的图。
+
+![图 5:API dependency 图。callers 在左,焦点 endpoint 在中间,callees 在右,通过 + handle 
扩展一跳,每条边带时延和 SLA 着色 
RPM。](/screenshots/horizon-0.7.0/p03-topology-05-api-dependency.webp)
+图 5:按 endpoint 一跳一跳走请求链,每条边都有时延。</br>
+
+## 一个服务在所有 Layer 里的样子
+
+一个逻辑服务经常会同时通过多个 Layer 上报:General agent、Service Mesh sidecar、mesh data 
plane、Kubernetes pod。SkyWalking 从 OAP 10 开始就建模了这种跨 Layer 层级关系;Horizon 
做的事情,是让它从地图上任何位置都能 **一键打开**。选中一个节点后,Horizon 会惰性探测它的 hierarchy。如果这个服务有跨 Layer 
peers,节点上会贴一个小的 **chevron-stack chip**。
+
+![图 6:选中的服务节点上带 chevron-stack chip,这是该服务还通过其他 Layer 
上报的提示。](/screenshots/horizon-0.7.0/p03-topology-06-smartscape.webp)
+图 6:选中节点上的 chevron-stack chip。它在选择时惰性探测,只在服务存在跨 Layer peers 时显示。</br>
+
+点击这个 chip,拓扑会在 **Smartscape** 叠加视图下变暗:焦点节点在原位高亮重绘,它的 peers 按 OAP 的 Layer 
顺序纵向展开,请求近端 Layer 在上,基础设施近端 Layer 在下。之后两步点击就能在对应 Layer 中打开任意 
peer,并完成预选。(叠加视图打开时自动刷新会暂停,避免内容在你眼前移动。)
+
+![图 7:Smartscape 叠加视图。一个逻辑服务投射到多个 Layer(General agent、Service Mesh、mesh data 
plane、Kubernetes),按 Layer 顺序展开,每个 peer 可一键进入自己的 
Layer。](/screenshots/horizon-0.7.0/p03-topology-06-smartscape-expand.webp)
+图 7:一个服务在所有上报 Layer 中的样子,以一键叠加视图展示跨 Layer hierarchy。</br>
+
+## 下一步去哪里
+
+这些地图上的每个指标、阈值和边权重,都位于 Layer template 的 `topology` 
块里。换句话说,你会用和仪表盘一样的配置驱动方式调整它们,这也是后续文章的主题。字段参考可以看 
[layer-template](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/customization/layer-templates/)
 里的 topology 文档。
+
+下一篇:**Deployment 标签页和 BanyanDB 自观测**。同样的地图技术会转向 *内部*,展示一个集群服务自身实例是如何部署、如何相互通信的。
diff --git a/content/zh/2026-06-21-skywalking-horizon-ui-introduction/index.md 
b/content/zh/2026-06-21-skywalking-horizon-ui-introduction/index.md
new file mode 100644
index 00000000000..9b1ae491c5e
--- /dev/null
+++ b/content/zh/2026-06-21-skywalking-horizon-ui-introduction/index.md
@@ -0,0 +1,152 @@
+---
+title: "认识 Horizon UI · 1/17:SkyWalking 新一代可观测性控制台"
+date: 2026-06-21
+author: 吴晟
+description: "介绍 Apache SkyWalking Horizon UI:基于同一个 OAP 后端重新设计的新一代 Web 
UI,从一条能实时反映系统全貌的侧边栏开始,让观测、运维、治理和定制都回到同一个控制台里。"
+tags:
+  - Release
+  - Cloud Native
+---
+
+*本文翻译自英文原文:[Meet Horizon UI · 1/17: SkyWalking's New Observability 
Console](/blog/2026-06-21-skywalking-horizon-ui-introduction/),发布日期沿用原文日期。*
+
+Apache SkyWalking Horizon UI 是 SkyWalking 的新一代 Web 控制台。它仍然连接你已经在运行的 OAP 后端:同样的 
GraphQL 查询协议,同样的 admin REST 接口,同样的 MQE 语言,同样的 `Layer` 概念。所以你可以直接把 Horizon 
指向一个正在运行的 OAP,然后登录使用,不需要改后端。变化发生在这个契约之前的整个用户界面。
+
+这是这个系列的第一篇。后续文章会依次介绍仪表盘和指标查询语言、拓扑视图、整个部署的 WebGL 3D 
地图、链路和日志探索器、性能剖析、运维界面、访问控制,以及把这些能力串起来的配置化定制。本篇先交代背景:Horizon 是什么,整个 UI 
围绕哪一个核心想法构建,以及今天如何把它接到你的 OAP 前面。
+
+Horizon 围绕四个动词展开。你先 **observe**:拓扑、链路、日志、五类性能剖析、只读告警,以及每个 Layer 的仪表盘。然后你可以 
**operate** 你正在观测的对象,**govern** 谁可以操作它们,并在不写 UI 代码的情况下 **customize** 
整个控制台。Observe、operate、govern、customize,就是这个系列的主线。我们从每次会话都会看到的地方开始:侧边栏。
+
+## 侧边栏就是你的系统全貌
+
+打开 Horizon,左侧边栏不是手工写死的菜单,而是 OAP 当前上报内容的实时映射。Horizon 会向 OAP 查询有哪些 Layer、哪些 
Layer 里有服务,然后只渲染这些内容,并每 60 秒刷新一次。某个 Layer 
开始上报,它就出现;安静下来,它就消失。菜单不会和现实漂移,因为菜单本身就是轮询出来的现实。
+
+![图 1:Horizon 首页,左侧是系统全貌(Layer 分组为 Virtual Targets、Istio、Kubernetes 和 
MQ,并显示实时的 "13 with services" 计数),右侧是跨 Layer 的 Services 
概览。](/screenshots/horizon-0.7.0/p01-intro-01-sidebar-is-the-estate.webp)
+图 1:Horizon 首页,左侧是实时系统全貌,右侧是跨 Layer 的 Services 概览。</br>
+
+这个侧边栏里有几个关键点:
+
+- **实时服务计数。** **Layers** 标题显示当前有多少个 Layer 包含服务,图 1 中是 *13 with services*。展开每个 
Layer 后,也能看到它自己的服务数量。这些计数来自同一个服务端目录,整个 UI 共用,并且每分钟刷新一次,所以侧边栏、告警 Layer 
标记器和落地页不会因为各自轮询而出现不一致。
+- **按组组织,而不是平铺列表。** Layer 会放在自己的分组下,比如 *Virtual 
Targets*、*Istio*、*Kubernetes*、*MQ*。顶部是 **Overviews** 和 
**Alarms**,运维和管理区域(Cluster Status、Alerting rules、DSL Management、Users、Roles & 
permissions)放在更靠下的位置,并且只对有权限打开它们的角色展示。访问控制直接织进了菜单,而不是事后再补一层。
+- **不会静默隐藏内容。** OAP 上报的每个 Layer 现在都会出现。即使没有内置模板,也会回退到一个普通的 Service 页面。过去有一份写死的 
"hidden layers" 列表,会悄悄隐藏 `BanyanDB` 这样的 Layer;现在这件事被移除了。想隐藏某个 Layer,需要在 
`horizon.yaml` 里通过 `layers.excluded` 明确配置。默认值是 `FAAS` 和 
`VIRTUAL_GATEWAY`;清空列表就可以展示所有 Layer。
+
+点击任意 Layer,Horizon 会打开它的第一个可用标签页。所有 Layer 都沿用同一条脊柱:
+
+```text
+service → instance → endpoint → topology → trace → logs → profiling
+```
+
+槽位名称会跟随 Layer 的语义变化。图 2 中的 General Service Layer 会把 endpoint 槽位命名为 
**API**,增加一个 **API dependency** 视图,并把 **Profiling** 
展开成它实际拥有的引擎:Trace、eBPF、pprof(Go)和 Async。某个 Layer 
不支持的标签页会在模板里直接关掉,所以你不会落到空页面上。选中一个服务后,右侧画布就是这个服务的仪表盘:上方是一排 
KPI(RPM、Apdex、错误率,每个都有自己的 sparkline),下方是只针对这个实体的组件网格。
+
+![图 2:展开一个 Layer 后,它会展开成完整操作路径。这里 General Service 显示 
Service、Instances、API、Topology、API dependency、Traces、Logs 和四个 profiling 
引擎,右侧画布显示选中服务的仪表盘。](/screenshots/horizon-0.7.0/p01-intro-02-layer-drilldown.webp)
+图 2:展开一个 Layer 后进入完整流程,左侧是标签脊柱,右侧是选中服务的仪表盘。</br>
+
+## 不再给你一个空白页
+
+一个跟随实时数据变化的控制台,必须能处理“没有数据”的时刻:全新安装、配置不完整的部署,或者刚刚重启的 OAP。Horizon 
把这些都当成一等状态,而不是死胡同。
+
+打开 `/` 时,Horizon 会逐级落到一个真实目的地:第一个可用的公共 overview 仪表盘;如果没有,就进入第一个有服务的 
Layer;只有两者都不存在时,才展示空落地页。真的进入空页面时,它会用明确语言告诉你问题在哪里:**"No data is flowing yet"** 
表示还没有任何内容上报,**"No dashboard configured yet"** 表示已经有服务,但没有配置 
overview。它会指向运维团队,而不是把你丢在一个空网格上。只要有服务开始上报,或者运维人员发布了仪表盘,下一次 60 秒刷新就会把空页面替换成真实页面。
+
+![图 3:空落地页明确说明当前状态。这里是 "No dashboard configured yet"(服务已经上报,但没有配置 
overview),而不是显示空仪表盘。](/screenshots/horizon-0.7.0/p01-intro-03-empty-no-dashboard-configured.webp)
+图 3:空落地页说明真实原因。这里是服务已经上报,但没有配置 overview,而不是给出一个空仪表盘。</br>
+
+OAP 短暂不可达时,Horizon 也遵循同样思路。如果后端短时间连不上,Horizon 会保留最后一次已知的侧边栏结构,并显示 "OAP 
unreachable" 横幅,服务计数标记为未知,直到恢复为止。短暂故障不会看起来像配置突然消失。
+
+当数据正常流入时,落地页就是图 1 里看到的战情室:跨 Layer 概览、按类型拆分的服务卡片(General services、Virtual 
databases、caches、MQs、GenAI)、实时拓扑和活跃告警栏。每个 Layer 自己的落地页会按你选择的列真正计算 top-N 
服务,不再先截取任意前 25 个再排序;页面还会告诉你 "top N of M",所以截断不会悄悄发生。
+
+长 Layer 名称和深命名空间也很常见,所以 shell 
会主动让出空间:拖动分隔线可以调整侧边栏宽度,双击重置;也可以折叠成一条窄图标栏,把水平空间尽量交给画布。宽度会按浏览器记住。
+
+![图 4:拖动分隔线加宽侧边栏,长 Layer 
名称和命名空间不再被截断。](/screenshots/horizon-0.7.0/p01-intro-04-resize.webp)
+图 4:拖动分隔线加宽侧边栏,长名称不再被截断,宽度会按浏览器记住。</br>
+
+![图 
5:把侧边栏折叠成窄图标栏,把每一个水平像素都留给画布。](/screenshots/horizon-0.7.0/p01-intro-04-fold-rail.webp)
+图 5:需要最大画布空间时,可以把侧边栏折叠成窄图标栏。</br>
+
+## 新增一层,后面的能力才成立
+
+过去,SkyWalking Web UI 是浏览器直接访问 OAP。Horizon 在中间加了一小层基础设施:**Backend-for-Frontend 
(BFF)**,一个运行在 Node.js 上的 Fastify 服务。它负责提供 UI,并代理所有到 OAP 的调用。
+
+![架构图:浏览器只访问 Horizon BFF(运行在 Node.js 上的 Fastify 服务)。BFF 处理认证和会话、RBAC 
校验、审计日志、能力探测和缓存、服务端 i18n 与组件开关,然后代理到 OAP 的 GraphQL query host(端口 12800)和 admin 
host(端口 17128)。](/screenshots/horizon-0.7.0/p01-intro-architecture.svg)
+*浏览器只访问 BFF;BFF 负责 auth、RBAC、audit、capability probing,以及服务端 i18n / widget 
gating,然后代理到 OAP 的 query host(`:12800`)和 admin host(`:17128`)。*
+
+后续文章里很多能力都依赖这一层。认证、基于角色的访问控制和审计都在服务端执行,伪造请求绕不过去。BFF 启动时会探测一次 OAP 的 GraphQL 
schema,某个能力不存在时就优雅降级;Horizon 能用同一个构建支持两代 OAP,靠的就是这个机制。它还会每分钟缓存一次服务目录,让整个 UI 
对系统全貌持有同一份视图。运维、安全和定制相关的文章会分别展开这些内容;这里先记住一点:现在这里有一个服务端,它承担了实实在在的工作。
+
+## 用 3D 看完整部署
+
+有一个界面值得先提前看,因为它最能表达“后退一步,一次看清全局”的想法:**3D Infrastructure Map**。每个 Layer 
的服务都会变成立方体,堆叠到按请求流向排列的层级上,实时流量、告警和调用关系都画在它们之间。拖动即可旋转:
+
+{{< map3d poster="/images/home/horizon-3d-map.png" badge="交互演示 · 示例数据" >}}
+
+后续有一篇专门拆解 3D 地图:层级、告警信标、让健康对象变成幽影而只突出告警对象的 "Beacon mode",以及配置它的结构化编辑器。现在先把它当成 
Horizon 目标的一个缩影:整个部署放在一个视图里,而且是活的。
+
+## 这个系列会讲什么
+
+本篇之后还有十五篇,每篇都会独立介绍 Horizon 的一个角落。可以按任意顺序阅读,每篇也都会链接回这里。它们分成四条主线。
+
+**看见你的数据**
+
+1. **Dashboards & MQE**:只查询当前实体相关数据的组件、人类可读的数值格式、同步十字线和多实体对比。
+2. **Topology & service dependency**:一套可为每个 Layer 重绘的拓扑引擎、降噪过滤器和多跳 API 
dependency 图。
+3. **The Deployment tab & BanyanDB self-observability**:深入单个集群服务内部的视图,以及 
SkyWalking 终于像观测其他对象一样观测自己的数据库。
+4. **The 3D Infrastructure Map**:完整展开上面这个 3D 视图。
+5. **Trace explorer**:在时延散点图上框选慢 Trace,然后用三种方式阅读同一条 Trace。
+6. **Log explorer**:类似 Loki 的日志流,带 facets、top patterns 和结构化 payload。
+7. **Browser & RUM monitoring**:前端错误日志,以及把混淆后的栈恢复到原始源码行。
+8. **Five profilers, one flame graph**:trace、async-profiler、eBPF、Go pprof 和 
network profiling,统一到同一套工作方式里。
+
+**运维它**
+
+9. **Alarms & incident triage**:以 incident 为中心的活跃告警,并带上触发它的图表。
+10. **Runtime rules, live debugging & inspect**:可热加载规则,以及用实时样本逐步调试 
OAL(traces)、MAL(metrics)和 LAL(logs)的 Live Debugger。
+11. **Platform & cluster introspection**:在 UI 里查看 OAP 集群健康、最终解析后的配置和数据保留策略。
+
+**治理和保护它**
+
+12. **Access control & security**:服务端强制执行的 RBAC、LDAP/AD、审计轨迹和 break-glass,让 UI 
可以进入企业部署。
+
+**把它变成你的控制台,并完成接入**
+
+13. **Customization: config-driven layer templates**:从 draft 到 publish,不写 UI 
代码也能增加一个全新的被监控 Layer。
+14. **Localization**:八种语言的仪表盘,并且可以在实时预览里点击组件完成翻译。
+15. **Getting started & migration**:安装、OAP 版本矩阵,以及如何用 Horizon 替换现有 UI。
+
+## 今天就接到你的 OAP 上试试
+
+Horizon 可以运行在你已有的 OAP 之上。在今天的 **OAP 10.x** 上,绝大多数功能已经可用:所有仪表盘、拓扑、Trace(原生和 
**Zipkin**)、日志、告警,以及五类性能剖析,都通过 OAP 的 query host(`:12800`)渲染。Horizon 
的访问控制、审计和主题运行在 BFF 里,不依赖 OAP 版本。需要等待 **OAP 11.0** 的是 *operate* 
层:runtime-rule(DSL)管理、Live Debugger、Metrics Inspect、告警规则编辑器、Cluster Status 
管理面板,以及把模板编辑发布回 OAP。这些依赖 admin host(`:17128`),即将随 OAP 11.0 发布。Horizon 会按 admin 
module 是否存在来探测能力,10.x 不能提供的页面会直接隐藏;完整观测控制台今天就能跑在 10.x 上,迁移到 11.0 后运维工具会自动亮起来。
+
+把 Horizon 指向已有集群即可启动,不需要改后端。仍然是你的部署已经在使用的那个 OAP:
+
+```sh
+docker run -d --name horizon \
+  -p 8081:8081 \
+  -v "$PWD/horizon.yaml:/app/horizon.yaml:ro" \
+  -v horizon-state:/data \
+  ghcr.io/apache/skywalking-horizon-ui:<version>
+```
+
+最小化的 `horizon.yaml` 只需要说明 OAP 在哪里,以及一个可登录的本地用户:
+
+```yaml
+oap:
+  queryUrl: http://<oap-host>:12800
+  adminUrl: http://<oap-host>:17128
+auth:
+  backend: local
+  local:
+    users:
+      - username: admin
+        passwordHash: "$argon2id$v=19$..."   # generated, never plaintext
+        roles: [admin]
+```
+
+打开 `http://<host>:8081/`,登录后第一站是 **Cluster Status**,确认 Horizon 和 OAP 
能正常通信。之后侧边栏就会填入你的系统全貌。
+
+完整安装路径,包括 binary tarball、Kubernetes、LDAP、TLS 和生产检查清单,请看 [Horizon UI 
文档](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/readme/)。左侧菜单里覆盖了安装、兼容性、访问控制、定制、组件和运维。
+
+## 其他值得注意的点
+
+- **可以直接接入现有 OAP。** Horizon 是一次从零开始的重写,但保留了所有后端契约:同样的 GraphQL 查询协议、admin REST 
接口、MQE 语言和 `Layer` 概念。所以你可以把它指向一个正在运行的集群,不改后端。今天的 **OAP 10.x** 
已经能运行完整观测控制台(仪表盘、拓扑、包括 **Zipkin** 在内的 Trace、日志、告警、性能剖析),以及 Horizon BFF 
侧的访问控制、审计和主题。只有 *operate* 工具链需要等待 OAP 的 **admin host**(`:17128`),也就是随 **OAP 
11.0,即将发布** 的 runtime rules、Live Debugger、Inspect、Cluster Status admin pane 
和模板编辑发布。
+- **暗色优先,高密度。** 12 列网格面向 incident 扫描设计,首屏承载更多信号,减少不必要留白。
+- **基于现代技术栈。** 前端是 Vue 3 + TypeScript on Vite、Pinia、Apache ECharts、D3 和 
Monaco;BFF 使用 Node.js 上的 Fastify。
+- **Apache 许可证,社区共建。** Horizon UI 位于 
[apache/skywalking-horizon-ui](https://github.com/apache/skywalking-horizon-ui)。欢迎接到你的集群上试用,也欢迎告诉我们缺什么,issue
 和 pull request 都可以。
+
+下一篇:仪表盘,以及为什么一个组件可以在服务端判断自己不适用于当前实体,并且连查询都不发。
diff --git a/content/zh/2026-06-22-horizon-ui-3d-infrastructure-map/index.md 
b/content/zh/2026-06-22-horizon-ui-3d-infrastructure-map/index.md
new file mode 100644
index 00000000000..6ef2be5c2ab
--- /dev/null
+++ b/content/zh/2026-06-22-horizon-ui-3d-infrastructure-map/index.md
@@ -0,0 +1,91 @@
+---
+title: "认识 Horizon UI · 5/17:3D 基础设施地图"
+date: 2026-06-22
+author: 吴晟
+description: "Horizon UI 系列第五篇:用一个 WebGL 视图查看整个部署,把每个 Layer 的服务渲染成立方体并堆叠到不同 
tier 上,同时显示实时流量、告警信标和调用关系。"
+tags:
+  - Cloud Native
+  - Engineering
+---
+
+*本文翻译自英文原文:[Meet Horizon UI · 5/17: The 3D Infrastructure 
Map](/blog/2026-06-22-horizon-ui-3d-infrastructure-map/),发布日期沿用原文日期。*
+
+这是 [Meet Horizon UI](/zh/2026-06-21-skywalking-horizon-ui-introduction/) 
系列的第五篇。[第三篇](/zh/2026-06-21-horizon-ui-topology-and-dependency/)画的是服务 *之间* 
的地图,[第四篇](/zh/2026-06-21-horizon-ui-deployment-and-banyandb/)画的是单个服务 *内部* 
的地图。这一篇把视角完全拉远:用一个 **WebGL** 视图一次看完整个部署。每个 SkyWalking Layer 的服务都会渲染成立方体,堆叠到 3D 
空间里,并显示实时流量、告警和它们之间的调用关系。它是按 Layer 仪表盘之外的鸟瞰视角:退后一步,看全局。
+
+它也确实可以交互。所以与其冷冰冰描述,不如直接放出来:下面就是运行在 demo 示例数据上的真实地图。拖动旋转,滚轮缩放,点击立方体:
+
+{{< map3d poster="/images/home/horizon-3d-map.png" badge="交互演示 · 示例数据" >}}
+
+## 一个场景看完整系统
+
+3D 地图是 `/3d/map` 下的独立全屏视图,从顶栏里的 **3D Infra** pill 
打开。它刻意拿掉控制台其余部分:没有侧边栏,没有顶栏,没有全局时间选择器。整个 viewport 都交给场景。SkyWalking 标识放在左下角,右上角的 
`×` 返回 Horizon。里面所有数据都来自 Horizon 其他页面访问的同一个 OAP:服务清单、每个 Layer 
的拓扑、每个服务的流量,以及活跃告警。
+
+![图 1:3D Infrastructure Map。每个 Layer 的服务渲染成立方体,按品牌色分组为每个 Layer 的 zone,并堆叠到横向 
tier 上,右侧是 tier/layer 
面板。](/screenshots/horizon-0.7.0/p05-3dmap-01-overview.webp)
+图 1:一个场景看完整部署:服务是立方体,Layer 是带颜色的 zone,角色按 tier 堆叠。</br>
+
+## Tier 是骨架
+
+**Tier** 是一层水平平面,用来把系统中角色相关的 Layer 放在一起。Tier 
从上到下的阅读顺序,就是请求流动的大致方向:从用户触达的应用,一路到底层平台。Horizon 内置四个 tier:
+
+- **Apps**(顶部):应用界面和应用视角看到的依赖,包括 General agent services、Browser/RUM、mobile,以及 
`Virtual*` targets(database、cache、MQ、gateway、GenAI)。
+- **Middleware**:数据和消息服务、网关,以及自观测组件,包括 
MySQL、PostgreSQL、Redis、Kafka、RocketMQ、APISIX、Nginx、SkyWalking SO11Y components 
和云托管数据服务。
+- **Service Mesh**:承载应用流量的 mesh,包括 Istio control/data plane、Cilium、Envoy AI 
Gateway。
+- **Infra**(底部):其余内容运行在其上的平台,包括 Kubernetes、hosts、VMs。
+
+OAP 上报的每个 Layer 都会落到一个 tier。Horizon 还没分类的新 Layer,比如 OAP 新增的 Layer,会落到 
**failover tier**(默认 Middleware)并带 "unclassified" 
标记。这样它会出现,运维人员也可以重新分配,而不是静默从地图上消失。右侧面板映射了整个堆栈:点击 tier 
行可以把相机飞到对应位置,用眼睛开关一次显示或隐藏整个 tier(或单个 Layer),并查看当前可见服务数量。
+
+## 怎么读地图:立方体、zone、流量
+
+每个 **立方体就是一个服务**。立方体会在 tier 上按所属 Layer 聚成一个 **zone**:半透明矩形使用该 Layer 的品牌色,并盖上项目 
logo(Istio 的帆、Kubernetes 舵轮、数据库圆柱、队列图标),所以任何相机角度下都能辨认出 zone。带拓扑的 
Layer(General、Service Mesh、Kubernetes Service、Cilium)会按 **调用依赖** 摆放立方体:上游 
caller 在一侧,下游服务在另一侧,对应 2D 服务地图的 3D 版本。没有拓扑的 Layer 则把立方体排成整齐网格。
+
+立方体下方的小 **traffic pill** 显示该服务的实时主吞吐:应用和 mesh 服务是 requests per minute,数据服务是 
queries 或 operations per second,并保留各自单位。只有足够近、可读时 pill 
才出现;缩远后会淡出,保持场景干净;选中的立方体总会显示它的数字。
+
+## 告警,以及 incident 用的 Beacon mode
+
+当一个服务有 **当前正在触发的告警** 时(Horizon 轮询最近 20 分钟,并只统计 service scope 下仍在触发的告警),它的立方体会 
**红色脉冲**。这就是一个信标,即使隔着整个场景也能看到,而告警 feed 会独立刷新。
+
+在繁忙地图里,几百个立方体中的一个红点仍然可能难找,所以有 **Beacon mode**。从工具栏打开后,所有 *健康* 立方体都会变成深色 
wireframe 幽影,只留下正在告警的服务发光。部署形状仍然可读,但真正出问题的服务才有颜色。它把鸟瞰图一键变成 incident triage 界面。
+
+![图 2:Beacon mode。所有健康立方体变成 wireframe 
幽影,只有正在触发告警的服务保持红色发光。](/screenshots/horizon-0.7.0/p05-3dmap-02-beacon-mode.webp)
+图 2:Beacon mode 会把健康对象变暗成幽影,所以你只会看到正在触发的服务。</br>
+
+## 对象之间的线
+
+地图不只画节点,也画调用图:
+
+- **In-layer calls**:同一个 Layer 内两个服务之间的浅青色管线,并带沿线运动的数据包动画。这是每个 Layer 
自己的内部调用图,始终开启。
+- **Cross-layer calls**:同一个 tier 上不同 Layer 服务之间的柔和琥珀色箭头,比如 Browser app 调用 
Frontend、Frontend 调用 Virtual Database,方向从 caller 指向 callee。
+- **Hierarchy links**:这是让 3D 布局真正发挥价值的一类线。选中一个立方体后,粗灰色管线会连接 **同一个逻辑服务在不同 tier 
上的多张面孔**:agent 看到的服务、mesh 看到的服务、Kubernetes service 看到的服务。它们表示 
*身份*,不是流量,所以默认隐藏;选中立方体后只显示它自己的 relatives,并沿着 tier 
一层层爬上去。这就是[第三篇](/zh/2026-06-21-horizon-ui-topology-and-dependency/)里的 
Smartscape,用它本来就该拥有的维度画出来。
+
+![图 3:选中一个服务后,详情卡片出现在立方体旁边,跨 tier hierarchy links 亮起,把 Apps、Service Mesh 和 
Infra tier 
中的同一个逻辑服务连起来。](/screenshots/horizon-0.7.0/p05-3dmap-03-selected-hierarchy.webp)
+图 3:选中立方体后,身份链接沿 tier 爬升:同一个服务,被 agent、mesh 和 Kubernetes 分别看到。</br>
+
+## 怎么移动
+
+拖动旋转,滚轮缩放,**方向键** 或 **WASD** 平移视角(按住 **Shift** 
步长更大);左上角工具栏也为触控板提供同样动作的按钮。有一条刻意设计的规则值得知道:**3D 
场景里的点击永远不会移动相机**,只负责选择。点击一个立方体,它会高亮,旁边出现详情卡片(服务名称、tier、Layer,以及会在新标签页打开该服务 
Layer 仪表盘的 **Open dashboard** 按钮),它的 hierarchy links 也会亮起。移动相机的交互面是 *侧边面板* 和 
*工具栏*;点击 Layer 行,相机会滑到它的 zone。把“选择”和“移动相机”分开,点击小立方体才会可靠,不会刚点中它就让它从光标下滑走。
+
+## 它如何构建场景
+
+完整部署数据太大,不适合一次请求拉完,所以地图分阶段加载,底部细长的 **timeline strip** 
会实时展示进度:**Services**(服务清单和所属 Layer)→ **Templates**(哪些 Layer 带拓扑)→ 
**Topologies**(每个有拓扑 Layer 的调用图)→ **Hierarchy**(跨 tier 身份链接)→ 
**Layout**(摆放立方体)→ **Metrics**(按批次获取每个服务的流量,让立方体逐步亮起来)。点击任意阶段可以打开抽屉查看详情,也可以点击 
refresh 重新跑完整流程。
+
+两个设计让刷新变便宜。**Hierarchy** 
阶段是增量的:只有上次之后新增的服务需要探测,其余从缓存复用,所以稳定部署在这一步没有额外代价。场景还会按每个 Layer 的结构 hash 重新 
key;结构没变时刷新会保留你的相机位置,只有服务清单或边真的变化时才重建布局。底层使用 [Three.js](https://threejs.org/) 
加一层很薄的 Vue wrapper,同类立方体共享 geometry 和 material。正是这类细节,让几百个服务也能在浏览器标签页里平滑渲染。
+
+## 配置出来的,不是写死的
+
+上面这些不是一张写死的 "3D screen"。地图展示什么,由管理员在 `/admin/3d-map` 的 **结构化表单编辑器** 
里编辑:tier、Layer、颜色和指标都通过表单控制,而不是直接写 JSON。你可以在里面:
+
+- **用一个全局正则过滤 Layer**:匹配排除的内容会完全从地图上消失。
+- **安排 tier**:重命名、从上到下重排,并把每个 Layer 固定到某个 tier 上,同时指定 failover tier,避免内容静默丢失。
+- **对 Layer 分组**:把多个相关 Layer,比如 SkyWalking 自观测组件,聚成一个带标签的 block,每个成员仍然保留自己的颜色。
+- **为每个 Layer 配色并选择流量指标**:配置 MQE 表达式、label 和单位;默认值会从该 Layer 的仪表盘模板里初始化,所以大多数 
Layer 一开始就能显示合理数字。
+
+Horizon 自带一份默认配置,所以地图开箱就有用。你的修改会以本地 draft 保存,直到点击 **Check diff & push** 发布到 
OAP。它使用和仪表盘相同的 draft → preview → publish 模型,也支持同样的 
Export/Import,用于备份或在部署之间迁移配置。地图本身是只读 **observe** 界面,可以直接运行在当前 OAP 
上;发布塑造它的配置,则属于后续文章会完整介绍的配置化定制能力。
+
+![图 4:3D-map 配置。`/admin/3d-map` 提供结构化编辑器,用于配置 tier、每个 Layer 的颜色和流量指标、Layer 
group 和全局过滤器,并使用常规 draft → Check diff & push 
发布流程。](/screenshots/horizon-0.7.0/p05-3dmap-04-config-editor.webp)
+图 4:地图是配置,不是代码。tier、颜色和每个 Layer 的流量指标都以表单方式编辑,然后发布到 OAP。</br>
+
+## 下一步去哪里
+
+3D 地图是鸟瞰摘要;2D 的按 Layer 页面仍然是权威服务地图。查看它只需要读权限(`infra-3d:read`,内置 viewer 
角色及以上持有);塑造它需要和仪表盘相同的写权限。字段参考,包括 tier、配置结构和加载阶段,可以看 [3D Infrastructure Map 
文档](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/operate/infra-3d-map/)。
+
+下一篇:**Trace Explorer**。从整个部署的鸟瞰图,回到单个请求,并用三种方式画出来。
diff --git a/content/zh/2026-06-22-horizon-ui-trace-explorer/index.md 
b/content/zh/2026-06-22-horizon-ui-trace-explorer/index.md
new file mode 100644
index 00000000000..096457649f8
--- /dev/null
+++ b/content/zh/2026-06-22-horizon-ui-trace-explorer/index.md
@@ -0,0 +1,92 @@
+---
+title: "认识 Horizon UI · 6/17:Trace Explorer"
+date: 2026-06-22
+author: 吴晟
+description: "Horizon UI 系列第六篇:按 Layer 使用的分布式 Trace 
探索器,支持分阶段条件、可框选的时延分布图、三种阅读同一条 Trace 的方式,以及与原生 Trace 并列的 Zipkin 标签页。"
+tags:
+  - Tracing
+  - Cloud Native
+---
+
+*本文翻译自英文原文:[Meet Horizon UI · 6/17: The Trace 
Explorer](/blog/2026-06-22-horizon-ui-trace-explorer/),发布日期沿用原文日期。*
+
+这是 [Meet Horizon UI](/zh/2026-06-21-skywalking-horizon-ui-introduction/) 
系列的第六篇。前几篇都在讲地图:服务之间的[拓扑](/zh/2026-06-21-horizon-ui-topology-and-dependency/)、单个服务内部的
 [deployment](/zh/2026-06-21-horizon-ui-deployment-and-banyandb/),以及整个系统全貌的 [3D 
view](/zh/2026-06-22-horizon-ui-3d-infrastructure-map/)。它们回答“我的系统长什么样”。这一篇转向相反方向:从聚合视角一路下钻到
 *一个请求*,看它的 spans、时序,以及到底是哪一跳变慢了。这就是 **Traces** 标签页。
+
+## 为排查设计,而不是为 tailing 设计
+
+Traces 标签页是一个位于 **Layer 内部** 的分布式 Trace 探索器:选择服务,设置条件,然后阅读单条 Trace 的 span 
时间线。它有意和控制台其他部分不一样,因为 Trace 是排查数据,不是实时 feed。
+
+它 **拥有自己的时间范围和条件**。它不跟随全局顶栏时间选择器,也不会自动刷新。你先把要找的条件摆好,再按 **Run 
query**;按之前不会取任何数据。第一次运行前,列表只显示 *"Pick your conditions, then click Run 
query."*。当你在追二十分钟前的一条坏 Trace 时,最不需要的就是页面每几秒自己往前滑,所以它不会这么做。
+
+## 条件表单,不是查询语言
+
+整个过滤界面都是结构化表单控件:select、数字范围、tag chips。条件会暂存在工具栏里,只在点击 **Run query** 后生效:
+
+- **Instance** 和 **Endpoint**:在服务内部收窄范围,endpoint 下拉框只列出这个服务自己的 endpoints。
+- **Status**:`ALL` / `SUCCESS` / `ERROR`。
+- **Order**:Newest(按开始时间)或 Slowest(按耗时)。
+- **Limit**:拉取多少行,默认 30;BFF 会在服务端限制 page size,避免客户端向 OAP 请求过量数据。
+- **Time range**:滚动预设(最近 15 分钟到 24 小时)或自定义绝对窗口,按 **秒级精度** 计算,所以刚结束的 Trace 
不会因为分钟取整而掉出窗口。
+- **Trace ID**:粘贴一个 id 直接查。
+- **Duration range**:毫秒级 min-max。
+- **Tag**:自由输入 span tags,格式为 `key=value`(比如 `http.status_code=500`),按 Enter 
添加为可删除 chip,多个 tag 按 AND 连接;key 和 value 都从后端获得 typeahead。
+
+它不是查询语言。Horizon 里没有 TraceQL 输入框。上面的结构化条件就是完整界面。(TraceQL 是另一条路径:SkyWalking 
后端可以通过 TraceQL 向 Grafana 提供 
Trace,这件事在[另一篇文章](/zh/2026-04-08-traceql/)里讲。Horizon 的探索器是表单,不是 DSL。)
+
+## 可以框选的分布图
+
+结果返回后,工具栏下会出现一张 **Distribution** 图:每个点代表一条 Trace,X 轴是开始时间,高度是 duration,越慢的 
Trace 越高。点按 **status** 着色:错误为红色,成功为强调色。所以左上角、右上角那类高处红点,就是你要找的“又慢又失败”的区域。
+
+这张图本身也是过滤器。点击一个点可以选中它,或者 **拖一个矩形框选一片点**,结果列表会收窄到这批选择;header 切换成 *"N picked"* 
计数,并提供 Reset。这是基于已加载结果的客户端过滤,不会发起新查询。直接框住慢且失败的角落,只读那几行,是从“200 条 Trace”缩到“这 6 
条值得打开”的最快路径。
+
+![图 1:Traces 探索器。分阶段条件工具栏、Distribution 图(每点一条 Trace,高度表示 duration,红色表示 
error)和被框选的区域(8 
picked),下方是结果列表。](/screenshots/horizon-0.7.0/p06-traces-01-explorer.webp)
+图 1:先摆条件、执行查询,再在分布图上框选一片区域,把列表缩到真正值得打开的 Trace。</br>
+
+每条结果行会显示 Trace 的 root endpoint、OK/ERR 标记、duration,以及按当前结果中最慢 Trace 
归一化后的长度条。每一行 *代表什么* 取决于存储后端,Horizon 会自动检测:横幅会显示 *"Full traces are returned 
inline"*,表示后端返回的是带 spans 的完整 Trace,点击即可打开;或者显示 *"Each row is a trace segment — 
click one to fetch its full trace."*。你不需要配置这个,横幅只是告诉你当前看到的是什么。
+
+## 三种方式读同一条 Trace
+
+点击一行后,Trace 会打开,并在同一组 spans 上提供三种视图切换:**Default**、**Tree** 和 **Statistics**。
+
+- **Default** 是 span 瀑布图:每个 span 一行缩进展示,带一个按服务着色的条形,条形在共享时间线上按 span 
起始偏移和耗时定位;同时显示 span-kind glyph、组件图标(和拓扑地图共用同一套图标)、endpoint 或 peer 名称,以及 span 
自身耗时。错误 span 会高亮,带 attached events 的 span 会有标记。关键点在于,瀑布图会用 parent references 
**把跨 segment 的 spans 缝起来**,所以一个跨过五个服务的请求会渲染成一条连贯时间线,而不是五段互不相干的内容。
+- **Tree** 把同一批 spans 画成可缩放、可平移的节点图:root 在左,callees 
向右流动。适合你更关心调用树形状,而不是精确时序的时候。
+- **Statistics** 按 **name** 聚合 spans:一张可排序表,展示每个 operation 的 count、total / 
average / maximum duration。所以“这条 Trace 里到底哪个 span 名称累计耗时最多”只需要点一次排序。
+
+![图 2:Default 视图。span 瀑布图,每个 span 是共享时间线上的服务色条,带 kind glyph、组件图标和 duration;错误 
span 高亮,跨服务 spans 
被缝成一条时间线。](/screenshots/horizon-0.7.0/p06-traces-02-waterfall.webp)
+图 2:瀑布图(Default),一条请求触达的所有服务被画成同一条连贯时间线。</br>
+
+![图 3:Tree 视图。同一条 Trace 被画成可缩放的节点图,root 在左,callees 
向右流动。](/screenshots/horizon-0.7.0/p06-traces-03-tree.webp)
+图 3:Tree 视图,把同一批 spans 画成调用树形状,可以缩放和平移。</br>
+
+## 进入一个 span 内部
+
+点击任意 span,旁边会打开详情面板。**Meta** 展示核心信息:service、instance、endpoint、kind(entry / 
exit / local / producer / consumer)、component、peer、layer、start time、duration 和 
error 标记。适用时,下面还会出现:
+
+- **Cross-trace refs**:当一个 span 的 parent 位于 *另一条* Trace(异步跳转、稍后消费的消息)中时,这里会列出 
parent 的 trace id、segment 和 span;trace id 是一个 **链接**,点击可以直接切换到那条 Trace。
+- **Tags**、**Logs**(每个 span 的带时间戳日志项)和 **Attached Events**(带 start/end time 和 
summary key/values 的命名事件)。
+
+详情 header 会显示 Trace 开始时间、总耗时、span 数量,以及触达了多少个不同服务;从这里可以复制 trace id 
或可分享链接。打开一个带 `?traceId=...` 的分享 URL,会直接落到该 Trace 的 overlay 上。这让 Trace 成为可以粘贴到 
incident channel 里、让同事打开同一视图的对象。
+
+## Native 和 Zipkin 并排
+
+并不是每个 Layer 的 Trace 都来自 SkyWalking 自己的 agent。Layer 模板带一个 `traces.source` 
设置,可以是 `native`、`zipkin` 或 `both`,Horizon 据此路由。由 agent 接入的 Layer(比如 General 
Service)使用上面讲的 **native** 探索器;service-mesh 和 Kubernetes 风格的 Layer 中,spans 以 
Zipkin/OpenTelemetry 数据进入,则使用 **Zipkin** 探索器;设置为 `both` 的 Layer 会简单地得到 
**两个侧边栏标签页**,因为 native 和 Zipkin spans 的形状和条件确实不同。
+
+Zipkin 标签页通过 **OAP 的 Zipkin query API** 查询上游 Zipkin store。这是 OAP 向任何 Zipkin 
client 暴露的兼容接口,不是 GraphQL,也不是 TraceQL。Zipkin 按自己的服务宇宙组织数据(每个 span 上的 
`serviceName`,可能和 SkyWalking 的服务列表不同),所以这个标签页有自己的服务控件,不绑定页面上的 service 
picker;它也带 Zipkin 原生条件,比如 *Remote service*、*Span name* 和 *Annotations* 
查询(`error` 或 `key=value`)。两个存储路径独立失败:Zipkin 不可达时,native traces 不受影响,反之亦然。
+
+![图 4:mesh Layer 上的 Zipkin trace 标签页。它有自己的 service / remote-service / 
span-name / annotations 条件,并通过 OAP 查询上游 Zipkin store,打开了一条 Zipkin trace 
waterfall。](/screenshots/horizon-0.7.0/p06-traces-04-zipkin.webp)
+图 4:设置为 Zipkin 的 Layer 会得到自己的标签页和自己的服务宇宙,并通过 OAP 查询上游 Zipkin store。</br>
+
+打开一个 Zipkin span 后,详情会保留 Zipkin 的形状:`CLIENT` / `SERVER` kind、本地和远端 
endpoint,以及原始 Zipkin/OpenTelemetry tags(`istio.*`、`http.status_code`、sidecar 
`node_id`)都会按 Zipkin 记录的方式展示,不翻译成 SkyWalking span 模型。
+
+![图 5:Zipkin span 详情面板。Meta(Kind CLIENT、peer、duration)和原始 Zipkin/OTel tags,包括 
Istio sidecar 
相关字段,都保留原生形状。](/screenshots/horizon-0.7.0/p06-traces-04-zipkin-span.webp)
+图 5:Zipkin span 保留自己的字段:kind、endpoints,以及原始 `istio.*` / HTTP tags。</br>
+
+## 从慢记录跳到背后的 Trace
+
+还有一种进入 Trace 的方式,不需要经过探索器。整个应用只挂载一个 Trace overlay,多个入口都能按 **trace id** 
打开它:`?traceId=` 链接、cross-trace 
ref、日志行,以及[第二篇](/zh/2026-06-21-horizon-ui-dashboards-and-mqe/)里提到的 record 
组件慢语句行上的 **jump-to-trace** 图标。因为它按 id 解析,而不是按 Layer 解析,所以即使 Trace 属于你当前看到的 
*另一个* Layer 也能工作:Virtual Database、Cache 或 MQ 服务没有自己的 traces 标签页,但它的慢语句仍然能带你到发起方 
Trace。跳转如果带 timestamp(日志行知道自己写入时间),查找会围绕那个时间放宽窗口,所以即便 Trace 已经进入冷存储,也不会悄悄找不到。
+
+## 下一步去哪里
+
+Traces 标签页把一个请求完整展开;前面几篇的仪表盘和地图,是你最初发现异常的地方。字段参考,包括每个条件、native-vs-Zipkin 拆分和 
span 详情面板,可以看 [Traces 
文档](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/operate/traces/)。
+
+下一篇:**Log Explorer**。同样的排查思路,应用到日志流而不是 spans。
diff --git 
a/content/zh/2026-06-23-horizon-ui-browser-errors-and-source-maps/index.md 
b/content/zh/2026-06-23-horizon-ui-browser-errors-and-source-maps/index.md
new file mode 100644
index 00000000000..f9f38a2f0f6
--- /dev/null
+++ b/content/zh/2026-06-23-horizon-ui-browser-errors-and-source-maps/index.md
@@ -0,0 +1,69 @@
+---
+title: "认识 Horizon UI · 8/17:浏览器错误与 Source Maps"
+date: 2026-06-23
+author: 吴晟
+description: "Horizon UI 系列第八篇:browser agent 上报的 JavaScript 
错误流,以及让这些错误真正可用的能力:逐帧把生产环境混淆栈还原到原始文件、行、列、符号和源码片段。"
+tags:
+  - Logging
+  - Engineering
+---
+
+*本文翻译自英文原文:[Meet Horizon UI · 8/17: Browser Errors & Source 
Maps](/blog/2026-06-23-horizon-ui-browser-errors-and-source-maps/),发布日期沿用原文日期。*
+
+这是 [Meet Horizon UI](/zh/2026-06-21-skywalking-horizon-ui-introduction/) 
系列的第八篇。[第七篇](/zh/2026-06-23-horizon-ui-log-explorer/)讲的是服务日志;这一篇讲 *用户* 
遇到的错误,也就是 browser agent 上报的 JavaScript 异常,以及把这些错误从噪声变成可处理问题的关键能力。
+
+生产环境 JavaScript stack 基本不可读。代码经过压缩和打包后发布,浏览器只会报告错误出现在 
`app.min.js:1:98412`,也就是一段机器生成代码里的位置,几乎不给你任何线索。这个功能的目的,是把这条 stack 沿着正确的 
**source map** 走回你的源码:原始文件、行、列、符号名,以及出错位置附近的代码片段,逐帧还原。
+
+## 浏览器错误流
+
+在 **BROWSER** Layer 上,**Browser Logs** 标签页(屏幕上的标签名,它专门表示 JavaScript 错误流)会列出 
browser agent 上报的内容。BROWSER Layer 会把槽位重命名成自己的语义:services 变成 
**Applications**,instances 变成 **Versions**,endpoints 变成 **Pages**。这个 feed 
的阅读方式类似 [Log Explorer](/zh/2026-06-23-horizon-ui-log-explorer/):可点击的 
**category** legend 带计数,density histogram 位于日志流之上。每一行都有时间、**category**、page、app 
version 和错误消息;如果带有 minified `line:col`,也会显示成 chip。
+
+排查方式和 trace/log 标签页一致:它拥有自己的 **Time range**(全局顶栏暂停),你可以按 **Version**、**Page** 
或 **Category** 收窄,然后点击 **Run 
query**。没有后台轮询把视图从你脚下挪走,也没有要学习的查询语言,只有结构化控件。点击一行后,它会在日志流里原地展开。
+
+![图 1:BROWSER Layer 上的 Browser Logs 标签页。category legend 和 density histogram 位于 
JS 错误流上方,每行显示 category、page、app version 和 minified 
line:col。](/screenshots/horizon-0.7.0/p08-browser-01-stream.webp)
+图 1:browser agent 的错误流:按 category 组织、带图表,并限定到某个 app 版本和页面。</br>
+
+那个 minified `line:col` 就是问题的缩影。它是真实位置,但位置在 *构建后* 的 bundle 
里,不在你的源码里。后面的能力就是为了解决它。
+
+## 从 minified stack 回到源码
+
+展开一个错误后,面板分成两侧:左边是浏览器原样报告的 **raw stack**,也就是那段乱码;右边是解析结果区域。选择一个 **source 
map**,点击 **Resolve**,Horizon 会解析 stack,并通过这份 map 映射 **每一帧**:
+
+- 每帧原始 **`file:line:column`**;
+- 原始 **symbol name**(如果 map 携带了);
+- 出错行附近几行 **原始源码**,命中行会高亮(如果 map 内嵌 `sourcesContent`)。
+
+map 覆盖不到的 frame 会诚实显示为 `unmapped`。所以一条顶层 frame 为 `app.min.js:1:45` 的 
stack,可以还原成 `checkout.ts:2:20` 上的 `computeCartTotal`,并把 `checkout.ts` 
附近几行显示出来。真正抛错的 `cart.items.reduce(...)` 就在面板里,不只还原第一帧,而是从上到下还原整条 stack。
+
+这里有一些细节决定结果可信还是悄悄错掉:浏览器 stack 的列号从 1 开始计数,source map 从 0 
开始计数,所以解析器每次查找前都会做偏移;这条路径用真实 bundler 输出测试,而不是手写 fixture。
+
+![图 2:展开后的错误。左侧是原始 minified stack,右侧是解析后的 stack,每一帧显示原始 
file:line:column、symbol 
和高亮源码片段。](/screenshots/horizon-0.7.0/p08-browser-02-resolve.webp)
+图 2:核心能力:把 minified stack 指向正确 map,然后逐帧读回你自己的源码。</br>
+
+## 哪些错误带可解析 stack
+
+不是每类错误都有东西可翻译。**`JS`**、**`PROMISE`** 和 **`VUE`** 是真实 JavaScript 错误,它们的 stack 
指向 bundle,可以解析。**`AJAX`** 和 **`RESOURCE`** 是网络和加载失败;它们的“stack”是 HTTP status 或失败 
URL,不是代码,所以 source map 没有东西可映射(Horizon 不会阻止它们,只是那里没有 JavaScript 可以走回去)。没有 
source map 的代码、`eval` 或 inline scripts 里的 frame,也会保持 `unmapped`。(`JS` 
也是唯一由浏览器上报顶层 `line:col` 的 category;其他 category 的位置在 stack 字符串内部,由解析器提取。)
+
+## 怎么提供 map:上传,或者挂载
+
+解析前必须让 map 可用。Horizon 提供两种方式,耐久性刻意不同:
+
+- **Upload** 一个 `.map`,直接从标签页上传。它只保存在服务端 **内存** 
里,没有后端存储,并且临时性是设计目标:它占用内存预算,在压力下按 least-recently-used 
淘汰,**服务重启后丢失**;多实例部署时,它也只存在于接收上传的那一个实例。这个路径适合临时排查:拖一个 map 进来,解析,处理完离开。
+- **Mount** `.map` 文件到服务端 **source-map 目录**(容器镜像中是 `/app/sourcemaps`,可通过 
`HORIZON_SOURCEMAPS_DIR` 指定)。这些文件在启动时按 Source Map v3 
校验,按需从磁盘读取(所以不占内存预算),重启后仍然存在,会自动 reload,并且 **不能从 UI 删除**。这是生产路径:把构建产物里的 maps 
放进镜像或挂载目录,它们就一直可用。
+
+管理器会显示每个 map 的来源(*uploaded · temporary* 还是 *mounted · 
durable*),以及当前内存预算使用量。预算配置,包括单文件上限和常驻上传总量上限,默认 64 MiB 和 512 MiB,位于 
`horizon.yaml` 的 `sourceMaps` 块。
+
+![图 3:source-map 管理器。Upload .map 控件、内存预算条(这里是 0 B / 512 MB,max 64 MB/file)和已加载 
maps;图中 map 是 Mounted 且 durable,所以不能在这里删除,uploaded maps 会显示为 
temporary。](/screenshots/horizon-0.7.0/p08-browser-03-sourcemap-manager.webp)
+图 3:两种提供 map 的方式:upload 用于快速排查,mount 用于稳定生产集。</br>
+
+## 你需要主动选择 map
+
+Horizon 刻意 **不猜测**。browser agent 会上报 app **version**,但不会上报精确 build 
fingerprint,所以没有安全方法自动把一个错误匹配到某份 map。用错 build 的 map 
会给出非常自信、但完全错误的行号,比没有答案更糟。所以这里由你选择:挑选和该错误 build 对应的 map,并按版本给 map 
清晰命名。(还有一个必须直说的注意点:source map 的 `sourcesContent` 会包含你的原始源码,所以无论上传还是挂载,都要把 map 
当成敏感内容,只放在可信服务器上。)
+
+这种“有意手动”的选择,也划清了 **权限** 边界。查看错误、列出 maps、**解析** stack 都是读操作,由 
`browser-errors:read` 控制;**上传或删除** map 是写操作,由 `source-map:write` 控制。所以只读 viewer 
可以整天反混淆 stack,但没有权限改变已加载的 map 集合。读就是读,修改 map store 才是写。
+
+## 下一步去哪里
+
+字段参考,包括 categories、两种提供路径、预算,以及如何按 build 匹配 map,可以看 [Browser Logs & Source 
Maps 
文档](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/operate/browser-source-maps/)。
+
+下一篇英文系列将进入 **Profiling**:五种 profiler(trace、async、eBPF、Go 
pprof、network)通过同一个火焰图呈现。
diff --git a/content/zh/2026-06-23-horizon-ui-log-explorer/index.md 
b/content/zh/2026-06-23-horizon-ui-log-explorer/index.md
new file mode 100644
index 00000000000..4db118e40a4
--- /dev/null
+++ b/content/zh/2026-06-23-horizon-ui-log-explorer/index.md
@@ -0,0 +1,67 @@
+---
+title: "认识 Horizon UI · 7/17:Log Explorer"
+date: 2026-06-23
+author: 吴晟
+description: "Horizon UI 系列第七篇:两种日志界面,一种是已采集、已索引、可与 Trace 关联的存储日志流,带 level 
直方图;另一种是按需实时 tail Kubernetes pod 的容器日志。"
+tags:
+  - Logging
+  - Cloud Native
+---
+
+*本文翻译自英文原文:[Meet Horizon UI · 7/17: The Log 
Explorer](/blog/2026-06-23-horizon-ui-log-explorer/),发布日期沿用原文日期。*
+
+这是 [Meet Horizon UI](/zh/2026-06-21-skywalking-horizon-ui-introduction/) 
系列的第七篇。[第六篇](/zh/2026-06-22-horizon-ui-trace-explorer/)讲的是一个请求的 
spans;这一篇讲它周围的日志行。Horizon 通过 **两个不同标签页** 
展示日志,因为它们回答的是两个不同问题:*“这个服务过去半小时打了什么日志?”* 以及 *“这个 pod 现在正在向 stdout 打什么?”*
+
+- **Logs** 标签页查询 SkyWalking 已经 **采集并存储** 的日志:已索引、可过滤、可与 Trace 关联。
+- **Pod Logs** 标签页按需 **实时 tail** Kubernetes pod 的容器日志。这些不是存储日志:OAP 直接从 
**Kubernetes API server** 读取它们(也就是 `kubectl logs` 那条路径),Horizon 
展示窗口,然后丢弃。不会持久化,也不会进入 SkyWalking 日志存储。
+
+某个 Layer 展示哪些标签页由模板决定:启用日志的 Layer(General、Mesh、Nginx、Envoy AI Gateway、mobile 和 
mini-program Layer)会显示 **Logs** 标签页;只有感知 Kubernetes 的 Layer(Kubernetes 
Service、Mesh、Mesh data plane)会显示 **Pod Logs** 标签页。Browser JavaScript 
错误又是另一类数据:它不是服务日志,而是 browser agent 上报的客户端错误事件,有自己的分类,也有自己的 **source-map 
de-obfuscation**,可以把混淆后的 `app.min.js:1:...` frame 还原到原始 `file:line`。这是 Browser 
Layer 上的独立标签页,会在这个系列的另一篇文章里讲。
+
+## 存储日志流
+
+打开一个有 **Logs** 标签页的 Layer,先在 header 里选择服务,最新日志流会按 newest-first 加载。和 Trace 
探索器一样,这个标签页 **拥有自己的时间范围**。当你在这里排查时,全局顶栏时间选择器会暂停,自动刷新不会把窗口从你脚下移走。可以选择滚动预设(最近 15 
分钟到 24 小时,默认 30 分钟),也可以选择自定义绝对窗口;查询按 **秒级精度** 执行,所以最新日志不会被分钟取整吞掉。
+
+条件栏用来收窄日志流,每个过滤条件都是可选的,多个条件按 AND 连接:
+
+- **Instance**:限制到某个服务实例。在 sidecar Layer 上标签显示为 **Sidecar**。
+- **Endpoint**:输入搜索服务 endpoints,点击固定,按 **×** 清除。
+- **Trace ID**:只显示和某条 Trace 关联的日志行。从 Trace 跳转过来时,也会预填这个字段并直接限定日志流。
+- **Tags**:单个 `key=value` 字段,带 autocomplete;输入 key 可看建议,输入 `=` 后切换到已知 value,按 
Enter 提交。提交后的 tags 以可删除 chip 形式保留。
+- **Level**:日志流上方的 **Levels** 条也可以当过滤器用。点击 `error`、`warn`、`info` 或 `debug` 
只保留该级别,再点一次清除。
+
+这里没有日志查询语言,不需要学习 LogQL。上面的条件就是完整界面,并且 **编辑时会立即刷新日志流**;**Run query** 
只是显式告诉系统“我改完了,现在刷新”,同时回到第一页。
+
+## 怎么读日志流
+
+日志视图的目标不是 *列出* 行,而是帮你找到形状,所以日志流上方有两个定位信息。
+
+**Density histogram** 按时间画出日志数量,每个柱按 legend 颜色 **堆叠 level**;hover 柱子可以看到该 
bucket 的时间范围和每个 level 的计数。它基于当前页面上可见数据绘制,所以展示的是你正在看的内容形状。**Levels** 条则保留每个 
level 在窗口内的运行计数。这个计数跨整个查询窗口采样,而不只是当前可见页,所以 error/warn/info 比例反映的是整个窗口。
+
+每行日志会显示 timestamp、level(行颜色跟随 level)、service、存在 Trace 关联时的 **↗ trace** 
链接、**`JSON` / `YAML` / `TEXT` 格式 chip**,以及内容的一行预览。Horizon 按 payload 实际内容决定这个 
chip:OAP 会标注 body 是 JSON 还是 plain text,在此基础上 Horizon 还会嗅探 JSON 和 YAML 
结构,所以即使一行没有被标注但内容是结构化的,也会得到正确处理。JSON 在预览里压平成一行,YAML 保留 key,plain text 会折叠空白。
+
+![图 1:存储 Logs 流。条件栏、按 level 堆叠的 density histogram 和 Levels 条在上方,下面是日志行,每行带 
level 颜色、service、格式 chip 和 ↗ trace 
链接。](/screenshots/horizon-0.7.0/p07-logs-01-stream.webp)
+图 1:某个服务的存储日志流:窗口上的 level histogram 和 level 计数,下面是每行日志,带 JSON / YAML / TEXT 
标记并可跳到 Trace。</br>
+
+## 进入单行日志
+
+点击一行后,完整 payload 会在 popout 里打开:完整内容会按 **格式感知 pretty-printing** 展示,JSON 和 YAML 
正常排版,plain text 则获得完整画布,而不是被挤在一条窄条里。面板还提供 **Copy** 按钮、service / instance / 
endpoint / trace 上下文,以及该行所有 tag 的表格。日志行与 Trace 关联时,**↗ trace** 按钮会在 overlay 
中打开相关 [Trace 瀑布图](/zh/2026-06-22-horizon-ui-trace-explorer/),不离开日志流;它还会把这行日志的 
timestamp 传过去,所以 Trace 即使已经进入更冷的存储 tier,也仍然能找到。按 Escape 或点击 backdrop 即可关闭。
+
+![图 2:日志行 payload popout。完整内容按格式 pretty-print(这里是 JSON access log),带 Copy 
按钮、service 和 instance 上下文,以及该行 tag 表(这里是 
`status.code`)。](/screenshots/horizon-0.7.0/p07-logs-02-payload.webp)
+图 2:完整查看一行日志:payload 按格式排版,旁边展示上下文和所有 tags。</br>
+
+## Pod Logs:tail 当前正在输出的内容
+
+**Pod Logs** 标签页回答另一个问题,它的数据源也完全不同:不是 SkyWalking 存储的日志,而是通过 OAP 从 **Kubernetes 
API server** 实时读取 pod 的容器输出,也就是 `kubectl logs -f` 
读取的同一类内容。这里没有可翻页的存储历史;每次刷新拉取尾部窗口,展示出来,然后丢弃。
+
+启动 tail 只需要几个选择:选一个 **Pod**(固定的服务实例)、一个 **Container**(Horizon 会列出 pod 的 
containers 并默认选第一个)、一个回看 **Window**(last 30s、1m、5m、15m 或 30m,决定每次轮询向前取多远),以及轮询 
**Interval**(2s、5s、10s 或 30s,决定多久重新取一次)。按 **Start** 后,窗口会流入只读 
viewer,保持最新行可见,并持续轮询直到你按 **Pause**。header 条显示 container、行数、live 
indicator,以及上次更新距今多久。两行 **Include** / **Exclude** filter 用来收窄可见内容;每个 chip 都是一个 
**整行正则表达式**(`.*error.*`),由 OAP 执行,所以它匹配整行而不是子串,并且可以叠加。
+
+使用前需要知道一点:按需读取 pod logs 在 OAP 上 **默认关闭**,因为容器输出可能包含 secret。功能关闭时,或者你选择的 pod 
已经滚动或缩容消失时,OAP 会返回一个 *原因*,Horizon 会把它显示成横幅,而不是给你一个空面板。这样你能区分“需要打开这个功能”和“那个 pod 
已经不存在”。
+
+![图 3:Pod Logs 标签页。pod 和 container 选择器、回看窗口和轮询间隔、live-indicator 
header、Include/Exclude 正则 chips,以及流式展示容器最近输出的只读 tail 
pane。](/screenshots/horizon-0.7.0/p07-logs-03-pod-logs.webp)
+图 3:一个 pod 容器的实时 tail:窗口化、按间隔轮询、可用正则过滤、永不持久化。</br>
+
+## 下一步去哪里
+
+两个标签页,包括存储查询、tag 和 container autocomplete、live tail,都由同一个 `logs:read` 
权限控制。所以授予“可以读日志”就是一个开关。字段参考,包括每个条件、histogram、Pod Logs 的窗口和过滤器,可以看 [Logs 
文档](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/operate/logs/)。
+
+下一篇:**Browser & RUM monitoring**。browser agent 自己的错误流,以及如何用 source map 反混淆 
minified stack。


Reply via email to