Skip to content

Repository files navigation

Apache SkyWalking Horizon UI

SkyWalking logo

License

Horizon UI is the next-generation web UI for Apache SkyWalking — a config-driven, dark-dense, multi-layer observability front end built for feature parity with the legacy skywalking-booster-ui on the same OAP GraphQL query-protocol and MQE. It renders services, instances, endpoints, topology, traces, logs, alarms, and profiling across every layer SkyWalking observes — language agents, service mesh, middleware, and Kubernetes infrastructure — ships an in-browser admin suite for runtime rules, RBAC, template management, and cluster status, and includes an optional bring-your-own-LLM AI assistant that answers questions from live OAP data using the same dashboard widgets. Dashboards are JSON templates: live OAP 11 deployments publish them to OAP, while readonly deployments render the bundled copies — new screens are configuration, not code.

Features

AI assistant

  • Chat with your live system — ask in plain language ("what's unhealthy right now?", "investigate latency for a service") and the assistant reads live OAP data through the same query path the dashboards use, streaming back a narrative with inline charts, top-N lists, and tables drawn by the real widget components; open it as a side drawer, a full page (/ai), or a new tab.
  • Real product views embedded in the chat — topology, traces (native and Zipkin, with the span waterfall), logs, browser errors, Kubernetes pod logs, deployment graphs, API dependencies, and instance maps mount as the actual read-only views, scoped to the service in question.
  • Captured-snapshot replay — every figure, map, trace/log list, and profiling result is frozen at read time and stamped "captured <time>" with a replay badge, so reopening a conversation replays the exact evidence offline instead of silently re-querying.
  • Guided root-cause analysis — built-in investigation playbooks (latency, error-rate/SLA, saturation, middleware, Kubernetes-workload, service-mesh) that walk the dependency topology and follow the cross-layer hierarchy down into the backing infrastructure.
  • Profiling only on your approval — when metrics and traces can't pinpoint a cause, the assistant proposes the flavor that fits the target (trace / async-profiler / pprof / eBPF / network) as a decision card; nothing runs until you approve it, and the analysis renders inline as the real flame graph, trace waterfall, or process graph.
  • Bring your own LLM — off by default, enabled via the ai: config block against any OpenAI-compatible endpoint or Amazon Bedrock, with the API key env-only and redacted from logs; access is RBAC-gated (ai:read), every data tool enforces the same read verbs the signed-in user already holds, and the assistant never changes configuration, rules, or dashboards.

MCP — bring your own agent

  • Horizon speaks the Model Context Protocol at POST /api/mcp, so Claude Code, Codex, Claude Desktop or any MCP client gets the same 28 investigation tools the assistant uses, plus the root-cause playbooks as prompts. On by default and needing no LLM provider, because the model stays on the caller's side.
  • The same permissions, never more — the endpoint takes the login every other route takes (an API token, or a browser session), is gated by mcp:read, and every tool re-checks the read verb its own screen needs, so an agent sees exactly what the operator it authenticated as sees.
  • A browser login instead of a pasted secret — an optional OAuth 2.1 authorization server sends the operator through Horizon's own login page (LDAP and all), with a consent screen naming what the grant would carry; the token holds the intersection of the consented scope and the user's live roles, so it can only ever narrow.
  • Answers a model can read, and a client that can draw gets the real widgets — figures come back as a log-scaled sparkline with bucketed min/avg/max and the extremes, trace/log lists come back as rows, and a host with inline rendering mounts Horizon's own chart, topology and trace components from a self-contained bundle that makes no network requests at all.

