/** * Service Flow SQL Queries * * This file contains SQL queries for fetching enriched service flow data * showing how requests flow through different layers of the infrastructure. */ // Service configuration for different log types const SERVICE_CONFIGS = { postgrest: { pathFilter: '%/rest/%', }, auth: { pathFilter: '%/auth/%', }, 'edge-function': { pathFilter: '%/functions/%', }, storage: { pathFilter: '%/storage/%', }, } as const type EdgeServiceType = keyof typeof SERVICE_CONFIGS /** * Base Edge Logs Service Flow Query * Consolidated query for all edge-based services (postgrest, auth, edge-function, storage) * to eliminate 500+ lines of SQL duplication */ const getBaseEdgeServiceFlowQuery = (logId: string, serviceType: EdgeServiceType): string => { return ` select id, el.timestamp as timestamp, '${serviceType}' as log_type, CAST(edge_logs_response.status_code AS STRING) as status, CASE WHEN edge_logs_response.status_code BETWEEN 200 AND 299 THEN 'success' WHEN edge_logs_response.status_code BETWEEN 400 AND 499 THEN 'warning' WHEN edge_logs_response.status_code >= 500 THEN 'error' ELSE 'success' END as level, -- Request data edge_logs_request.path as request_path, edge_logs_request.host as request_host, edge_logs_request.method as request_method, edge_logs_request.url as request_url, edge_logs_request.search as request_search, -- Response data edge_logs_response.origin_time as response_origin_time, edge_logs_response_headers.content_type as response_content_type, edge_logs_response_headers.cf_cache_status as response_cache_status, -- Client location data edge_logs_cf.continent as client_continent, edge_logs_cf.country as client_country, edge_logs_cf.city as client_city, edge_logs_cf.region as client_region, edge_logs_cf.regionCode as client_region_code, edge_logs_cf.latitude as client_latitude, edge_logs_cf.longitude as client_longitude, edge_logs_cf.timezone as client_timezone, -- Network data edge_logs_cf.httpProtocol as network_protocol, edge_logs_cf.colo as network_datacenter, -- Request headers edge_logs_request_headers.user_agent as headers_user_agent, edge_logs_request_headers.x_client_info as headers_x_client_info, edge_logs_request_headers.x_forwarded_proto as headers_x_forwarded_proto, edge_logs_request_headers.x_real_ip as headers_x_real_ip, edge_logs_request_headers.referer as headers_referer, -- Auth data authorization_payload.role as api_role, COALESCE(sb.auth_user, null) as auth_user, -- JWT Key Authentication (old keys) CASE WHEN apikey_payload.algorithm = 'HS256' AND apikey_payload.issuer = 'supabase' AND apikey_payload.role IN ('anon', 'service_role') THEN apikey_payload.role WHEN apikey_payload IS NOT NULL THEN '' ELSE NULL END as jwt_key_role, apikey_payload.signature_prefix as jwt_key_prefix, -- API Key Authentication (new keys from sb.apikey[0].apikey[0]) CASE WHEN sb_apikey_inner.prefix LIKE '%publishable%' THEN 'anon' WHEN sb_apikey_inner.prefix LIKE '%secret%' THEN 'service_role' WHEN sb_apikey_inner.prefix IS NOT NULL THEN 'unknown' ELSE NULL END as api_key_role, sb_apikey_inner.prefix as api_key_prefix, sb_apikey_inner.error as api_key_error, sb_apikey_inner.hash as api_key_hash, -- User Authorization authorization_payload.role as authorization_role, null as user_id, null as user_email, -- Cloudflare Network Info edge_logs_response_headers.cf_ray as cf_ray, edge_logs_request_headers.cf_ipcountry as cf_country, edge_logs_cf.colo as cf_datacenter, edge_logs_request_headers.cf_connecting_ip as client_ip, -- JWT data apikey_payload.role as jwt_apikey_role, apikey_payload.algorithm as jwt_apikey_algorithm, apikey_payload.expires_at as jwt_apikey_expires_at, apikey_payload.issuer as jwt_apikey_issuer, apikey_payload.signature_prefix as jwt_apikey_signature_prefix, null as jwt_apikey_key_id, null as jwt_apikey_session_id, apikey_payload.subject as jwt_apikey_subject, authorization_payload.role as jwt_auth_role, authorization_payload.algorithm as jwt_auth_algorithm, authorization_payload.expires_at as jwt_auth_expires_at, authorization_payload.issuer as jwt_auth_issuer, authorization_payload.signature_prefix as jwt_auth_signature_prefix, authorization_payload.key_id as jwt_auth_key_id, authorization_payload.session_id as jwt_auth_session_id, authorization_payload.subject as jwt_auth_subject, -- Storage specific data (included for all but only populated for storage) edge_logs_response_headers.sb_gateway_mode as storage_edge_gateway_mode, edge_logs_response_headers.sb_gateway_version as storage_edge_gateway_version, edge_logs_response_headers.cf_ray as correlation_cf_ray, -- Raw data el as raw_log_data from edge_logs as el cross join unnest(metadata) as edge_logs_metadata cross join unnest(edge_logs_metadata.request) as edge_logs_request cross join unnest(edge_logs_metadata.response) as edge_logs_response left join unnest(edge_logs_response.headers) as edge_logs_response_headers left join unnest(edge_logs_request.headers) as edge_logs_request_headers left join unnest(edge_logs_request.cf) as edge_logs_cf left join unnest(edge_logs_request.sb) as sb left join unnest(sb.jwt) as jwt left join unnest(COALESCE(jwt.apikey, [])) as apikey left join unnest(COALESCE(apikey.payload, [])) as apikey_payload left join unnest(COALESCE(jwt.authorization, [])) as auth left join unnest(COALESCE(auth.payload, [])) as authorization_payload left join unnest(COALESCE(sb.apikey, [])) as sb_apikey_outer left join unnest(COALESCE(sb_apikey_outer.apikey, [])) as sb_apikey_inner WHERE el.id = '${logId}' ` } /** * PostgREST Service Flow Query for /rest/ requests * Fetches enriched edge log data for PostgREST requests with additional service-specific metadata */ export const getPostgrestServiceFlowQuery = (logId: string): string => { return getBaseEdgeServiceFlowQuery(logId, 'postgrest') } /** * Auth Service Flow Query for /auth/ requests * Fetches enriched edge log data for GoTrue auth requests with service-specific metadata */ export const getAuthServiceFlowQuery = (logId: string): string => { return getBaseEdgeServiceFlowQuery(logId, 'auth') } /** * Edge Function Service Flow Query for /functions/ requests * Fetches enriched edge log data for Edge Function requests with service-specific metadata * NOTE: Uses function_edge_logs table instead of edge_logs, so kept separate like postgres */ export const getEdgeFunctionServiceFlowQuery = (logId: string): string => { return ` select fel.id as id, fel.timestamp as timestamp, 'edge-function' as log_type, CAST(fel_response.status_code AS STRING) as status, CASE WHEN fel_response.status_code BETWEEN 200 AND 299 THEN 'success' WHEN fel_response.status_code BETWEEN 400 AND 499 THEN 'warning' WHEN fel_response.status_code >= 500 THEN 'error' ELSE 'success' END as level, -- Request data fel_request.pathname as request_path, fel_request.host as request_host, fel_request.method as request_method, fel_request.url as request_url, fel_request.search as request_search, fel_request.protocol as request_protocol, fel_request.port as request_port, -- Response data (no origin_time in function_edge_logs) fel_response_headers.content_type as response_content_type, fel_response_headers.content_length as response_content_length, fel_response_headers.date as response_date, fel_response_headers.server as response_server, fel_response_headers.x_sb_edge_region as response_edge_region, fel_response_headers.x_sb_compute_multiplier as response_compute_multiplier, fel_response_headers.x_sb_resource_multiplier as response_resource_multiplier, fel_response_headers.x_served_by as response_served_by, -- Function specific data fel_metadata.execution_id as execution_id, fel_metadata.function_id as function_id, fel_metadata.deployment_id as deployment_id, fel_metadata.execution_time_ms as execution_time_ms, fel_metadata.project_ref as project_ref, fel_metadata.version as function_version, -- Request headers fel_request_headers.user_agent as headers_user_agent, fel_request_headers.x_client_info as headers_x_client_info, fel_request_headers.accept as headers_accept, fel_request_headers.accept_encoding as headers_accept_encoding, fel_request_headers.connection as headers_connection, fel_request_headers.cookie as headers_cookie, fel_request_headers.host as headers_host, -- Auth data authorization_payload.role as api_role, COALESCE(sb.auth_user, null) as auth_user, -- JWT Key Authentication (old keys) CASE WHEN apikey_payload.algorithm = 'HS256' AND apikey_payload.issuer = 'supabase' AND apikey_payload.role IN ('anon', 'service_role') THEN apikey_payload.role WHEN apikey_payload IS NOT NULL THEN '' ELSE NULL END as jwt_key_role, apikey_payload.signature_prefix as jwt_key_prefix, -- API Key Authentication (new keys from sb.apikey[0].apikey[0]) CASE WHEN sb_apikey_inner.prefix LIKE '%publishable%' THEN 'anon' WHEN sb_apikey_inner.prefix LIKE '%secret%' THEN 'service_role' WHEN sb_apikey_inner.prefix IS NOT NULL THEN 'unknown' ELSE NULL END as api_key_role, sb_apikey_inner.prefix as api_key_prefix, sb_apikey_inner.error as api_key_error, sb_apikey_inner.hash as api_key_hash, -- User Authorization authorization_payload.role as authorization_role, null as user_id, null as user_email, -- JWT data apikey_payload.role as jwt_apikey_role, apikey_payload.algorithm as jwt_apikey_algorithm, apikey_payload.expires_at as jwt_apikey_expires_at, apikey_payload.issuer as jwt_apikey_issuer, apikey_payload.signature_prefix as jwt_apikey_signature_prefix, null as jwt_apikey_key_id, null as jwt_apikey_session_id, apikey_payload.subject as jwt_apikey_subject, authorization_payload.role as jwt_auth_role, authorization_payload.algorithm as jwt_auth_algorithm, authorization_payload.expires_at as jwt_auth_expires_at, authorization_payload.issuer as jwt_auth_issuer, authorization_payload.signature_prefix as jwt_auth_signature_prefix, authorization_payload.key_id as jwt_auth_key_id, authorization_payload.session_id as jwt_auth_session_id, authorization_payload.subject as jwt_auth_subject, -- Function logs aggregation function_logs_agg.function_log_count as function_log_count, function_logs_agg.logs as function_logs, function_logs_agg.last_event_message as last_event_message, -- Raw data fel as raw_log_data from function_edge_logs as fel cross join unnest(metadata) as fel_metadata cross join unnest(fel_metadata.response) as fel_response cross join unnest(fel_metadata.request) as fel_request left join unnest(fel_response.headers) as fel_response_headers left join unnest(fel_request.headers) as fel_request_headers left join unnest(fel_request.sb) as sb left join unnest(sb.jwt) as jwt left join unnest(COALESCE(jwt.apikey, [])) as apikey left join unnest(COALESCE(apikey.payload, [])) as apikey_payload left join unnest(COALESCE(jwt.authorization, [])) as auth left join unnest(COALESCE(auth.payload, [])) as authorization_payload left join unnest(COALESCE(sb.apikey, [])) as sb_apikey_outer left join unnest(COALESCE(sb_apikey_outer.apikey, [])) as sb_apikey_inner left join ( SELECT fl_metadata.execution_id, COUNT(fl.id) as function_log_count, ANY_VALUE(fl.event_message) as last_event_message, ARRAY_AGG(STRUCT(fl.id, fl.timestamp, fl.event_message, fl_metadata.level, fl_metadata.event_type)) as logs FROM function_logs as fl CROSS JOIN UNNEST(fl.metadata) as fl_metadata WHERE fl_metadata.execution_id IS NOT NULL GROUP BY fl_metadata.execution_id ) as function_logs_agg on fel_metadata.execution_id = function_logs_agg.execution_id WHERE fel.id = '${logId}' ` } /** * Storage Service Flow Query for /storage/ requests * Fetches enriched edge log data for Storage requests with service-specific metadata */ export const getStorageServiceFlowQuery = (logId: string): string => { return getBaseEdgeServiceFlowQuery(logId, 'storage') } /** * Postgres Service Flow Query for database operations * Fetches enriched postgres log data with database-specific metadata * * This handles direct database operations, connections, and queries * NOTE: Uses postgres_logs table instead of edge_logs, so kept separate */ export const getPostgresServiceFlowQuery = (logId: string): string => { return ` select pgl.id as id, pgl.timestamp as timestamp, 'postgres' as log_type, pgl_parsed.sql_state_code as status, CASE WHEN pgl_parsed.error_severity = 'LOG' THEN 'success' WHEN pgl_parsed.error_severity = 'WARNING' THEN 'warning' WHEN pgl_parsed.error_severity = 'FATAL' THEN 'error' WHEN pgl_parsed.error_severity = 'ERROR' THEN 'error' ELSE 'success' END as level, -- Database connection details pgl_parsed.database_name as database_name, pgl_parsed.user_name as database_user, pgl_parsed.connection_from as connection_from, pgl_metadata.host as database_host, -- Query/Operation details pgl_parsed.command_tag as command_tag, pgl_parsed.backend_type as backend_type, pgl_parsed.query_id as query_id, -- Session details pgl_parsed.session_id as session_id, pgl_parsed.process_id as process_id, pgl_parsed.virtual_transaction_id as virtual_transaction_id, pgl_parsed.transaction_id as transaction_id, pgl_parsed.session_start_time as session_start_time, pgl_parsed.session_line_num as session_line_num, -- Error/Status details pgl_parsed.error_severity as error_severity, pgl_parsed.sql_state_code as sql_state_code, pgl.event_message as event_message, -- Timing pgl_parsed.timestamp as operation_timestamp, -- Raw data pgl as raw_log_data from postgres_logs as pgl cross join unnest(pgl.metadata) as pgl_metadata cross join unnest(pgl_metadata.parsed) as pgl_parsed WHERE pgl.id = '${logId}' ` }