import { COMPUTE_DISK, COMPUTE_MAX_IOPS } from 'shared-data' import { hasBurstableIO, mapComputeSizeNameToAddonVariantId, } from '@/components/interfaces/DiskManagement/DiskManagement.utils' import { compactNumberFormatter } from '@/components/ui/Charts/Charts.utils' import { ReportAttributes } from '@/components/ui/Charts/ComposedChart.utils' import { DiskAttributesData } from '@/data/config/disk-attributes-query' import { MaxConnectionsData } from '@/data/database/max-connections-query' import { Project } from '@/data/projects/project-detail-query' import { resolveHighAvailability } from '@/hooks/misc/useHighAvailability.constants' import { DOCS_URL } from '@/lib/constants' import { formatBytes, formatBytesMinMB } from '@/lib/helpers' // High Availability projects run on volumes without a burst credit pool, so the // Disk IO Burst Balance chart has no data to show for them. export const shouldShowDiskIOBurstBalanceChart = ( project: Project | undefined, isFlagEnabled: boolean ): boolean => isFlagEnabled && hasBurstableIO(project?.infra_compute_size) && !resolveHighAvailability(project) export const getReportAttributesV2: ( entitledFeatures: string[], project: Project, diskConfig?: DiskAttributesData, maxConnections?: MaxConnectionsData, pgBouncerMaxConnections?: number, isSpendCapEnabled?: boolean, showDiskIOBurstBalanceChart?: boolean, showMemoryCommitmentChart?: boolean ) => ReportAttributes[] = ( entitledFeatures, project, diskConfig, maxConnections, pgBouncerMaxConnections, isSpendCapEnabled, showDiskIOBurstBalanceChart, showMemoryCommitmentChart ) => { const computeVariantId = mapComputeSizeNameToAddonVariantId(project?.infra_compute_size) // High Availability projects run Multigres, whose dedicated pooler is multipooler rather // than PgBouncer. Multipooler docs aren't published yet, so the docs link is dropped for now. const isHighAvailability = resolveHighAvailability(project) const provisionedDiskIops = diskConfig?.attributes?.iops const computeIopsLimit = COMPUTE_MAX_IOPS[computeVariantId] const effectiveMaxIops = typeof provisionedDiskIops === 'number' && typeof computeIopsLimit === 'number' ? Math.min(provisionedDiskIops, computeIopsLimit) : provisionedDiskIops const showBurstBalanceChart = shouldShowDiskIOBurstBalanceChart( project, !!showDiskIOBurstBalanceChart ) const baselineThroughputMBps = COMPUTE_DISK[computeVariantId]?.baselineThroughputMBps const baselineThroughputLabel = typeof baselineThroughputMBps === 'number' ? `${baselineThroughputMBps} MB/s` : 'its baseline' return [ { id: 'ram-usage', label: 'Memory usage', docsUrl: `${DOCS_URL}/guides/telemetry/reports#memory-usage`, hide: false, showTooltip: true, showLegend: true, hideChartType: false, defaultChartStyle: 'bar', showMaxValue: false, showGrid: true, syncId: 'database-reports', valuePrecision: 2, YAxisProps: { width: 75, tickFormatter: (value: number) => formatBytesMinMB(value, 2), }, attributes: [ { attribute: 'ram_usage_used', provider: 'infra-monitoring', label: 'Used', color: 'var(--chart-1)', fill: 'var(--chart-1-fill)', tooltip: 'RAM in use by Postgres and the operating system. Sustained high usage may indicate memory pressure', }, { attribute: 'ram_usage_cache_and_buffers', provider: 'infra-monitoring', label: 'Cache + Buffers', color: 'var(--chart-2)', fill: 'var(--chart-2-fill)', tooltip: 'RAM used by the operating system page cache and PostgreSQL buffers to accelerate disk reads/writes', }, { attribute: 'ram_usage_free', provider: 'infra-monitoring', label: 'Free', color: 'var(--chart-muted)', fill: 'var(--chart-muted-fill)', tooltip: 'Unallocated memory available for use. A small portion is always reserved by the operating system', }, { attribute: 'ram_usage_total', provider: 'infra-monitoring', label: 'Total RAM', isMaxValue: true, omitFromTotal: true, tooltip: 'Total RAM available on this instance', }, { attribute: 'ram_usage_swap', provider: 'infra-monitoring', label: 'Swap', omitFromTotal: true, color: 'var(--chart-3)', tooltip: 'Swap space in use by the operating system. Sustained swap usage indicates memory pressure and may degrade database performance', }, ], }, { id: 'memory-commitment', label: 'Memory commitment', docsUrl: `${DOCS_URL}/guides/telemetry/reports#memory-commitment`, hide: !showMemoryCommitmentChart, showTooltip: true, showLegend: true, hideChartType: false, defaultChartStyle: 'bar', showMaxValue: true, showGrid: true, syncId: 'database-reports', valuePrecision: 2, YAxisProps: { width: 75, tickFormatter: (value: number) => formatBytesMinMB(value, 2), }, attributes: [ { attribute: 'ram_commit_used', provider: 'infra-monitoring', label: 'Committed', color: 'var(--chart-1)', fill: 'var(--chart-1-fill)', tooltip: 'Total memory the kernel has promised to processes (RAM plus swap). Sustained values near or above the commit limit indicate overcommitment and a high risk of out-of-memory failures', }, { attribute: 'ram_commit_limit', provider: 'infra-monitoring', label: 'Commit limit', color: 'var(--chart-reference)', isMaxValue: true, omitFromTotal: true, tooltip: 'Maximum memory the kernel will commit (RAM plus swap, adjusted by the overcommit ratio). Committed memory approaching this limit puts the database at risk of being killed when the system runs out of memory', }, ], }, { id: 'swap-usage', label: 'Swap usage', docsUrl: `${DOCS_URL}/guides/telemetry/reports#memory-usage`, hide: true, showTooltip: true, showLegend: false, hideChartType: false, defaultChartStyle: 'bar', showMaxValue: false, showGrid: true, syncId: 'database-reports', valuePrecision: 2, YAxisProps: { width: 75, tickFormatter: (value: number) => formatBytesMinMB(value, 2), // eslint-disable-next-line @typescript-eslint/no-explicit-any domain: [0, (dataMax: number) => Math.max(dataMax, 1024 * 1024 * 1024)] as any, }, attributes: [ { attribute: 'swap_usage', provider: 'infra-monitoring', label: 'Swap', tooltip: 'Swap space in use by the operating system. Sustained swap usage indicates memory pressure and may degrade database performance', }, ], }, { id: 'cpu-usage', label: 'CPU usage', docsUrl: `${DOCS_URL}/guides/telemetry/reports#cpu-usage`, syncId: 'database-reports', format: '%', valuePrecision: 2, hide: false, showTooltip: true, showLegend: true, showMaxValue: false, showGrid: true, YAxisProps: { width: 55, domain: [0, 100] as [number, number], allowDataOverflow: true, tickFormatter: (v: number) => `${Math.round(v)}%`, }, hideChartType: false, defaultChartStyle: 'bar', attributes: [ { attribute: 'cpu_usage_busy_system', provider: 'infra-monitoring', label: 'System', format: '%', color: 'var(--chart-2)', fill: 'var(--chart-2-fill)', tooltip: 'CPU time spent on kernel operations (e.g., process scheduling, memory management). High values may indicate system overhead', }, { attribute: 'cpu_usage_busy_user', provider: 'infra-monitoring', label: 'User', format: '%', color: 'var(--chart-1)', fill: 'var(--chart-1-fill)', tooltip: 'CPU time used by database queries and user-space processes. High values may suggest CPU-intensive queries', }, { attribute: 'cpu_usage_busy_iowait', provider: 'infra-monitoring', label: 'IOwait', format: '%', color: 'var(--chart-3)', fill: 'var(--chart-3-fill)', tooltip: 'CPU time waiting for disk or network I/O. High values may indicate disk bottlenecks', }, { attribute: 'cpu_usage_busy_irqs', provider: 'infra-monitoring', label: 'IRQs', format: '%', color: 'var(--chart-4)', fill: 'var(--chart-4-fill)', tooltip: 'CPU time handling hardware interrupt requests (IRQ)', }, { attribute: 'cpu_usage_busy_other', provider: 'infra-monitoring', label: 'Other', format: '%', color: 'var(--chart-5)', fill: 'var(--chart-5-fill)', tooltip: 'CPU time spent on other tasks (e.g., background processes, software interrupts)', }, { attribute: 'cpu_usage_busy_idle', provider: 'infra-monitoring', label: 'Idle', format: '%', omitFromTotal: true, color: 'var(--chart-muted)', fill: 'var(--chart-muted-fill)', tooltip: 'CPU time spent idle and available for new work', }, { attribute: 'cpu_usage_max', provider: 'reference-line', label: 'Max', value: 100, color: 'var(--chart-reference)', tooltip: 'Max CPU usage', isMaxValue: true, }, ], }, { id: 'network-throughput', label: 'Network throughput', syncId: 'database-reports', hide: false, showTooltip: true, format: 'bytes-per-second', valuePrecision: 1, showLegend: true, showMaxValue: false, hideChartType: false, showGrid: true, YAxisProps: { width: 70, tickFormatter: (value: number) => `${formatBytes(value, 1)}/s`, }, defaultChartStyle: 'stackedAreaLine', attributes: [ { attribute: 'network_receive_bytes', provider: 'infra-monitoring', label: 'Network in', color: 'var(--chart-in)', fill: 'var(--chart-in-fill)', tooltip: 'Inbound network throughput (bytes per second)', }, { attribute: 'network_transmit_bytes', provider: 'infra-monitoring', label: 'Network out', color: 'var(--chart-out)', fill: 'var(--chart-out-fill)', tooltip: 'Outbound network throughput (bytes per second)', }, ], }, { id: 'disk-iops', label: 'Disk Input/Output operations per second (IOPS)', docsUrl: `${DOCS_URL}/guides/telemetry/reports#disk-inputoutput-operations-per-second-iops`, syncId: 'database-reports', hide: false, showTooltip: true, valuePrecision: 0, showLegend: true, hideChartType: false, showGrid: true, showMaxValue: true, YAxisProps: { width: 55, tickFormatter: (value: number) => compactNumberFormatter(value), }, defaultChartStyle: 'bar', attributes: [ { attribute: 'disk_iops_write', provider: 'infra-monitoring', label: 'Write IOPS', color: 'var(--chart-out)', fill: 'var(--chart-out-fill)', tooltip: 'Number of write operations per second. High values indicate frequent data writes, logging, or transaction activity', }, { attribute: 'disk_iops_read', provider: 'infra-monitoring', label: 'Read IOPS', color: 'var(--chart-in)', fill: 'var(--chart-in-fill)', tooltip: 'Number of read operations per second. High values suggest frequent disk reads due to queries or poor caching', }, { attribute: 'disk_iops_max', provider: 'reference-line', label: 'Max IOPS', color: 'var(--chart-reference)', value: effectiveMaxIops, tooltip: 'Effective maximum IOPS for your current compute and disk configuration. Equal to the lower of the compute IOPS limit and the provisioned disk IOPS', isMaxValue: true, }, ], }, { id: 'disk-throughput', label: 'Disk throughput', docsUrl: `${DOCS_URL}/guides/platform/compute-add-ons#disk-throughput`, syncId: 'database-reports', hide: false, showTooltip: true, format: 'bytes-per-second', valuePrecision: 1, showLegend: true, showMaxValue: true, hideChartType: false, showGrid: true, YAxisProps: { width: 70, tickFormatter: (value: number) => `${formatBytes(value, 1)}/s`, }, defaultChartStyle: 'stackedAreaLine', attributes: [ { attribute: 'disk_bytes_read', provider: 'infra-monitoring', label: 'Read throughput', color: 'var(--chart-in)', fill: 'var(--chart-in-fill)', tooltip: 'Disk read throughput (bytes per second)', }, { attribute: 'disk_bytes_written', provider: 'infra-monitoring', label: 'Write throughput', color: 'var(--chart-out)', fill: 'var(--chart-out-fill)', tooltip: 'Disk write throughput (bytes per second)', }, { attribute: 'disk_throughput_max', provider: 'reference-line', label: 'Max throughput', color: 'var(--chart-reference)', value: diskConfig?.attributes?.type === 'gp3' && typeof diskConfig.attributes.throughput_mbps === 'number' ? diskConfig.attributes.throughput_mbps * 1024 * 1024 : undefined, tooltip: 'Maximum disk throughput for your current compute size', isMaxValue: true, }, ], }, { id: 'disk-io-burst-balance', label: 'Disk IO Burst Balance', titleTooltip: `The EBS burst credit pool your compute draws on to sustain IO above its baseline. When the balance hits 0%, sustained throughput returns to its baseline of ${baselineThroughputLabel} until it refills.`, docsUrl: `${DOCS_URL}/guides/platform/compute-add-ons#disk-throughput-and-iops`, syncId: 'database-reports', hide: !showBurstBalanceChart, format: '%', valuePrecision: 0, showTooltip: true, showLegend: false, showMaxValue: false, showGrid: true, YAxisProps: { width: 55, domain: [0, 100] as [number, number], allowDataOverflow: true, tickFormatter: (v: number) => `${Math.round(v)}%`, }, hideChartType: false, defaultChartStyle: 'bar', attributes: [ { attribute: 'disk_io_budget', provider: 'infra-monitoring', label: 'Burst credits remaining', format: '%', tooltip: `Percentage of EBS burst credits remaining. Drops only matter while the instance is bursting above its baseline IO. At 0%, sustained throughput returns to its baseline of ${baselineThroughputLabel} until it refills.`, }, ], }, { // Client Connections metric for free tier id: 'client-connections-basic', label: 'Database Connections', syncId: 'database-reports', valuePrecision: 0, hide: entitledFeatures.includes('database'), showTooltip: false, showLegend: false, showMaxValue: true, hideChartType: false, showGrid: true, YAxisProps: { width: 30 }, defaultChartStyle: 'bar', docsUrl: `${DOCS_URL}/guides/telemetry/reports#database-connections`, attributes: [ { attribute: 'pg_stat_database_num_backends', provider: 'infra-monitoring', label: 'Total connections', color: 'var(--chart-1)', fill: 'var(--chart-1-fill)', tooltip: 'Total number of active database connections', }, { attribute: 'max_db_connections', provider: 'reference-line', label: 'Max connections', color: 'var(--chart-reference)', value: maxConnections?.maxConnections, tooltip: 'Max available connections for your current compute size', isMaxValue: true, }, ], }, { // advanced client connections metric for paid and above id: 'client-connections', label: 'Database Connections', syncId: 'database-reports', valuePrecision: 0, entitlement: 'database', requiredPlan: 'Pro', hide: !entitledFeatures.includes('database'), showTooltip: true, showLegend: true, showMaxValue: true, hideChartType: false, showGrid: true, YAxisProps: { width: 30 }, defaultChartStyle: 'bar', docsUrl: `${DOCS_URL}/guides/telemetry/reports#database-connections`, attributes: [ { attribute: 'client_connections_postgres', provider: 'infra-monitoring', label: 'Postgres', color: 'var(--chart-1)', fill: 'var(--chart-1-fill)', tooltip: 'Direct connections to the Postgres database from your application and external clients', }, { attribute: 'client_connections_authenticator', provider: 'infra-monitoring', label: 'PostgREST', color: 'var(--chart-2)', fill: 'var(--chart-2-fill)', tooltip: 'Connection pool managed by PostgREST', }, { attribute: 'client_connections_supabase_admin', provider: 'infra-monitoring', label: 'Reserved', color: 'var(--chart-3)', fill: 'var(--chart-3-fill)', tooltip: 'Administrative connections used by various Supabase services for internal operations and maintenance tasks', }, { attribute: 'client_connections_supabase_auth_admin', provider: 'infra-monitoring', label: 'Auth', color: 'var(--chart-4)', fill: 'var(--chart-4-fill)', tooltip: 'Connection pool managed by Supabase Auth', }, { attribute: 'client_connections_supabase_storage_admin', provider: 'infra-monitoring', label: 'Storage', color: 'var(--chart-5)', fill: 'var(--chart-5-fill)', tooltip: 'Connection pool managed by Supabase Storage', }, { attribute: 'client_connections_other', provider: 'infra-monitoring', label: 'Other roles', color: 'var(--chart-6)', fill: 'var(--chart-6-fill)', tooltip: "Miscellaneous database connections that don't fall into other categories.", }, { attribute: 'max_db_connections', provider: 'reference-line', label: 'Max connections', color: 'var(--chart-reference)', value: maxConnections?.maxConnections, tooltip: 'Max available connections for your current compute size', isMaxValue: true, }, ], }, { id: 'pgbouncer-connections', label: 'Dedicated Pooler Client Connections', syncId: 'database-reports', valuePrecision: 0, entitlement: 'database', requiredPlan: 'Pro', hide: !entitledFeatures.includes('database'), showTooltip: true, showLegend: true, showMaxValue: true, showGrid: true, YAxisProps: { width: 30 }, hideChartType: false, defaultChartStyle: 'bar', titleTooltip: isHighAvailability ? 'Client connections to multipooler, the dedicated pooler for High Availability projects (docs coming soon)' : undefined, docsUrl: isHighAvailability ? undefined : `${DOCS_URL}/guides/platform/compute-and-disk#limits-and-constraints`, attributes: [ { attribute: 'client_connections_pgbouncer', provider: 'infra-monitoring', label: isHighAvailability ? 'multipooler' : 'pgbouncer', color: 'var(--chart-1)', fill: 'var(--chart-1-fill)', tooltip: isHighAvailability ? 'Multipooler connections' : 'PgBouncer connections', }, { attribute: 'pg_pooler_max_connections', provider: 'reference-line', label: 'Max pooler connections', color: 'var(--chart-reference)', value: pgBouncerMaxConnections, tooltip: 'Maximum allowed pooler connections for your current compute size', isMaxValue: true, }, ], }, { id: 'supavisor-connections-active', label: 'Shared Pooler (Supavisor) client connections', syncId: 'database-reports', valuePrecision: 0, entitlement: 'database', requiredPlan: 'Pro', // High Availability projects don't run Supavisor, so there's no data to show. hide: !entitledFeatures.includes('database') || isHighAvailability, showTooltip: true, showLegend: false, showMaxValue: false, showGrid: true, YAxisProps: { width: 30 }, hideChartType: false, defaultChartStyle: 'bar', attributes: [ { attribute: 'supavisor_connections_active', provider: 'infra-monitoring', label: 'supavisor', color: 'var(--chart-1)', fill: 'var(--chart-1-fill)', tooltip: 'Supavisor connections', }, ], }, { id: 'disk-size', label: 'Disk Usage', syncId: 'database-reports', valuePrecision: 2, hide: false, showTooltip: true, showLegend: true, showMaxValue: true, showGrid: true, YAxisProps: { width: 65, tickFormatter: (value: number) => formatBytes(value, 1), }, hideChartType: false, defaultChartStyle: 'bar', docsUrl: `${DOCS_URL}/guides/telemetry/reports#disk-size`, attributes: [ { attribute: 'disk_fs_used_system', provider: 'infra-monitoring', format: 'bytes', label: 'System', color: 'var(--chart-3)', fill: 'var(--chart-3-fill)', tooltip: 'Reserved space for the system to ensure your database runs smoothly', }, { attribute: 'disk_fs_used_wal', provider: 'infra-monitoring', format: 'bytes', label: 'WAL', color: 'var(--chart-2)', fill: 'var(--chart-2-fill)', tooltip: 'Disk usage by the write-ahead log. The usage depends on your WAL settings and the amount of data being written to the database', }, { attribute: 'pg_database_size', provider: 'infra-monitoring', format: 'bytes', label: 'Database', color: 'var(--chart-1)', fill: 'var(--chart-1-fill)', tooltip: 'Disk usage by your database (tables, indexes, data, ...)', }, { attribute: 'disk_fs_size', provider: 'infra-monitoring', isMaxValue: true, format: 'bytes', label: 'Disk Size', color: 'var(--chart-reference)', tooltip: 'Disk Size refers to the total space your project occupies on disk', }, entitledFeatures.includes('database') && (isSpendCapEnabled ? { attribute: 'pg_database_size_percent_paid_spendCap', provider: 'reference-line', isReferenceLine: true, strokeDasharray: '4 2', label: 'Spend cap enabled', value: diskConfig?.attributes?.size_gb! * 1024 * 1024 * 1024, className: '[&_line]:stroke-yellow-800! [&_line]:opacity-100!', opacity: 1, } : { attribute: 'pg_database_size_percent_paid', provider: 'reference-line', isReferenceLine: true, label: '90% - Disk resize threshold', className: '[&_line]:stroke-yellow-800!', value: diskConfig?.attributes?.size_gb! * 1024 * 1024 * 1024 * 0.9, }), ], }, ] }