diff --git a/ui/src/components/logs/logs-filters.tsx b/ui/src/components/logs/logs-filters.tsx index f1c4436c..4d00d830 100644 --- a/ui/src/components/logs/logs-filters.tsx +++ b/ui/src/components/logs/logs-filters.tsx @@ -44,6 +44,9 @@ export interface LogsFiltersProps { onRequestIdChange?: (v: string) => void; timeWindow?: LogsTimeWindow; onTimeWindowChange?: (v: LogsTimeWindow) => void; + /** When true, hides entries from `web-server:*` sources. Default ON. */ + hideDashboardInternals?: boolean; + onHideDashboardInternalsChange?: (next: boolean) => void; onClearAll?: () => void; } @@ -88,6 +91,8 @@ export function LogsFilters({ onRequestIdChange, timeWindow = 'all', onTimeWindowChange, + hideDashboardInternals = true, + onHideDashboardInternalsChange, onClearAll, }: LogsFiltersProps) { const [advancedOpen, setAdvancedOpen] = useState(false); @@ -312,6 +317,31 @@ export function LogsFilters({ ) : null} + {onHideDashboardInternalsChange ? ( +
+
+ +

+ Suppress web-server:*{' '} + self-polling. +

+
+ onHideDashboardInternalsChange(e.target.checked)} + className={cn('mt-0.5 h-4 w-4 cursor-pointer accent-foreground', FOCUS_RING)} + aria-label="Hide dashboard internals" + /> +
+ ) : null} diff --git a/ui/src/components/logs/logs-shell.tsx b/ui/src/components/logs/logs-shell.tsx index 2e985696..a659ee27 100644 --- a/ui/src/components/logs/logs-shell.tsx +++ b/ui/src/components/logs/logs-shell.tsx @@ -137,6 +137,18 @@ export function LogsShell({ workspace, updateConfig }: LogsShellProps) { [workspace.entriesQuery.data] ); + // Derive header stat strip values once per data refetch. + const headerStats = useMemo(() => { + const data = workspace.entriesQuery.data ?? []; + const requestIds = new Set(); + let errors = 0; + for (const entry of data) { + if (entry.requestId) requestIds.add(entry.requestId); + if (entry.level === 'error') errors += 1; + } + return { entries: data.length, traces: requestIds.size, errors }; + }, [workspace.entriesQuery.data]); + const focusSearch = useCallback(() => { const input = document.getElementById('logs-search') as HTMLInputElement | null; if (input) { @@ -180,6 +192,8 @@ export function LogsShell({ workspace, updateConfig }: LogsShellProps) { onRequestIdChange={workspace.setRequestIdFilter} timeWindow={workspace.timeWindow} onTimeWindowChange={workspace.setTimeWindow} + hideDashboardInternals={workspace.hideDashboardInternals} + onHideDashboardInternalsChange={workspace.setHideDashboardInternals} onClearAll={workspace.clearAdvancedFilters} /> ); @@ -228,6 +242,7 @@ export function LogsShell({ workspace, updateConfig }: LogsShellProps) { isFetching={workspace.entriesQuery.isFetching || workspace.sourcesQuery.isFetching} hasError={Boolean(workspace.entriesQuery.error)} capturedCount={workspace.entriesQuery.data?.length ?? 0} + stats={headerStats} onRefresh={handleRefresh} onOpenSettings={openSettings} onOpenShortcuts={() => setShortcutsOpen(true)} diff --git a/ui/src/hooks/use-logs.ts b/ui/src/hooks/use-logs.ts index 254b9285..702db1f6 100644 --- a/ui/src/hooks/use-logs.ts +++ b/ui/src/hooks/use-logs.ts @@ -116,6 +116,10 @@ export function useLogsWorkspace() { const [limit, setLimit] = useState(DEFAULT_LIMIT); const [selectedEntryId, setSelectedEntryId] = useState(null); const [isPaused, setIsPaused] = useState(false); + // Default ON: dashboard self-polling generates 100s of identical entries + // per refresh which drown out real provider activity. Users can opt in to + // see internals via the advanced filter toggle. + const [hideDashboardInternals, setHideDashboardInternals] = useState(true); const frozenIdsRef = useRef>(new Set()); const deferredSearch = useDeferredValue(search.trim()); @@ -151,6 +155,7 @@ export function useLogsWorkspace() { debouncedRequestId, timeWindow, limit, + hideDashboardInternals ? 'hide-internals' : 'show-internals', mockEnabled ? 'mock' : 'live', ], queryFn: async () => { @@ -191,6 +196,9 @@ export function useLogsWorkspace() { const ts = Date.parse(entry.timestamp); if (Number.isFinite(ts) && now - ts > cutoffMs) return false; } + // Hide dashboard self-polling unless user opted in. Preserves the + // signal-to-noise ratio for fresh-load investigations. + if (hideDashboardInternals && /^web-server:/i.test(entry.source)) return false; return true; }); const head = filtered[0]; @@ -265,6 +273,7 @@ export function useLogsWorkspace() { setStageFilter(''); setRequestIdFilter(''); setTimeWindow('all'); + setHideDashboardInternals(true); }, []); return { @@ -285,6 +294,8 @@ export function useLogsWorkspace() { setRequestIdFilter, timeWindow, setTimeWindow, + hideDashboardInternals, + setHideDashboardInternals, limit, setLimit, selectedEntryId: activeSelectedEntryId,