| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- import { type Table as TTable } from '@tanstack/react-table'
- import { cn } from 'ui'
- import { FacetMetadataSchema } from './UnifiedLogs.schema'
- import { LEVELS } from '@/components/ui/DataTable/DataTable.constants'
- export const logEventBus = {
- listeners: new Map<string, Set<(rowId: string) => void>>(),
- on(event: 'selectTraceTab', callback: (rowId: string) => void) {
- if (!this.listeners.has(event)) {
- this.listeners.set(event, new Set())
- }
- this.listeners.get(event)?.add(callback)
- return () => this.listeners.get(event)?.delete(callback)
- },
- emit(event: 'selectTraceTab', rowId: string) {
- this.listeners.get(event)?.forEach((callback) => callback(rowId))
- },
- }
- export const getFacetedUniqueValues = <TData>(facets?: Record<string, FacetMetadataSchema>) => {
- return (_table: TTable<TData>, columnId: string) => {
- return new Map(facets?.[columnId]?.rows?.map(({ value, total }) => [value, total]) || [])
- }
- }
- export const getFacetedMinMaxValues = <TData>(facets?: Record<string, FacetMetadataSchema>) => {
- return (_table: TTable<TData>, columnId: string) => {
- const min = facets?.[columnId]?.min
- const max = facets?.[columnId]?.max
- if (typeof min === 'number' && typeof max === 'number') return [min, max]
- if (typeof min === 'number') return [min, min]
- if (typeof max === 'number') return [max, max]
- return undefined
- }
- }
- /**
- * Returns a unified-logs row's timestamp in epoch milliseconds.
- *
- * The row mapper attaches a pre-parsed `date` (works for both BigQuery
- * microsecond timestamps and OTEL ISO strings); fall back to the raw
- * `timestamp` value when it's a number (older BQ-style microseconds).
- */
- export function getRowTimestampMs(
- row: { date?: Date | null; timestamp?: number | string | null } | null | undefined
- ): number | null {
- if (row?.date instanceof Date) return row.date.getTime()
- if (typeof row?.timestamp === 'number') return row.timestamp / 1000
- return null
- }
- export const getLevelLabel = (value: (typeof LEVELS)[number]): string => {
- switch (value) {
- case 'success':
- return '2xx'
- case 'warning':
- return '4xx'
- case 'error':
- return '5xx'
- }
- }
- // Helper function to determine level from HTTP status code
- export const getStatusLevel = (status?: number | string): string => {
- if (!status) return 'success'
- const statusNum = Number(status)
- if (statusNum >= 500) return 'error'
- if (statusNum >= 400) return 'warning'
- if (statusNum >= 300) return 'info' // 3xx redirects are informational
- if (statusNum >= 200) return 'success'
- if (statusNum >= 100) return 'info'
- return 'success'
- }
- export function getLevelRowClassName(value: (typeof LEVELS)[number]): string {
- switch (value) {
- case 'success':
- return ''
- case 'warning':
- return cn(
- 'bg-warning/5 hover:bg-warning/10',
- 'data-[state=selected]:bg-warning/20 focus-visible:bg-warning/10',
- 'dark:bg-warning/10 dark:hover:bg-warning/20 dark:data-[state=selected]:bg-warning/30 dark:focus-visible:bg-warning/20'
- )
- case 'error':
- return cn(
- 'bg-destructive/5 hover:bg-destructive/10',
- 'data-[state=selected]:bg-destructive/20 focus-visible:bg-destructive/10',
- 'dark:bg-error/10 dark:hover:bg-destructive/20 dark:data-[state=selected]:bg-destructive/30 dark:focus-visible:bg-destructive/20'
- )
- default:
- return ''
- }
- }
- /**
- * Formats service type strings for display purposes
- * Handles special cases like "edge function" -> "Edge Function"
- * and applies proper capitalization to other service types
- */
- export function formatServiceTypeForDisplay(serviceType: string): string {
- if (!serviceType) return ''
- // Handle special cases
- const specialCases: Record<string, string> = {
- 'edge function': 'Edge Function',
- postgrest: 'PostgREST',
- postgres: 'Postgres',
- auth: 'Auth',
- storage: 'Storage',
- }
- return specialCases[serviceType.toLowerCase()] || serviceType
- }
- /**
- * Parses an auth log event_message that may be a stringified JSON object.
- * Auth log entries store metadata as JSON in event_message (e.g. {"msg":"...","level":"info"}).
- * Extracts the human-readable msg field, falling back to error, then the raw string.
- * The fallback ensures self-hosted versions with different formats still render correctly.
- */
- export function parseAuthLogEventMessage(value: string | undefined): string | undefined {
- if (!value) return value
- try {
- const parsed = JSON.parse(value)
- if (parsed && typeof parsed === 'object') {
- const msg = parsed.msg
- const err = parsed.error
- if (typeof msg === 'string' && msg.trim()) return msg
- if (typeof err === 'string' && err.trim()) return err
- }
- return value
- } catch {
- return value
- }
- }
|