Files
supabase/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.constants.tsx
Saxon FletcherandClaude Opus 5.5 7eb1e625de feat(studio): merge edge function Invocations into a scoped Logs tab
With the unified logs preview on, an edge function's Logs tab renders
the unified logs view scoped to that function: its invocations and
runtime output in one list.

- UnifiedLogs takes a `scope` prop. A scoped view drops the filter
  sidebar and the user filter, and only offers the date, log type,
  level and message filters
- The Invocations tab and its shortcut are hidden, and old Invocations
  links redirect to Logs with their time range and selected log
- getEdgeFunctionLogsUrl builds links into the scoped tab; invocation
  chart clicks use it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:59:53 +10:00

410 lines
14 KiB
TypeScript

import {
createParser,
parseAsArrayOf,
parseAsBoolean,
parseAsInteger,
parseAsString,
parseAsStringLiteral,
parseAsTimestamp,
} from 'nuqs'
import {
RANGE_DELIMITER,
SLIDER_DELIMITER,
SORT_DELIMITER,
} from '@/components/ui/DataTable/DataTable.constants'
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_LABELS = {
edge: 'API Gateway',
postgres: 'Postgres',
postgrest: 'PostgREST',
auth: 'Auth',
storage: 'Storage',
'edge function': 'Edge Function',
'edge function runtime': 'Edge Function runtime',
realtime: 'Realtime',
supavisor: 'Supavisor',
pgbouncer: 'PgBouncer',
multigres: 'Multigres',
compute: 'Compute',
}
type LogType = keyof typeof LOG_TYPES_LABELS
export const LOG_TYPES = Object.keys(LOG_TYPES_LABELS) as [LogType, ...LogType[]]
export const DEFAULT_LOG_TYPES = ['postgres', 'edge'] as const
// An edge function's invocations plus the runtime output (console, boot, shutdown) they produce.
// These are the only log types a function-scoped view queries or offers as filters.
export const EDGE_FUNCTION_LOG_TYPES = [
'edge function',
'edge function runtime',
] as const satisfies readonly LogType[]
// Filters a function-scoped view offers: the time range, message search and severity its old
// Invocations and Logs tabs had, plus log type to tell invocations and runtime output apart.
export const EDGE_FUNCTION_FILTER_FIELDS = ['date', 'log_type', 'level', 'event_message'] as const
export const LOG_TYPE_TO_SOURCE: Record<Exclude<LogType, 'compute'>, string> = {
edge: 'edge_logs',
postgrest: 'postgrest_logs',
storage: 'storage_logs',
postgres: 'postgres_logs',
'edge function': 'function_edge_logs',
'edge function runtime': 'function_logs',
auth: 'auth_logs',
realtime: 'realtime_logs',
supavisor: 'supavisor_logs',
pgbouncer: 'pgbouncer_logs',
multigres: 'multigres_logs',
}
const parseAsSort = createParser({
parse(queryValue: string) {
const [id, desc] = queryValue.split(SORT_DELIMITER)
if (!id && !desc) return null
return { id, desc: desc === 'desc' }
},
serialize(value: { id: string; desc: boolean }) {
return `${value.id}.${value.desc ? 'desc' : 'asc'}`
},
})
export const SEARCH_PARAMS_PARSER = {
// Equality filters. Repeatable `?filter=column:opAbbrev:value` (e.g. `level:eq:info`,
// `host:neq:foo`). Parsed with the helpers in `UnifiedLogs.filters.ts`.
filter: parseAsArrayOf(parseAsString),
// Range/special filters keep their dedicated keys — their semantics are inherently
// multi-value (sliders, time ranges) and don't fit the eq/neq model.
latency: parseAsArrayOf(parseAsInteger, SLIDER_DELIMITER),
'timing.dns': parseAsArrayOf(parseAsInteger, SLIDER_DELIMITER),
'timing.connection': parseAsArrayOf(parseAsInteger, SLIDER_DELIMITER),
'timing.tls': parseAsArrayOf(parseAsInteger, SLIDER_DELIMITER),
'timing.ttfb': parseAsArrayOf(parseAsInteger, SLIDER_DELIMITER),
'timing.transfer': parseAsArrayOf(parseAsInteger, SLIDER_DELIMITER),
date: parseAsArrayOf(parseAsTimestamp, RANGE_DELIMITER),
// REQUIRED FOR SORTING & PAGINATION
sort: parseAsSort,
size: parseAsInteger.withDefault(40),
start: parseAsInteger.withDefault(0),
// REQUIRED FOR INFINITE SCROLLING (Live Mode and Load More)
direction: parseAsStringLiteral(['prev', 'next']).withDefault('next'),
cursor: parseAsTimestamp.withDefault(new Date()),
live: parseAsBoolean.withDefault(false),
uuid: parseAsString,
id: parseAsString,
// View options
show_connection_logs: parseAsBoolean.withDefault(true),
edge_auth: parseAsBoolean.withDefault(true),
edge_storage: parseAsBoolean.withDefault(true),
edge_postgrest: parseAsBoolean.withDefault(true),
// Support searching for user against user ID
// See userAttributionCondition in UnifiedLogs.queries.ts.
user: parseAsString,
}
const POSTGRES_STATUS_CODE_LABELS = {
'00000': 'Successful Completion',
'01000': 'Warning',
'0100C': 'Dynamic Result Sets Returned',
'01008': 'Implicit Zero Bit Padding',
'01003': 'Null Value Eliminated In Set Function',
'01007': 'Privilege Not Granted',
'01006': 'Privilege Not Revoked',
'01004': 'String Data Right Truncation',
'01P01': 'Deprecated Feature',
'02000': 'No Data',
'02001': 'No Additional Dynamic Result Sets Returned',
'03000': 'SQL Statement Not Yet Complete',
'08000': 'Connection Exception',
'08003': 'Connection Does Not Exist',
'08006': 'Connection Failure',
'08001': 'SQL Client Unable To Establish SQL Connection',
'08004': 'SQL Server Rejected Establishment Of SQL Connection',
'08007': 'Transaction Resolution Unknown',
'08P01': 'Protocol Violation',
'09000': 'Triggered Action Exception',
'0A000': 'Feature Not Supported',
'0B000': 'Invalid Transaction Initiation',
'0F000': 'Locator Exception',
'0F001': 'Invalid Locator Specification',
'0L000': 'Invalid Grantor',
'0LP01': 'Invalid Grant Operation',
'0P000': 'Invalid Role Specification',
'0Z000': 'Diagnostics Exception',
'0Z002': 'Stacked Diagnostics Accessed Without Active Handler',
'20000': 'Case Not Found',
'21000': 'Cardinality Violation',
'22000': 'Data Exception',
'2202E': 'Array Subscript Error',
'22021': 'Character Not In Repertoire',
'22008': 'Datetime Field Overflow',
'22012': 'Division By Zero',
'22005': 'Error In Assignment',
'2200B': 'Escape Character Conflict',
'22022': 'Indicator Overflow',
'22015': 'Interval Field Overflow',
'2201E': 'Invalid Argument For Logarithm',
'22014': 'Invalid Argument For Ntile Function',
'22016': 'Invalid Argument For Nth Value Function',
'2201F': 'Invalid Argument For Power Function',
'2201G': 'Invalid Argument For Width Bucket Function',
'22018': 'Invalid Character Value For Cast',
'22007': 'Invalid Datetime Format',
'22019': 'Invalid Escape Character',
'2200D': 'Invalid Escape Octet',
'22025': 'Invalid Escape Sequence',
'22P06': 'Nonstandard Use Of Escape Character',
'22010': 'Invalid Indicator Parameter Value',
'22023': 'Invalid Parameter Value',
'2201B': 'Invalid Regular Expression',
'2201W': 'Invalid Row Count In Limit Clause',
'2201X': 'Invalid Row Count In Result Offset Clause',
'22009': 'Invalid Time Zone Displacement Value',
'2200C': 'Invalid Use Of Escape Character',
'2200G': 'Most Specific Type Mismatch',
'22004': 'Null Value Not Allowed',
'22002': 'Null Value No Indicator Parameter',
'22003': 'Numeric Value Out Of Range',
'22026': 'String Data Length Mismatch',
'22001': 'String Data Right Truncation',
'22011': 'Substring Error',
'22027': 'Trim Error',
'22024': 'Unterminated C String',
'2200F': 'Zero Length Character String',
'22P01': 'Floating Point Exception',
'22P02': 'Invalid Text Representation',
'22P03': 'Invalid Binary Representation',
'22P04': 'Bad Copy File Format',
'22P05': 'Untranslatable Character',
'2200L': 'Not An XML Document',
'2200M': 'Invalid XML Document',
'2200N': 'Invalid XML Content',
'2200S': 'Invalid XML Comment',
'2200T': 'Invalid XML Processing Instruction',
'23000': 'Integrity Constraint Violation',
'23001': 'Restrict Violation',
'23502': 'Not Null Violation',
'23503': 'Foreign Key Violation',
'23505': 'Unique Violation',
'23514': 'Check Violation',
'23P01': 'Exclusion Violation',
'24000': 'Invalid Cursor State',
'25000': 'Invalid Transaction State',
'25001': 'Active SQL Transaction',
'25002': 'Branch Transaction Already Active',
'25008': 'Held Cursor Requires Same Isolation Level',
'25003': 'Inappropriate Access Mode For Branch Transaction',
'25004': 'Inappropriate Isolation Level For Branch Transaction',
'25005': 'No Active SQL Transaction For Branch Transaction',
'25006': 'Read Only SQL Transaction',
'25007': 'Schema And Data Statement Mixing Not Supported',
'25P01': 'No Active SQL Transaction',
'25P02': 'In Failed SQL Transaction',
'25P03': 'Idle In Transaction Session Timeout',
'26000': 'Invalid SQL Statement Name',
'27000': 'Triggered Data Change Violation',
'28000': 'Invalid Authorization Specification',
'28P01': 'Invalid Password',
'2B000': 'Dependent Privilege Descriptors Still Exist',
'2BP01': 'Dependent Objects Still Exist',
'2D000': 'Invalid Transaction Termination',
'2F000': 'SQL Routine Exception',
'2F005': 'Function Executed No Return Statement',
'2F002': 'Modifying SQL Data Not Permitted',
'2F003': 'Prohibited SQL Statement Attempted',
'2F004': 'Reading SQL Data Not Permitted',
'34000': 'Invalid Cursor Name',
'38000': 'External Routine Exception',
'38001': 'Containing SQL Not Permitted',
'38002': 'Modifying SQL Data Not Permitted',
'38003': 'Prohibited SQL Statement Attempted',
'38004': 'Reading SQL Data Not Permitted',
'39000': 'External Routine Invocation Exception',
'39001': 'Invalid SQLSTATE Returned',
'39004': 'Null Value Not Allowed',
'39P01': 'Trigger Protocol Violated',
'39P02': 'SRF Protocol Violated',
'39P03': 'Event Trigger Protocol Violated',
'3B000': 'Savepoint Exception',
'3B001': 'Invalid Savepoint Specification',
'3D000': 'Invalid Catalog Name',
'3F000': 'Invalid Schema Name',
'40000': 'Transaction Rollback',
'40002': 'Transaction Integrity Constraint Violation',
'40001': 'Serialization Failure',
'40003': 'Statement Completion Unknown',
'40P01': 'Deadlock Detected',
'42000': 'Syntax Error Or Access Rule Violation',
'42601': 'Syntax Error',
'42501': 'Insufficient Privilege',
'42846': 'Cannot Coerce',
'42803': 'Grouping Error',
'42P20': 'Windowing Error',
'42P19': 'Invalid Recursion',
'42830': 'Invalid Foreign Key',
'42602': 'Invalid Name',
'42622': 'Name Too Long',
'42939': 'Reserved Name',
'42804': 'Datatype Mismatch',
'42P18': 'Indeterminate Datatype',
'42809': 'Wrong Object Type',
'428C9': 'Generated Always',
'42703': 'Undefined Column',
'42883': 'Undefined Function',
'42P01': 'Undefined Table',
'42P02': 'Undefined Parameter',
'42704': 'Undefined Object',
'42701': 'Duplicate Column',
'42P03': 'Duplicate Cursor',
'42P04': 'Duplicate Database',
'42723': 'Duplicate Function',
'42P05': 'Duplicate Prepared Statement',
'42P06': 'Duplicate Schema',
'42P07': 'Duplicate Table',
'42712': 'Duplicate Alias',
'42710': 'Duplicate Object',
'42702': 'Ambiguous Column',
'42725': 'Ambiguous Function',
'42P08': 'Ambiguous Parameter',
'42P09': 'Ambiguous Alias',
'42P10': 'Invalid Column Reference',
'42611': 'Invalid Column Definition',
'42P11': 'Invalid Cursor Definition',
'42P12': 'Invalid Database Definition',
'42P13': 'Invalid Function Definition',
'42P14': 'Invalid Prepared Statement Definition',
'42P15': 'Invalid Schema Definition',
'42P16': 'Invalid Table Definition',
'42P17': 'Invalid Object Definition',
'44000': 'With Check Option Violation',
'53000': 'Insufficient Resources',
'53100': 'Disk Full',
'53200': 'Out Of Memory',
'53300': 'Too Many Connections',
'53400': 'Configuration Limit Exceeded',
'54000': 'Program Limit Exceeded',
'54001': 'Statement Too Complex',
'54011': 'Too Many Columns',
'54023': 'Too Many Arguments',
'55000': 'Object Not In Prerequisite State',
'55006': 'Object In Use',
'55P02': "Can't Change Runtime Param",
'55P03': 'Lock Not Available',
'55P04': 'Unsafe New Enum Value Usage',
'57000': 'Operator Intervention',
'57014': 'Query Canceled',
'57P01': 'Admin Shutdown',
'57P02': 'Crash Shutdown',
'57P03': 'Cannot Connect Now',
'57P04': 'Database Dropped',
'58000': 'System Error',
'58030': 'IO Error',
'58P01': 'Undefined File',
'58P02': 'Duplicate File',
F0000: 'Config File Error',
F0001: 'Lock File Exists',
HV000: 'FDW Error',
HV005: 'FDW Column Name Not Found',
HV002: 'FDW Dynamic Parameter Value Needed',
HV010: 'FDW Function Sequence Error',
HV021: 'FDW Inconsistent Data',
HV024: 'FDW Invalid Attribute Value',
HV007: 'FDW Invalid Column Name',
HV008: 'FDW Invalid Column Number',
HV004: 'FDW Invalid Data Type',
HV006: 'FDW Invalid Data Type Descriptors',
HV091: 'FDW Invalid Handle',
HV00B: 'FDW Invalid Option Index',
HV00C: 'FDW Invalid Option Name',
HV00D: 'FDW Invalid String Length Or Buffer Length',
HV090: 'FDW Invalid String Format',
HV00A: 'FDW Invalid Use Of Null Pointer',
HV009: 'FDW Too Many Handles',
HV014: 'FDW Out Of Memory',
HV001: 'FDW Unsupported Function',
P0000: 'PL/pgSQL Error',
P0001: 'Raise Exception',
P0002: 'No Data Found',
P0003: 'Too Many Rows',
P0004: 'Assert Failure',
XX000: 'Internal Error',
XX001: 'Data Corrupted',
XX002: 'Index Corrupted',
}
const HTTP_STATUS_CODE_LABELS = {
'100': 'Continue',
'101': 'Switching Protocols',
'102': 'Processing',
'103': 'Early Hints',
'200': 'OK',
'201': 'Created',
'202': 'Accepted',
'203': 'Non-Authoritative Information',
'204': 'No Content',
'205': 'Reset Content',
'206': 'Partial Content',
'207': 'Multi-Status',
'208': 'Already Reported',
'226': 'IM Used',
'300': 'Multiple Choices',
'301': 'Moved Permanently',
'302': 'Found',
'303': 'See Other',
'304': 'Not Modified',
'305': 'Use Proxy',
'307': 'Temporary Redirect',
'308': 'Permanent Redirect',
'400': 'Bad Request',
'401': 'Unauthorized',
'402': 'Payment Required',
'403': 'Forbidden',
'404': 'Not Found',
'405': 'Method Not Allowed',
'406': 'Not Acceptable',
'407': 'Proxy Authentication Required',
'408': 'Request Timeout',
'409': 'Conflict',
'410': 'Gone',
'411': 'Length Required',
'412': 'Precondition Failed',
'413': 'Payload Too Large',
'414': 'URI Too Long',
'415': 'Unsupported Media Type',
'416': 'Range Not Satisfiable',
'417': 'Expectation Failed',
'418': "I'm a teapot",
'421': 'Misdirected Request',
'422': 'Unprocessable Entity',
'423': 'Locked',
'424': 'Failed Dependency',
'425': 'Too Early',
'426': 'Upgrade Required',
'428': 'Precondition Required',
'429': 'Too Many Requests',
'431': 'Request Header Fields Too Large',
'451': 'Unavailable For Legal Reasons',
'500': 'Internal Server Error',
'501': 'Not Implemented',
'502': 'Bad Gateway',
'503': 'Service Unavailable',
'504': 'Gateway Timeout',
'505': 'HTTP Version Not Supported',
'506': 'Variant Also Negotiates',
'507': 'Insufficient Storage',
'508': 'Loop Detected',
'510': 'Not Extended',
'511': 'Network Authentication Required',
}
export const STATUS_CODE_LABELS = {
...HTTP_STATUS_CODE_LABELS,
...POSTGRES_STATUS_CODE_LABELS,
}