Layers & dashboards

  • Bundled instrumentation layers across four tiers — Apps (GENERAL, BROWSER, mobile, VIRTUAL_DATABASE/CACHE/MQ/GENAI), Service Mesh (MESH, MESH_DP, MESH_CP, CILIUM_SERVICE), Middleware (databases, queues, gateways, Flink, Airflow), and Infrastructure (K8S, OS_LINUX/WINDOWS, AWS) — plus a self-observability group (SO11Y_OAP, SO11Y_SATELLITE, BANYANDB).
  • Config-driven layer dashboards — multi-scope (Service / Instance / Endpoint) JSON templates edited in the UI admin and, in OAP 11 live mode, published to OAP with no code changes; per-layer sync badges show synced / diverged / local state.
  • Rich widget vocabulary — scalar KPI cards, time-series line charts with dual-axis, top-N rankings, sampled record lists, label-dimensioned tables, KPI composites, embedded topology, and alarm tiles.
  • Server-side widget visibility gates (visibleWhen) — render a widget only when an MQE metric has a value or an entity attribute matches (e.g. language = JAVA, container_name = lifecycle).
  • Cross-layer Overview dashboards — war-room views (Services Dashboard, Mesh Dashboard) built from KPI tiles, alarms, topology, and metrics on a 12-column drag-and-resize canvas; inactive layers auto-hide.
  • Layer customization — per-layer aliases (e.g. Pods/Endpoints on K8S_SERVICE), instance badges (agent language, BanyanDB container name), naming rules that group services (namespace.service for K8S/Istio), and split-by-Service.group to fan one layer into per-group sidebar entries.
  • Value formatting — enum maps (translatable value→label), duration as human time-ago, and compact SI suffixes (45.1k, 1.34M).
  • Template store reliability — in live mode the runtime renders only the OAP-published version; an unreachable store shows a visible banner, never a silent fallback to bundled defaults. Readonly mode explicitly renders the bundled templates instead.

Maps & topology

  • Service topology map — interactive directed call graph with health-ring nodes, component-technology icons, SLA-colored RPM edges, pan/zoom/drag, and conjectured-peer filtering.
  • Instance-level drill-down — client vs. server instances in grouped columns with relationship-aware pair picking and per-instance call metrics.
  • Deployment topology — a single service's instances clustered into pods with configurable node/edge roles and role-to-role edge metrics (e.g. liaison→data write/query, lifecycle→data migration), plus a Flows sub-tab.
  • API dependency graph — endpoint caller→callee chains with one-click expand, drag-to-rearrange, and drill-out links.
  • Cross-layer service navigation — jump a logical service between layers (Agent ↔ Mesh ↔ MeshDP ↔ K8S) via a service-map chip overlay.

Traces, logs & alarms

  • Distributed traces — native SkyWalking traces (queryTraces on BanyanDB with inline spans, or queryBasicTraces on any backend), plus Zipkin traces in a separate tab when a layer enables both, with state/order/duration/tag filters, a duration distribution chart, and second-precision time windows.
  • Trace waterfall — indented span timeline with service colors, span-kind glyphs, component icons, cross-segment references, and per-span duration/error state.
  • Application & service logs — keyword + tag filtering, a level-stacked density histogram, faceted sidebar, dense expandable stream, content-type-aware rendering (text / JSON / custom MIME), and a trace link per row.
  • Browser error logs — JavaScript errors on the BROWSER layer with raw minified stacks de-obfuscated against uploaded or mounted .map files, resolved to original file/line/column/symbol with a source snippet.
  • Pod logs (Kubernetes) — on-demand live-tail of container logs fetched through OAP from the K8s API, with lookback/poll controls, keyword and exclude filters, and a read-only Monaco pane.
  • Alarms (read-only) — active and historical alarms across layers with timeline lanes and incident grouping; recovery is backend-automatic — no acknowledge/close/silence.

Profiling

  • Trace-based profiling — CPU/memory call stacks from sampled spans via async-profiler (Java) and pprof (Go), as a stack tree or flame graph.
  • eBPF / kernel profiling — system-level on-CPU and off-CPU sampling with label aggregation.
  • Async / continuous profiling (Java) — live thread profiling with event-type selection (CPU/ALLOC/LOCK/WALL/CTIMER/ITIMER) and multi-instance scoping.
  • pprof profiling (Go) — event selection (CPU/HEAP/BLOCK/GOROUTINE/MUTEX/ALLOCS/THREADCREATE), sampling-rate controls, plus on-demand one-shot dumps.
  • Network profiling — process-level topology and inter-process call metrics from eBPF network / continuous-profiling tasks in a honeycomb layout.

