Skip to content

Commit 5f4153d

Browse files
authored
Adjust auth log detail pane in unified logs (supabase#46372)
## Context Currently when opening an auth log, the log details panel is seemingly very empty Auth logs are pretty empty by their nature unlike the other logs so am opting to adjust the detail panel for them slightly ### Changes involved - Fixing passing `host` and `path` when rendering auth log details - Opting to only show "Network" + "Authentication" segments for auth (The other fields do not apply for auth logs) <img width="434" height="476" alt="image" src="https://github.com/user-attachments/assets/cf8bb128-2332-424a-a10e-a7e836acb7d5" /> - Make each section collapsible, allow users to adjust themselves how they want to consume the information <img width="421" height="474" alt="image" src="https://github.com/user-attachments/assets/e842bc79-edff-4ec6-ae38-a9249966881d" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Postgres connection and session info now appear in separate expandable sections for easier browsing * Auth-related fields (ID, status, path, referer) now extract and present richer, more accurate values * Request path and host resolution improved across service flow/network views * **Bug Fixes / Improvements** * Safer parsing of auth event messages and more robust fallbacks for missing fields * Cleaner row styling and section rendering for consistent visuals <!-- review_stack_entry_start --> [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46372?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent f5c732b commit 5f4153d

6 files changed

Lines changed: 135 additions & 87 deletions

File tree

apps/studio/components/interfaces/UnifiedLogs/ServiceFlow/components/blocks/PostgresFlowDetail.tsx

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Table } from '@tanstack/react-table'
2-
import { Cable, Clock, Database } from 'lucide-react'
2+
import { Cable, ChevronDown, Clock, Database } from 'lucide-react'
33
import { memo } from 'react'
4+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from 'ui'
45

