From 9c572a56fd46c5bd41eaabaa2272e8917ec3d9bf Mon Sep 17 00:00:00 2001 From: Jordi Enric <37541088+jordienr@users.noreply.github.com> Date: Tue, 9 Jun 2026 18:46:37 +0200 Subject: [PATCH] feat(logs): add realtime, supavisor, and pgbouncer to unified logs (#46786) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem The unified logs view was missing three log sources that the backend already returns: Realtime (`realtime_logs`), Supavisor (`supavisor_logs`), and PgBouncer (`pgbouncer_logs`). Users had no way to filter or view logs from these services in the unified view. ## Fix - Added `realtime`, `supavisor`, and `pgbouncer` to `LOG_TYPE_PREDICATE` and `LOG_TYPE_EXPR` in the OTEL query builder so rows from these sources are matched and labeled correctly. - Added the three types to `LOG_TYPES` so filter chips appear in the UI. - Added icons (`Realtime` from the icons package, `Cable` from lucide-react for both pooler types) in `LogTypeIcon.tsx`. - Added display labels in `formatServiceTypeForDisplay` (`Realtime`, `Supavisor`, `PgBouncer`). - Fixed a pre-existing unsafe cast in `ServiceFlowPanel.tsx` where any log type not in the service flow allow-list (like the new types) would produce a truthy `serviceFlowType` and trigger a runtime error on row click. The fix checks against `SERVICE_FLOW_TYPES` before casting. Note: `pg_cron_logs` is not included because the backend otel query does not yet return that source. ## How to test 1. Open unified logs for a project that has Realtime activity. 2. In the log type filter, confirm `realtime`, `supavisor`, and `pgbouncer` chips are visible. 3. Toggle on `realtime` and confirm Realtime logs appear with the correct icon. 4. Click a realtime log row and confirm the detail panel opens on the raw JSON tab without a runtime error. 5. Toggle on `supavisor` or `pgbouncer` and confirm pooler logs appear if the project has connection pooler activity. ## Summary by CodeRabbit * **New Features** * Added support for three new log types — Realtime, Supavisor, and PgBouncer — in Unified Logs with display labels, icons, and filtering/viewing support. * **Bug Fixes / UI Behavior** * Service Flow “Overview” tab now only shows when the service type is recognized, preventing irrelevant overview content for unsupported log sources. --------- Co-authored-by: Claude Sonnet 4.6 --- .../UnifiedLogs/ServiceFlowPanel.tsx | 9 +++- .../UnifiedLogs/UnifiedLogs.constants.tsx | 11 ++++- .../UnifiedLogs/UnifiedLogs.queries.ts | 6 +++ .../UnifiedLogs/UnifiedLogs.utils.ts | 3 ++ .../UnifiedLogs/components/LogTypeIcon.tsx | 47 +++++++++---------- packages/common/telemetry-constants.ts | 10 +++- 6 files changed, 58 insertions(+), 28 deletions(-) diff --git a/apps/studio/components/interfaces/UnifiedLogs/ServiceFlowPanel.tsx b/apps/studio/components/interfaces/UnifiedLogs/ServiceFlowPanel.tsx index c4a7723148a..ff6058b87c7 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/ServiceFlowPanel.tsx +++ b/apps/studio/components/interfaces/UnifiedLogs/ServiceFlowPanel.tsx @@ -30,6 +30,7 @@ import { QuerySearchParamsType } from './UnifiedLogs.types' import { getRowTimestampMs } from './UnifiedLogs.utils' import { useDataTable } from '@/components/ui/DataTable/providers/DataTableProvider' import { + SERVICE_FLOW_TYPES, ServiceFlowType, useUnifiedLogInspectionQuery, } from '@/data/logs/unified-log-inspection-query' @@ -63,8 +64,12 @@ export function ServiceFlowPanel({ }, [selectedRowKey]) const logType = selectedRow?.log_type - const serviceFlowType: ServiceFlowType | undefined = - logType === 'edge function' ? 'edge-function' : (logType as ServiceFlowType) + const normalizedLogType = logType === 'edge function' ? 'edge-function' : logType + const serviceFlowType: ServiceFlowType | undefined = SERVICE_FLOW_TYPES.includes( + normalizedLogType as ServiceFlowType + ) + ? (normalizedLogType as ServiceFlowType) + : undefined const shouldShowServiceFlow = !!serviceFlowType useEffect(() => { diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.constants.tsx b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.constants.tsx index 47e7b5c2ab7..8abac9cca6d 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.constants.tsx +++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.constants.tsx @@ -16,7 +16,16 @@ import { export const REGIONS = ['ams', 'fra', 'gru', 'hkg', 'iad', 'syd'] as const export const METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'] as const -export const LOG_TYPES = ['postgres', 'postgrest', 'auth', 'storage', 'edge function'] as const +export const LOG_TYPES = [ + 'postgres', + 'postgrest', + 'auth', + 'storage', + 'edge function', + 'realtime', + 'supavisor', + 'pgbouncer', +] as const export const DEFAULT_LOG_TYPES = ['postgres', 'postgrest'] as const const parseAsSort = createParser({ diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.queries.ts b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.queries.ts index 5d111ac7ec2..01839820d90 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.queries.ts +++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.queries.ts @@ -53,6 +53,9 @@ const LOG_TYPE_PREDICATE: Record = { postgres: safeSql`source = 'postgres_logs'`, 'edge function': safeSql`source = 'function_edge_logs'`, auth: safeSql`source = 'auth_logs'`, + realtime: safeSql`source = 'realtime_logs'`, + supavisor: safeSql`source = 'supavisor_logs'`, + pgbouncer: safeSql`source = 'pgbouncer_logs'`, } // Derived `log_type` column for SELECT / GROUP BY / countIf use. @@ -63,6 +66,9 @@ const LOG_TYPE_EXPR: SafeLogSqlFragment = safeSql`CASE WHEN source = 'postgres_logs' THEN 'postgres' WHEN source = 'function_edge_logs' THEN 'edge function' WHEN source = 'auth_logs' THEN 'auth' + WHEN source = 'realtime_logs' THEN 'realtime' + WHEN source = 'supavisor_logs' THEN 'supavisor' + WHEN source = 'pgbouncer_logs' THEN 'pgbouncer' ELSE source END` diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.utils.ts b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.utils.ts index c526a0cfcdd..bc2c09fea07 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.utils.ts +++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.utils.ts @@ -95,6 +95,9 @@ export function formatServiceTypeForDisplay(serviceType: string): string { postgres: 'Postgres', auth: 'Auth', storage: 'Storage', + realtime: 'Realtime', + supavisor: 'Supavisor', + pgbouncer: 'PgBouncer', } return specialCases[serviceType.toLowerCase()] || serviceType diff --git a/apps/studio/components/interfaces/UnifiedLogs/components/LogTypeIcon.tsx b/apps/studio/components/interfaces/UnifiedLogs/components/LogTypeIcon.tsx index 2d85e47a3aa..73134ae74fe 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/components/LogTypeIcon.tsx +++ b/apps/studio/components/interfaces/UnifiedLogs/components/LogTypeIcon.tsx @@ -1,5 +1,5 @@ -import { Auth, EdgeFunctions, Storage } from 'icons' -import { Box, Code2, Database } from 'lucide-react' +import { Auth, EdgeFunctions, Realtime, Storage } from 'icons' +import { Box, Cable, Code2, Database } from 'lucide-react' import { Tooltip, TooltipContent, TooltipTrigger } from 'ui' import { type LOG_TYPES } from '../UnifiedLogs.constants' @@ -11,38 +11,37 @@ interface LogTypeIconProps { className?: string } +type IconComponent = React.ComponentType<{ + size?: number + strokeWidth?: number + className?: string +}> + +// [Alaister]: commented out types coming in the future +// edge: Globe, +const ICON_MAP: Partial> = { + postgrest: Code2, + auth: Auth, + 'edge function': EdgeFunctions, + postgres: Database, + storage: Storage, + realtime: Realtime, + supavisor: Cable, + pgbouncer: Cable, +} + export const LogTypeIcon = ({ type, size = 16, strokeWidth = 1.5, className, }: LogTypeIconProps) => { - // [Alaister]: commented out types coming in the future - const iconMap: Record<(typeof LOG_TYPES)[number], () => React.ReactNode> = { - // edge: () => , - postgrest: () => , - auth: () => , - 'edge function': () => ( - - ), - postgres: () => , - // function_events: () => ( - // - // ), - // supavisor: () => , - // postgres_upgrade: () => , - storage: () => , - - // cron: () => , - } - - const IconComponent = - iconMap[type] || (() => ) + const Icon = ICON_MAP[type] ?? Box return ( - +
{type}
diff --git a/packages/common/telemetry-constants.ts b/packages/common/telemetry-constants.ts index a06cd36d605..d000c1e47ee 100644 --- a/packages/common/telemetry-constants.ts +++ b/packages/common/telemetry-constants.ts @@ -3154,7 +3154,15 @@ export interface UnifiedLogsRowClickedEvent { * Server values are validated against this set by zod (UnifiedLogs.schema.ts) before * reaching the table; anything else is rejected upstream so the union here is exhaustive. */ - logType: 'postgres' | 'postgrest' | 'auth' | 'storage' | 'edge function' + logType: + | 'postgres' + | 'postgrest' + | 'auth' + | 'storage' + | 'edge function' + | 'realtime' + | 'supavisor' + | 'pgbouncer' } groups: TelemetryGroups }