feat(logs): add realtime, supavisor, and pgbouncer to unified logs (#46786)

## 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.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## 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.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jordi Enric
2026-06-09 18:46:37 +02:00
committed by GitHub
parent 136a7be98f
commit 9c572a56fd
6 changed files with 58 additions and 28 deletions

View File

@@ -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(() => {

View File

@@ -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({

View File

@@ -53,6 +53,9 @@ const LOG_TYPE_PREDICATE: Record<string, SafeLogSqlFragment> = {
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`

View File

@@ -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

View File

@@ -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<Record<(typeof LOG_TYPES)[number], IconComponent>> = {
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: () => <Globe size={size} strokeWidth={strokeWidth} className={className} />,
postgrest: () => <Code2 size={size} strokeWidth={strokeWidth} className={className} />,
auth: () => <Auth size={size} strokeWidth={strokeWidth} className={className} />,
'edge function': () => (
<EdgeFunctions size={size} strokeWidth={strokeWidth} className={className} />
),
postgres: () => <Database size={size} strokeWidth={strokeWidth} className={className} />,
// function_events: () => (
// <EdgeFunctions size={size} strokeWidth={strokeWidth} className={className} />
// ),
// supavisor: () => <Cpu size={size} strokeWidth={strokeWidth} className={className} />,
// postgres_upgrade: () => <Cpu size={size} strokeWidth={strokeWidth} className={className} />,
storage: () => <Storage size={size} strokeWidth={strokeWidth} className={className} />,
// cron: () => <Clock size={size} strokeWidth={strokeWidth} className={className} />,
}
const IconComponent =
iconMap[type] || (() => <Box size={size} strokeWidth={strokeWidth} className={className} />)
const Icon = ICON_MAP[type] ?? Box
return (
<Tooltip>
<TooltipTrigger>
<IconComponent />
<Icon size={size} strokeWidth={strokeWidth} className={className} />
</TooltipTrigger>
<TooltipContent side="left">
<div className="text-xs">{type}</div>

View File

@@ -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
}