Operate & admin

  • Runtime rule management (OAL / MAL / LAL) — Monaco YAML editor, catalog, and bytecode/AST dump, with a live phase stepper for structural applies (Compiled → Confirming across the cluster → Committing → Done), cluster-propagation warnings, and a force-recover button for degraded applies.
  • Alerting rules — per-entity running-context for alarm rules (FIRING / SILENCED_FIRING / RECOVERY_OBSERVATION) with a snapshot sparkline and per-OAP-node evaluation state.
  • Live Debugger — start/poll/stop debugging sessions for the three runtime-rule languages, with per-node fan-out, sample payloads, diff-default label grouping, and replayable capture history.
  • Metrics Inspect (MQE board) — browse the OAP metric catalog by source (OAL / MAL·OTEL / MAL·Telegraf / MAL·Meter / LAL→MAL), pick a scope and entity, and fire MQE expressions live against the running system.
  • Cluster status — GraphQL-port health (version, server clock, timezone, health score) and admin-host module readiness, surfaced as a topbar health chip.
  • Data retention (TTL) — backend-aware per-data-class retention (BanyanDB hot+warm/cold stages or single-stage for other backends), read-only.
  • OAP configuration dump, RBAC matrix (four built-in roles over a verb-namespaced permission set), Users admin (local + LDAP), and Auth status with an on-demand LDAP resolve probe.
  • Template management — a bundled → local-draft → remote-OAP model with source pill, sync badge, Save (local only), and Check diff & push (Monaco side-by-side) across layer dashboards, overviews, 3D map, alerts, themes, and time defaults.
  • Export / import — download any dashboard, overview, 3D-map, or per-locale translation config as JSON for backup or sharing; import loads a local draft and never writes OAP directly.

3D infrastructure map & multi-entity compare

  • 3D infrastructure map — a WebGL (Three.js + TresJS) bird's-eye view with services as cubes on stacked tier-planes (Apps / Service Mesh / Middleware / Infra), SLA-colored health rings, animated intra-zone call arcs, orbit/keyboard controls, beacon mode (dim healthy cubes so only alarming ones glow), and a fully configurable tier/layer/color/traffic-MQE/logic-group editor published to OAP.
  • Multi-entity compare — pin up to 6 services/instances/endpoints (cross-service) and compare inline without changing the primary selection: line charts overlay hued series, cards show a row per entity, top-N/record widgets gain per-entity tabs, and tables gain an Entity column.

Internationalization & design

  • Eight first-class locales — English (source), zh-CN, ja, ko, es, pt, de, fr; UI chrome resolves client-side via vue-i18n, and bundled dashboard templates carry per-locale overlay catalogs merged BFF-side before they reach the browser.
  • Tech terms and OAP-supplied data stay verbatim — SkyWalking, Kubernetes, OAP, MQE, eBPF, scope enums, layer keys, and metric ids are never translated; service names, trace spans, log messages, and alarm rule names render as-is in every locale.
  • Five bundled themes — Horizon, Meridian, Obsidian, and Aurora (dark) plus a light Daybreak — built entirely on CSS custom properties (no Tailwind, no CSS-in-JS); dark-dense by default, with synced crosshairs across all time-series on a dashboard.
  • MQE as a first-class editable language — syntax-highlighted, schema-aware, and debuggable in dashboards and the Live Debugger.

Architecture

Horizon UI is a pnpm-workspaces monorepo:

  • apps/ui — the Vue 3 + TypeScript (strict) single-page app, built with Vite. State via Pinia, data via @tanstack/vue-query, charts via Apache ECharts (wrapped — never instantiated directly in a view), topology and flame graphs via D3, 3D via Three.js + TresJS, code editing via Monaco.
  • apps/bff — a Fastify (Node) backend-for-frontend. It is the only tier that talks to OAP, shaping every reply for the SPA, owning timezone conversion, template sync, and auth/RBAC.
  • packages/api-client, packages/design-tokens — the shared typed client for the BFF, and the canonical design tokens. Bundled dashboard JSON lives with the BFF that serves it.

The BFF speaks three OAP contracts, all owned upstream and treated as fixed:

  • GraphQL query-protocol (POST /graphql) — metrics, topology, traces, logs, alarms, browser errors.
  • Admin REST (OAP admin host, default port 17128) — runtime rules/DSL, cluster status, metrics inspect, live debugging.
  • Zipkin v2 REST — Zipkin-format trace/span fetch.

The flow inside the BFF is one-directional — http → logic → client → OAP. In the default live mode the bundled templates are seeded to OAP on first boot, after which the running UI renders only what OAP serves — the disk bundle is a seed/reset source, never a render-time fallback. In templates.mode: readonly the bundle is the declared source and OAP's template store is never called.

