This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-website.git
The following commit(s) were added to refs/heads/master by this push:
new 04c8ccf9b88 Blog: Meet Horizon UI 7/16 — The Log Explorer (#866)
04c8ccf9b88 is described below
commit 04c8ccf9b886a1de942cdf8df93628ba1e93e875
Author: 吴晟 Wu Sheng <[email protected]>
AuthorDate: Tue Jun 23 09:50:54 2026 +0800
Blog: Meet Horizon UI 7/16 — The Log Explorer (#866)
* Blog: Meet Horizon UI 7/16 — The Log Explorer
Part 7 of the Meet Horizon UI series: two log surfaces — the stored,
indexed, trace-correlated Logs stream (level histogram, Levels filter,
format-aware payload popout, no log query language) and the on-demand Pod Logs
live tail read from the Kubernetes API server (Window/Interval, Include/Exclude
regex, never persisted, disabled-by-default on OAP). 3 WebP figures.
Render-verified against apps/ui/src/layer/{logs,pod-logs} +
docs/operate/logs.md. Tags: Logging, Cloud Native.
* docs(blog): P7 — explain why browser JS errors are a separate stream;
drop placeholder link
---
.../2026-06-23-horizon-ui-log-explorer/index.md | 65 +++++++++++++++++++++
.../horizon-0.7.0/p07-logs-01-stream.webp | Bin 0 -> 181950 bytes
.../horizon-0.7.0/p07-logs-02-payload.webp | Bin 0 -> 138566 bytes
.../horizon-0.7.0/p07-logs-03-pod-logs.webp | Bin 0 -> 291638 bytes
4 files changed, 65 insertions(+)
diff --git a/content/blog/2026-06-23-horizon-ui-log-explorer/index.md
b/content/blog/2026-06-23-horizon-ui-log-explorer/index.md
new file mode 100644
index 00000000000..5e34a385f8c
--- /dev/null
+++ b/content/blog/2026-06-23-horizon-ui-log-explorer/index.md
@@ -0,0 +1,65 @@
+---
+title: "Meet Horizon UI · 7/16: The Log Explorer"
+date: 2026-06-23
+author: Sheng Wu
+description: "Part 7 of the Meet Horizon UI series: two log surfaces — a
stored, indexed, trace-correlated log stream with a level histogram, and an
on-demand live tail of a Kubernetes pod's container logs."
+tags:
+ - Logging
+ - Cloud Native
+---
+
+This is the seventh post in the [Meet Horizon
UI](/blog/2026-06-21-skywalking-horizon-ui-introduction/) series. [Part
6](/blog/2026-06-22-horizon-ui-trace-explorer/) was one request's spans; this
one is the log lines around it. Horizon surfaces logs through **two distinct
tabs**, because there are really two different questions: *"what did this
service log over the last half hour?"* and *"what is this pod printing to
stdout right now?"*
+
+- The **Logs** tab queries the logs SkyWalking has already **collected and
stored** — indexed, filterable, correlated with traces.
+- The **Pod Logs** tab **live-tails** a Kubernetes pod's container logs *on
demand* — these aren't stored logs at all: OAP reads them straight from the
**Kubernetes API server** (the `kubectl logs` path), Horizon shows the window,
and it's discarded. Nothing is persisted, and SkyWalking's log storage is never
involved.
+
+Which tabs a layer shows is up to its template: the **Logs** tab appears on
layers that enable it (General, Mesh, Nginx, the Envoy AI Gateway, the mobile
and mini-program layers); the **Pod Logs** tab appears only on the
Kubernetes-aware layers (Kubernetes Service, Mesh, Mesh data plane). Browser
JavaScript errors are a different thing again — not service logs but
client-side error events the browser agent reports, with their own categories
and their own **source-map de-obfuscation** (tu [...]
+
+## The stored log stream
+
+Open a layer that has a **Logs** tab, pick a service in the header, and its
stored log stream loads newest-first. Like the trace explorer, this tab **owns
its own time range** — the global topbar picker is paused while you're here, so
auto-refresh can't shift the window out from under an investigation. Pick a
rolling preset (last 15 minutes through 24 hours, default 30) or a custom
absolute window; queries run at **second precision** so the most recent lines
are never rounded off the minute.
+
+A conditions bar narrows the stream, and every filter is optional and
AND-joined:
+
+- **Instance** — restrict to one service instance (labelled **Sidecar** on a
sidecar layer).
+- **Endpoint** — type to search the service's endpoints, click to pin, **×**
to clear.
+- **Trace ID** — show only the lines correlated with one trace. This is also
how a log lands when you arrive *from* a trace: the field pre-fills and the
stream is already scoped.
+- **Tags** — a single `key=value` field with autocomplete; start a key to see
suggestions, type `=` to switch to known values, Enter to commit. Committed
tags ride along as removable chips.
+- **Level** — the **Levels** strip above the stream doubles as a filter: click
`error`, `warn`, `info`, or `debug` to keep only that level, click again to
clear.
+
+There's no log query language here — no LogQL box to learn. The conditions
above are the whole surface, and **edits refresh the stream as you make them**;
**Run query** is just the explicit "I'm done editing, refresh now" button that
resets to the first page.
+
+## Reading the stream
+
+The point of a log view isn't to *list* lines, it's to find the shape in them
— so the stream comes with two pieces of orientation above it.
+
+A **density histogram** plots log count over time, each bar **stacked by
level** in the legend's colors; hover a bar for that bucket's time range and
per-level counts. It's drawn from the page currently on screen, so it shows the
shape of what you're looking at. And the **Levels** strip carries a running
count per level — sampled across the window, not just the visible page, so the
error/warn/info mix reflects the whole window you're querying.
+
+Each row then shows the timestamp, the level (the row is color-keyed to it),
the service, an **↗ trace** link when the line is trace-correlated, a **`JSON`
/ `YAML` / `TEXT` format chip**, and a one-line preview of the content. Horizon
decides that chip by what the payload actually *is*: OAP labels a body JSON or
plain text, and on top of that Horizon sniffs for JSON and YAML structure, so
an unlabelled-but-structured line still gets the right treatment — JSON
flattened to one line in th [...]
+
+
+Figure 1: A service's stored log stream — a level histogram and level counts
over the window, then the rows, each tagged JSON / YAML / TEXT and linked to
its trace.</br>
+
+## Into a single line
+
+Click a row and the full payload opens in a popout: the complete content with
**format-aware pretty-printing** — JSON and YAML laid out properly, plain text
given the whole canvas instead of a cramped strip — plus a **Copy** button, the
service / instance / endpoint / trace context, and a table of every tag on the
line. When the line is trace-correlated, an **↗ trace** button opens the
related [trace's waterfall](/blog/2026-06-22-horizon-ui-trace-explorer/) in an
overlay without leaving [...]
+
+
+Figure 2: One line in full — its payload pretty-printed by format, with its
context and every tag laid out beside it.</br>
+
+## Pod Logs: tailing what's printing right now
+
+The **Pod Logs** tab answers the other question, and it's a fundamentally
different source: not SkyWalking's stored logs, but the pod's container output
read live from the **Kubernetes API server** through OAP — the exact thing
`kubectl logs -f` reads. There's no stored history to page through; each
refresh pulls the trailing window, shows it, and throws it away.
+
+Starting a tail is a few picks: choose a **Pod** (one service instance,
pinned), a **Container** (Horizon lists the pod's containers and selects the
first), a look-back **Window** (last 30s, 1m, 5m, 15m, or 30m — how far back
each poll reaches), and a poll **Interval** (2s, 5s, 10s, or 30s — how often it
re-fetches). Press **Start** and the window streams into a read-only viewer
that keeps the newest line in view and re-polls until you **Pause**; a header
strip shows the container, the l [...]
+
+One thing to know going in: on-demand pod logs are **disabled by default on
OAP**, because container output can carry secrets. When the feature is off — or
when the pod you picked has been rolled or scaled away — OAP returns a
*reason*, and Horizon shows it in a banner rather than an empty pane, so you
can tell "turn this on" apart from "that pod is gone."
+
+
+Figure 3: A live tail of one pod's container — windowed, interval-polled,
regex-filterable, never persisted.</br>
+
+## Where to go next
+
+Both tabs — the stored queries, the tag and container autocomplete, and the
live tail — are gated by a single `logs:read` permission, so granting "can read
logs" is one switch. For the field reference — every condition, the histogram,
the Pod Logs windows and filters — see the [Logs
docs](https://skywalking.apache.org/docs/skywalking-horizon-ui/next/operate/logs/).
+
+Next up: **Browser & RUM monitoring** — the browser agent's own error stream,
and de-obfuscating a minified stack with source maps.
diff --git a/static/screenshots/horizon-0.7.0/p07-logs-01-stream.webp
b/static/screenshots/horizon-0.7.0/p07-logs-01-stream.webp
new file mode 100644
index 00000000000..c7d8f451a29
Binary files /dev/null and
b/static/screenshots/horizon-0.7.0/p07-logs-01-stream.webp differ
diff --git a/static/screenshots/horizon-0.7.0/p07-logs-02-payload.webp
b/static/screenshots/horizon-0.7.0/p07-logs-02-payload.webp
new file mode 100644
index 00000000000..39f46cc946d
Binary files /dev/null and
b/static/screenshots/horizon-0.7.0/p07-logs-02-payload.webp differ
diff --git a/static/screenshots/horizon-0.7.0/p07-logs-03-pod-logs.webp
b/static/screenshots/horizon-0.7.0/p07-logs-03-pod-logs.webp
new file mode 100644
index 00000000000..c12b465697d
Binary files /dev/null and
b/static/screenshots/horizon-0.7.0/p07-logs-03-pod-logs.webp differ