56
import { ColumnSchema } from '../../../UnifiedLogs.schema'
67
import { getRowTimestampMs } from '../../../UnifiedLogs.utils'
@@ -70,40 +71,52 @@ export const PostgresFlowDetail = memo(function PostgresFlowDetail({
7071
((data as Record<string, unknown>)?.error_severity as string | undefined)
7172

7273
return (
73-
<div className="[&>*:nth-child(even)]:bg-surface-100/50">
74+
<div>
7475
<DetailSectionHeader
7576
title="Request started"
7677
icon={Clock}
7778
summary={formattedTime ?? undefined}
7879
/>
7980

80-
<DetailSectionHeader title="Postgres" icon={Database} />
81+
<Collapsible defaultOpen>
82+
<CollapsibleTrigger className="w-full flex items-center justify-between pr-4 [&[data-state=open]>svg]:-rotate-180!">
83+
<DetailSectionHeader title="Postgres" icon={Database} />
84+
<ChevronDown className="transition-transform duration-200" strokeWidth={1.5} size={14} />
85+
</CollapsibleTrigger>
86+
<CollapsibleContent className="[&>*:nth-child(odd)]:bg-surface-100/50">
87+
{postgresPrimaryFields.map((field) => (
88+
<FieldDetailRow
89+
key={field.id}
90+
config={field}
91+
data={data}
92+
enrichedData={enrichedData}
93+
isLoading={isLoading}
94+
filterFields={filterFields}
95+
table={table}
96+
/>
97+
))}
98+
</CollapsibleContent>
99+
</Collapsible>
81100

82-
{postgresPrimaryFields.map((field) => (
83-
<FieldDetailRow
84-
key={field.id}
85-
config={field}
86-
data={data}
87-
enrichedData={enrichedData}
88-
isLoading={isLoading}
89-
filterFields={filterFields}
90-
table={table}
91-
/>
92-
))}
93-
94-
<DetailSectionHeader title="Connection & Session Details" icon={Cable} />
95-
96-
{postgresDetailsFields.map((field) => (
97-
<FieldDetailRow
98-
key={field.id}
99-
config={field}
100-
data={data}
101-
enrichedData={enrichedData}
102-
isLoading={isLoading}
103-
filterFields={filterFields}
104-
table={table}
105-
/>
106-
))}
101+
<Collapsible defaultOpen>
102+
<CollapsibleTrigger className="w-full flex items-center justify-between pr-4 [&[data-state=open]>svg]:-rotate-180!">
103+
<DetailSectionHeader title="Connection & Session Details" icon={Cable} />
104+
<ChevronDown className="transition-transform duration-200" strokeWidth={1.5} size={14} />
105+
</CollapsibleTrigger>
106+
<CollapsibleContent className="[&>*:nth-child(odd)]:bg-surface-100/50">
107+
{postgresDetailsFields.map((field) => (
108+
<FieldDetailRow
109+
key={field.id}
110+
config={field}
111+
data={data}
112+
enrichedData={enrichedData}
113+
isLoading={isLoading}
114+
filterFields={filterFields}
115+
table={table}
116+
/>
117+
))}
118+
</CollapsibleContent>
119+
</Collapsible>
107120

108121
<DetailSectionHeader
109122
title="Operation result"

apps/studio/components/interfaces/UnifiedLogs/ServiceFlow/components/shared/Block.tsx

Lines changed: 70 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import { LucideIcon } from 'lucide-react'
1+
import { partition } from 'lodash'
2+
import { ChevronDown, LucideIcon } from 'lucide-react'
23
import { memo } from 'react'
4+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from 'ui'
35

46
import { BlockFieldConfig, BlockFieldProps, ServiceFlowBlockProps } from '../../types'
57
import { DetailRow } from './DetailRow'
@@ -59,25 +61,30 @@ export function createBlock(config: BlockConfig) {
5961
filterFields,
6062
table,
6163
}: ServiceFlowBlockProps) {
62-
return (
63-
<>
64-
<DetailSectionHeader title={config.title} icon={config.icon} />
64+
const [seeMoreFieldsSections, otherSections] = partition(
65+
config.sections,
66+
(x) => 'type' in x && x.type === 'fieldWithSeeMore'
67+
) as [FieldWithSeeMoreSection[], BlockSection[]]
6568

66-
{config.primaryFields?.map((field) => (
67-
<FieldRow
68-
key={field.id}
69-
config={field}
70-
data={data}
71-
enrichedData={enrichedData}
72-
isLoading={isLoading}
73-
filterFields={filterFields}
74-
table={table}
75-
/>
76-
))}
69+
/**
70+
* [Joshen] AFAICT, a lot of the fields do not apply for auth logs as the data is not present
71+
* Am opting to hide all the additional fields only for auth logs, but we can present them if
72+
* we do eventually have the data to show
73+
*/
7774

78-
{config.sections?.map((section) => {
79-
if ('type' in section && section.type === 'fieldWithSeeMore') {
80-
return [section.primaryField, ...section.additionalFields].map((field) => (
75+
return (
76+
<>
77+
<Collapsible defaultOpen>
78+
<CollapsibleTrigger className="w-full flex items-center justify-between pr-4 [&[data-state=open]>svg]:-rotate-180!">
79+
<DetailSectionHeader title={config.title} icon={config.icon} />
80+
<ChevronDown
81+
className="transition-transform duration-200"
82+
strokeWidth={1.5}
83+
size={14}
84+
/>
85+
</CollapsibleTrigger>
86+
<CollapsibleContent className="[&>*:nth-child(odd)]:bg-surface-100/50">
87+
{config.primaryFields?.map((field) => (
8188
<FieldRow
8289
key={field.id}
8390
config={field}
@@ -87,27 +94,52 @@ export function createBlock(config: BlockConfig) {
8794
filterFields={filterFields}
8895
table={table}
8996
/>
90-
))
91-
}
97+
))}
98+
{data.log_type !== 'auth' &&
99+
seeMoreFieldsSections.map((section) => {
100+
return [section.primaryField, ...section.additionalFields].map((field) => (
101+
<FieldRow
102+
key={field.id}
103+
config={field}
104+
data={data}
105+
enrichedData={enrichedData}
106+
isLoading={isLoading}
107+
filterFields={filterFields}
108+
table={table}
109+
/>
110+
))
111+
})}
112+
</CollapsibleContent>
113+
</Collapsible>
92114

93-
const blockSection = section as BlockSection
94-
return (
95-
<span key={blockSection.title} className="contents">
96-
<DetailSectionHeader title={blockSection.title} icon={blockSection.icon} />
97-
{blockSection.fields.map((field) => (
98-
<FieldRow
99-
key={field.id}
100-
config={field}
101-
data={data}
102-
enrichedData={enrichedData}
103-
isLoading={isLoading}
104-
filterFields={filterFields}
105-
table={table}
106-
/>
107-
))}
108-
</span>
109-
)
110-
})}
115+
{data.log_type !== 'auth' &&
116+
otherSections.map((section) => {
117+
return (
118+
<Collapsible key={section.title}>
119+
<CollapsibleTrigger className="w-full flex items-center justify-between pr-4 [&[data-state=open]>svg]:-rotate-180!">
120+
<DetailSectionHeader title={section.title} icon={section.icon} />
121+
<ChevronDown
122+
className="transition-transform duration-200"
123+
strokeWidth={1.5}
124+
size={14}
125+
/>
126+
</CollapsibleTrigger>
127+
<CollapsibleContent className="[&>*:nth-child(odd)]:bg-surface-100/50">
128+
{section.fields.map((field) => (
129+
<FieldRow
130+
key={field.id}
131+
config={field}
132+
data={data}
133+
enrichedData={enrichedData}
134+
isLoading={isLoading}
135+
filterFields={filterFields}
136+
table={table}
137+
/>
138+
))}
139+
</CollapsibleContent>
140+
</Collapsible>
141+
)
142+
})}
111143
</>
112144
)
113145
})

apps/studio/components/interfaces/UnifiedLogs/ServiceFlow/config/serviceFlowFields.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { BlockFieldConfig } from '../types'
22
import { getStorageMetadata } from '../utils/storageUtils'
3-
import { formatBytes } from '@/lib/helpers'
3+
import { formatBytes, tryParseJson } from '@/lib/helpers'
44

55
// Helper functions that avoid duplication with existing storage utilities
66
const getFileName = (path: string): string => {
@@ -371,28 +371,34 @@ export const postgrestResponseFields: BlockFieldConfig[] = [
371371
// Primary GoTrue/Auth Fields (Always Visible)
372372
export const authPrimaryFields: BlockFieldConfig[] = [
373373
{
374-
id: 'auth_path',
375-
label: 'Auth Path',
374+
id: 'log_id',
375+
label: 'Log ID',
376376
getValue: (data, enrichedData) => {
377-
return enrichedData?.path || enrichedData?.request_path || data?.path
377+
const logId = data?.id || enrichedData?.id
378+
return logId ?? null
378379
},
379-
requiresEnrichedData: true,
380380
},
381381
{
382-
id: 'log_id',
383-
label: 'Log ID',
382+
id: 'status',
383+
label: 'Status',
384+
getValue: (data) => {
385+
return data.status
386+
},
387+
},
388+
{
389+
id: 'auth_path',
390+
label: 'Auth Path',
384391
getValue: (data, enrichedData) => {
385-
const logId = data?.id || enrichedData?.id
386-
return logId ? `${logId.substring(0, 8)}...` : null
392+
return enrichedData?.path || enrichedData?.request_path || data?.path || data?.pathname
387393
},
388394
},
389395
{
390396
id: 'referer',
391397
label: 'Referer',
392-
getValue: (_data, enrichedData) => {
393-
return enrichedData?.headers_referer || null
398+
getValue: (data, enrichedData) => {
399+
const eventMessage = tryParseJson(data.event_message)
400+
return eventMessage?.referer || enrichedData?.headers_referer || null
394401
},
395-
requiresEnrichedData: true,
396402
},
397403
]
398404

apps/studio/components/interfaces/UnifiedLogs/ServiceFlowPanel.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,21 +158,19 @@ export function ServiceFlowPanel({
158158
table={table}
159159
/>
160160
) : (
161-
<div className="[&>*:nth-child(even)]:bg-surface-100/50">
161+
<div>
162162
<DetailSectionHeader
163163
title="Request started"
164164
icon={Clock}
165165
summary={formattedTime ?? undefined}
166166
/>
167-
168167
<MemoizedNetworkBlock
169168
data={selectedRow}
170169
enrichedData={serviceFlowData?.result?.[0]}
171170
isLoading={isLoading}
172171
filterFields={filterFields}
173172
table={table}
174173
/>
175-
176174
{serviceFlowType === 'auth' ? (
177175
<MemoizedGoTrueBlock
178176
data={selectedRow}

apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.utils.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,8 @@ export function parseAuthLogEventMessage(value: string | undefined): string | un
136136

137137
const msg = parsed.msg
138138
if (typeof msg === 'string' && msg.trim()) {
139-
const authEvent =
140-
'action' in parsed || 'auth_event_action' in parsed
141-
? (parsed.action || parsed.auth_event.action).replaceAll('_', ' ')
142-
: undefined
139+
const action = parsed.action ?? parsed.auth_event?.action
140+
const authEvent = typeof action === 'string' ? action.replaceAll('_', ' ') : undefined
143141
return `${authEvent ? `${authEvent}: ` : ''}${msg}`
144142
}
145143
}

apps/studio/data/logs/otel-inspection.utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ export function flattenOtelInspectionRow(
4040
): UnifiedLogInspectionEntry & Record<string, unknown> {
4141
const attrs: Record<string, any> = row.log_attributes ?? {}
4242

43+
const host = attrs['request.host'] ?? attrs['host'] ?? ''
4344
// Path key differs across sources: edge_logs uses `request.path`,
4445
// function_edge_logs uses `request.pathname`. Coalesce.
45-
const requestPath = attrs['request.path'] ?? attrs['request.pathname']
46+
const requestPath = attrs['request.path'] ?? attrs['request.pathname'] ?? attrs['path'] ?? ''
4647
// Status: HTTP response code for gateway rows, Postgres SQL state code for postgres rows.
4748
const status =
4849
row.source === 'postgres_logs' ? attrs['parsed.sql_state_code'] : attrs['response.status_code']
@@ -70,9 +71,9 @@ export function flattenOtelInspectionRow(
7071
level,
7172

7273
// Network -- flat aliases the panel reads as `enrichedData.request_path` etc.
74+
host,
7375
method: attrs['request.method'] ?? '',
7476
path: requestPath ?? '',
75-
host: attrs['request.host'] ?? '',
7677
status_code: status != null ? String(status) : '',
7778
request_path: requestPath ?? null,
7879
request_host: attrs['request.host'] ?? null,

0 commit comments

Comments
 (0)