Getting started / Development

Prerequisites: Node (see package.json engines>=24, the line CI and the container image both use) and pnpm via Corepack (the repo pins the version through packageManager).

corepack enable
pnpm install

Run the dev servers — Vite serves the UI on :9091 and proxies /api to the BFF on :8081:

pnpm dev          # run UI + BFF together
pnpm dev:ui       # UI only  (Vite on :9091)
pnpm dev:bff      # BFF only  (:8081, NODE_ENV=development, tsx watch)

Quality gates and build:

pnpm type-check   # TypeScript strict, all packages
pnpm lint
pnpm test:unit    # vitest + jsdom
pnpm build        # build all packages
pnpm package      # produce the distributable dist/ (BFF dist/server.js + static UI)
pnpm start        # run the packaged server (HORIZON_CONFIG=./horizon.yaml)

License headers and dependency licenses are enforced in CI via skywalking-eyes — run pnpm license:check (or pnpm license:fix) before pushing.

Docker

A multi-stage, multi-arch image (linux/amd64, linux/arm64) ships the BFF plus the static UI on node Alpine, runs as a non-root horizon user, exposes port 8081, and mounts /data for state files. The Dockerfile builds dist/ from source inside the image (no host pre-step); images are published to GHCR and Docker Hub per release.

docker build -t horizon-ui:local .
docker run --rm -p 8081:8081 -v "$PWD/horizon.yaml:/app/horizon.yaml:ro" horizon-ui:local

See docs/setup/container-image.md for image tags, env vars, mounting horizon.yaml, and a Kubernetes example.

Configuration

Horizon UI is configured by a single horizon.yaml (hot-reloaded, with ${VAR} environment-variable interpolation) — see horizon.yaml. Key sections:

  • server — host / port.
  • oapqueryUrl, adminUrl, zipkinUrl, timeoutMs, and optional outbound basic-auth.
  • auth — backend local or ldap (with LDAP bind / user-filter / group-mapping and an optional break-glass local admin), plus single sign-on and API tokens.
  • rbac — four built-in roles (viewer / maintainer / operator / admin) over fine-grained, verb-namespaced permissions (e.g. dashboard:write, rule:write:structural, source-map:write).
  • templateslive (default: bundled templates seed through OAP 11's REST API and stay editable) or readonly (render from the local bundle; required for OAP 10 because Horizon does not consume its legacy GraphQL template API).
  • ai — the AI assistant: enabled (off by default), provider (openai-compatible or bedrock), model, base URL, and an env-only API key.
  • performance — how hard the BFF fans metric queries out to OAP (per-route bulk sizes and concurrency) plus protective caps (topology render valve, the largest page a list may display).
  • query — load caps: landingServiceCap (how many top services a layer landing fetches metrics for) and overviewTopN (the Overview KPI rollup window).
  • session, debugLog (the outbound OAP wire log), sourceMaps (browser-error source-map cache), and layers.excluded — the wire-log file defaults under /data/* in the container.

Local user passwords are argon2-hashed; generate a hash with the BFF CLI. Set session.cookieSecure: true when running behind HTTPS.

Documentation

Operator-focused documentation (setup, OAP compatibility, access control, customization, components, and operate) lives in this repo under docs/ and is rendered on the SkyWalking website. Start with the Quick Start, then OAP Connection and Auth/RBAC.

Contributing

Contributions are welcome. Horizon UI is a greenfield rewrite that tracks the OAP GraphQL query-protocol and MQE — backend contracts are fixed and owned by apache/skywalking. Read CLAUDE.md for the project's working principles (correctness first, validate against a live OAP, TypeScript strict, charts wrapped, density beats whitespace), record operator-visible changes in the changelog file for the version in development (docs/changelog/<version>.md, the version package.json carries as -dev), and run the type-check / lint / unit-test / license-header gates before opening a PR.

License

Licensed under the Apache License 2.0 — see LICENSE and NOTICE.

Apache SkyWalking, SkyWalking, and the Apache feather logo are trademarks of The Apache Software Foundation.

About

Apache SkyWalking next-generation UI (Horizon)

Topics

Resources

Code of conduct

Security policy

Stars

15 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages