Skip to content

Commit 4a3a426

Browse files
committed
[local-explorer-ui] Hide Vite's internal plumbing from the Observability views
Vite's own module-init and export-type requests were listed as traces, and its module-runner RPC dispatch as logs — 8 of 11 rows in the Traces list for one real session. None of it exists in a deployed Worker, so it's hidden by default and the toggle it sat behind has gone; build the UI with VITE_LOCAL_EXPLORER_SHOW_VITE_INTERNALS=true to see it. Vite's requests are matched by URL path rather than wrapper-service name, because Vite routes every request through its router worker — matching a root span by name would have hidden the user's real traffic too. The executeCallback shape rule only applies inside a trace already known to be Vite, so a wrangler dev user with an RPC method of that name keeps their logs. Failures are never hidden.
1 parent 24c5e91 commit 4a3a426

4 files changed

Lines changed: 188 additions & 87 deletions

File tree

.changeset/hide-vite-internals.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"miniflare": patch
3+
"wrangler": patch
4+
---
5+
6+
Hide Vite's internal plumbing from the Observability views
7+
8+
Under the Vite plugin your Worker runs inside a runner Durable Object behind a couple of wrapper workers. Vite's own module-init and export-type requests were showing up as traces, and its RPC dispatch was showing up as logs — in one session that was 8 of 11 rows in the Traces list. None of it exists in a deployed Worker, so it's now hidden, and the show/hide toggle it used to sit behind has gone.
9+
10+
Failures are never hidden, and a plain `wrangler dev` session is unaffected.

packages/local-explorer-ui/src/__tests__/observability/observability.test.ts

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import { describe, test } from "vitest";
1+
import { beforeEach, describe, test, vi } from "vitest";
2+
import { observabilityQuery } from "../../api";
23
import {
34
buildSpanTree,
45
buildWaterfall,
56
formatDuration,
67
formatLogMessage,
78
isRunning,
89
isViteWrapperSpan,
10+
listEvents,
11+
listTraces,
912
parseAttributes,
1013
spanIsError,
1114
stripDevRunnerSpans,
@@ -15,6 +18,11 @@ import {
1518
} from "../../utils/observability";
1619
import type { Span } from "../../utils/observability";
1720

21+
vi.mock("../../api", () => ({
22+
observabilityQuery: vi.fn(),
23+
observabilityClear: vi.fn(),
24+
}));
25+
1826
function span(partial: Partial<Span>): Span {
1927
return {
2028
trace_id: "t",
@@ -150,6 +158,81 @@ describe("isViteWrapperSpan", () => {
150158
});
151159
});
152160

161+
describe("listEvents filtering", () => {
162+
beforeEach(() => {
163+
vi.mocked(observabilityQuery).mockReset();
164+
vi.mocked(observabilityQuery).mockResolvedValue({
165+
data: { result: { columns: [], rows: [] } },
166+
} as never);
167+
});
168+
169+
async function eventsSql(): Promise<string> {
170+
await listEvents();
171+
const call = vi.mocked(observabilityQuery).mock.calls.at(-1)?.[0];
172+
return String((call as { body?: { sql?: string } })?.body?.sql ?? "");
173+
}
174+
175+
test("only hides executeCallback logs when the trace is really Vite dev", async ({
176+
expect,
177+
}) => {
178+
// A `wrangler dev` user can have their own executeCallback RPC method, so
179+
// the shape rule must be paired with a wrapper-span check on the trace.
180+
const sql = await eventsSql();
181+
expect(sql).toMatch(
182+
/executeCallback[\s\S]*EXISTS[\s\S]*v\.trace_id = l\.trace_id/
183+
);
184+
});
185+
186+
test("filters in the WHERE clause, before LIMIT", async ({ expect }) => {
187+
// Filtering after LIMIT would short-change the page and skew its count.
188+
const sql = await eventsSql();
189+
const where = sql.indexOf("WHERE");
190+
expect(where).toBeGreaterThan(-1);
191+
expect(sql.indexOf("executeCallback")).toBeGreaterThan(where);
192+
expect(sql.lastIndexOf("LIMIT ?")).toBeGreaterThan(
193+
sql.indexOf("executeCallback")
194+
);
195+
});
196+
});
197+
198+
describe("listTraces filtering", () => {
199+
beforeEach(() => {
200+
vi.mocked(observabilityQuery).mockReset();
201+
vi.mocked(observabilityQuery).mockResolvedValue({
202+
data: { result: { columns: [], rows: [] } },
203+
} as never);
204+
});
205+
206+
async function tracesSql(): Promise<string> {
207+
await listTraces();
208+
const call = vi.mocked(observabilityQuery).mock.calls.at(-1)?.[0];
209+
return String((call as { body?: { sql?: string } })?.body?.sql ?? "");
210+
}
211+
212+
test("hides Vite's own internal requests by path", async ({ expect }) => {
213+
const sql = await tracesSql();
214+
expect(sql).toContain("'/__vite_plugin_cloudflare'");
215+
});
216+
217+
test("doesn't marker-match the root span, which would hide real traffic", async ({
218+
expect,
219+
}) => {
220+
// Vite routes every request through __router-worker__, so a root-span
221+
// marker match would blank out the user's own requests too.
222+
const sql = await tracesSql();
223+
expect(sql).not.toContain("__router-worker__");
224+
});
225+
226+
test("keeps a hidden Vite request visible when it failed", async ({
227+
expect,
228+
}) => {
229+
// Only a 5xx (or an uncaught error) counts as a failure — a 404 is just how
230+
// an unserved path answers.
231+
const sql = await tracesSql();
232+
expect(sql).toMatch(/AND NOT COALESCE\([\s\S]*>= 500/);
233+
});
234+
});
235+
153236
describe("traceExtentMs", () => {
154237
test("measures latest end minus earliest start", ({ expect }) => {
155238
const spans = [

packages/local-explorer-ui/src/routes/observability/index.tsx

Lines changed: 3 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import {
66
Select,
77
} from "@cloudflare/kumo";
88
import {
9-
EyeIcon,
10-
EyeSlashIcon,
119
InfoIcon,
1210
ListBulletsIcon,
1311
MagnifyingGlassIcon,
@@ -39,9 +37,9 @@ import {
3937
getTagKeys,
4038
isObservabilityDisabledError,
4139
isRunning,
42-
isViteWrapperSpan,
4340
listTraces,
4441
operationLabel,
42+
SHOW_VITE_INTERNALS,
4543
spanIsError,
4644
traceExtentMs,
4745
visibleTraceSpans,
@@ -52,8 +50,6 @@ import type { Span, TraceRow } from "../../utils/observability";
5250
import type { QueryClause } from "../../utils/observability-query";
5351
import type { JSX } from "react";
5452

55-
const HIDE_DEV_RUNNER_KEY = "wobs-hide-dev-runner";
56-
5753
/** Display labels for the status/type filter dropdowns (excluding the "all" state). */
5854
const STATUS_LABELS: Record<string, string> = {
5955
success: "Success",
@@ -134,27 +130,6 @@ function ObservabilityView(): JSX.Element {
134130
// trace list, and pause polling so we don't hammer a disabled endpoint.
135131
const [disabled, setDisabled] = useState(false);
136132
const [clearing, setClearing] = useState(false);
137-
// Hide Vite dev module-runner plumbing spans (default on; persisted).
138-
const [hideDevRunner, setHideDevRunner] = useState(() => {
139-
try {
140-
return localStorage.getItem(HIDE_DEV_RUNNER_KEY) !== "false";
141-
} catch {
142-
return true;
143-
}
144-
});
145-
const toggleHideDevRunner = useCallback(() => {
146-
setHideDevRunner((prev) => {
147-
const next = !prev;
148-
try {
149-
localStorage.setItem(HIDE_DEV_RUNNER_KEY, String(next));
150-
} catch {
151-
// ignore
152-
}
153-
return next;
154-
});
155-
}, []);
156-
// Session-only dismissal of the "running under Vite dev" notice.
157-
const [viteNoticeDismissed, setViteNoticeDismissed] = useState(false);
158133
// Traces whose inline log panel is expanded (keyed by traceKey).
159134
const [showLogsFor, setShowLogsFor] = useState<Set<string>>(new Set());
160135
const toggleLogs = useCallback((key: string) => {
@@ -336,16 +311,6 @@ function ObservabilityView(): JSX.Element {
336311
[traces]
337312
);
338313

339-
// Detect a Vite dev session from the data: Vite routes every request through
340-
// its router/asset workers, so any HTTP trace is rooted in an infra worker.
341-
// (Internally-triggered traces — alarm/queue/cron — are rooted in the user
342-
// worker, but a real session always has at least one request too.)
343-
const isViteDev = useMemo(
344-
() => traces.some((t) => isViteWrapperSpan(t)),
345-
[traces]
346-
);
347-
const showViteNotice = isViteDev && !viteNoticeDismissed;
348-
349314
if (disabled) {
350315
return <ObservabilityDisabled />;
351316
}
@@ -361,20 +326,6 @@ function ObservabilityView(): JSX.Element {
361326
</span>
362327
</div>
363328
<div className="flex-1" />
364-
<Button
365-
size="sm"
366-
variant={hideDevRunner ? "secondary" : "ghost"}
367-
icon={hideDevRunner ? EyeIcon : EyeSlashIcon}
368-
title={
369-
hideDevRunner
370-
? "Show Vite dev module-runner plumbing spans (vite dev only)"
371-
: "Hide Vite dev module-runner plumbing spans (vite dev only)"
372-
}
373-
aria-pressed={hideDevRunner}
374-
onClick={toggleHideDevRunner}
375-
>
376-
{hideDevRunner ? "Show Vite runner spans" : "Hide Vite runner spans"}
377-
</Button>
378329
<ClearButton
379330
onConfirm={handleClear}
380331
loading={clearing}
@@ -388,29 +339,6 @@ function ObservabilityView(): JSX.Element {
388339
/>
389340
</header>
390341

391-
{showViteNotice ? (
392-
<div className="flex items-center gap-2 border-b border-kumo-fill bg-blue-500/10 px-6 py-2 text-xs text-kumo-default">
393-
<InfoIcon size={14} className="shrink-0 text-blue-500" />
394-
<span className="flex-1">
395-
{hideDevRunner
396-
? "Running under Vite dev — some spans come from Vite's module runner (module loading, RPC dispatch) rather than your code. They're hidden by “Hide Vite runner spans”."
397-
: "Running under Vite dev — Vite module-runner spans (module loading, RPC dispatch) are shown and may add noise to your traces."}
398-
</span>
399-
<Button size="sm" variant="secondary" onClick={toggleHideDevRunner}>
400-
{hideDevRunner
401-
? "Show Vite runner spans"
402-
: "Hide Vite runner spans"}
403-
</Button>
404-
<Button
405-
size="sm"
406-
variant="ghost"
407-
icon={XIcon}
408-
aria-label="Dismiss notice"
409-
onClick={() => setViteNoticeDismissed(true)}
410-
/>
411-
</div>
412-
) : null}
413-
414342
{/* filter bar — a simpler version of the dashboard query builder */}
415343
<div className="flex items-center gap-2 border-b border-kumo-fill px-6 py-3">
416344
<InputGroup size="sm" className="flex-1">
@@ -551,7 +479,7 @@ function ObservabilityView(): JSX.Element {
551479
// e.g. an alarm's ~15s runner-dispatch span as its duration.
552480
const shownSpans =
553481
isSel && spans.length
554-
? visibleTraceSpans(spans, hideDevRunner)
482+
? visibleTraceSpans(spans, !SHOW_VITE_INTERNALS)
555483
: spans;
556484
const shownDur =
557485
isSel && spans.length ? traceExtentMs(shownSpans) : dur;
@@ -660,7 +588,7 @@ function ObservabilityView(): JSX.Element {
660588
rootSpanId={t.root_span_id}
661589
traceDurationMs={shownDur}
662590
invocationRootIds={invocationRootsByTrace[key]}
663-
hideDevRunner={hideDevRunner}
591+
hideDevRunner={!SHOW_VITE_INTERNALS}
664592
/>
665593
{showLogsFor.has(key) ? (
666594
<InvocationLogs traceId={t.trace_id} />

0 commit comments

Comments
 (0)