@oneuptime/common 13.0.3 → 13.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/Index.ts +4 -0
- package/Models/DatabaseModels/RumApplication.ts +1 -1
- package/Models/DatabaseModels/SecurityEventConnection.ts +457 -0
- package/Models/DatabaseModels/SecurityEventConnectionRun.ts +263 -0
- package/Models/DatabaseModels/TelemetryIngestionKey.ts +2 -2
- package/Server/API/AIInvestigationAPI.ts +484 -24
- package/Server/API/GoogleSecOpsConnectionAPI.ts +249 -8
- package/Server/API/SecurityEventConnectionAPI.ts +250 -0
- package/Server/API/TelemetryAPI.ts +402 -265
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.ts +99 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Middleware/TelemetryIngest.ts +101 -6
- package/Server/Services/ExceptionAggregationService.ts +7 -16
- package/Server/Services/GoogleSecOpsConnectionService.ts +15 -0
- package/Server/Services/Index.ts +4 -0
- package/Server/Services/InventoryItemService.ts +28 -0
- package/Server/Services/LogAggregationService.ts +17 -23
- package/Server/Services/MetricAggregationService.ts +4 -14
- package/Server/Services/SecurityEventConnectionRunService.ts +10 -0
- package/Server/Services/SecurityEventConnectionService.ts +538 -0
- package/Server/Services/TraceAggregationService.ts +77 -28
- package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
- package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +13 -1
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +15 -1
- package/Server/Utils/AI/SRE/InvestigationEvidence.ts +658 -0
- package/Server/Utils/AI/SRE/InvestigationReferences.ts +324 -0
- package/Server/Utils/AI/Toolbox/Index.ts +38 -0
- package/Server/Utils/AI/Toolbox/TimelineTools.ts +9 -2
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +80 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +5 -3
- package/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.ts +1108 -0
- package/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.ts +732 -0
- package/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.ts +495 -0
- package/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.ts +689 -0
- package/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.ts +767 -0
- package/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.ts +571 -0
- package/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.ts +827 -0
- package/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.ts +610 -0
- package/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.ts +549 -0
- package/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.ts +830 -0
- package/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.ts +684 -0
- package/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.ts +487 -0
- package/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.ts +778 -0
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.ts +1002 -0
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.ts +556 -0
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.ts +275 -0
- package/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.ts +53 -0
- package/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.ts +709 -0
- package/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.ts +596 -0
- package/Server/Utils/SecurityEvent/Connectors/Types.ts +191 -0
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.ts +353 -65
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.ts +777 -0
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +747 -148
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.ts +48 -2
- package/Server/Utils/SecurityEvent/SecurityEventDedupe.ts +81 -0
- package/Server/Utils/SessionReplay/SessionReplayReadService.ts +741 -40
- package/Server/Utils/StartServer.ts +10 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +8 -0
- package/Server/Utils/Telemetry/KubernetesResourceAttributes.ts +108 -0
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +174 -93
- package/Server/Utils/Telemetry/ResourceFacetPlanner.ts +251 -0
- package/Server/Utils/Telemetry/ResourceFacetResolver.ts +248 -413
- package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +668 -0
- package/Server/Utils/Telemetry/TraceContextPropagation.ts +348 -0
- package/Server/Utils/Telemetry.ts +18 -0
- package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +413 -0
- package/Tests/App/Dashboard/AIRootCauseFeedItem.test.tsx +285 -0
- package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +242 -0
- package/Tests/App/Dashboard/AlertEpisodeViewFields.test.tsx +601 -15
- package/Tests/App/Dashboard/ChangeAlertStateAIHeader.test.tsx +835 -0
- package/Tests/App/Dashboard/CloudResourceTelemetryScope.test.ts +41 -0
- package/Tests/App/Dashboard/ConnectionTestModal.test.tsx +604 -0
- package/Tests/App/Dashboard/ConnectorTestReportView.test.tsx +738 -0
- package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +153 -6
- package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +165 -0
- package/Tests/App/Dashboard/EpisodeChangeState.test.tsx +1069 -0
- package/Tests/App/Dashboard/EpisodeMembersCard.test.tsx +772 -0
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +2354 -0
- package/Tests/App/Dashboard/EventOverviewSkeleton.test.tsx +210 -0
- package/Tests/App/Dashboard/EventStatBar.test.tsx +392 -0
- package/Tests/App/Dashboard/EventStatusPanel.test.tsx +247 -0
- package/Tests/App/Dashboard/ExceptionAIAssistance.test.tsx +606 -0
- package/Tests/App/Dashboard/ExceptionBreadcrumbTimeline.test.tsx +273 -0
- package/Tests/App/Dashboard/ExceptionDetailSideMenu.test.tsx +176 -0
- package/Tests/App/Dashboard/ExceptionOverviewCards.test.tsx +366 -0
- package/Tests/App/Dashboard/ExceptionSignalPages.test.tsx +371 -0
- package/Tests/App/Dashboard/ExceptionStackFrameViewer.test.tsx +440 -0
- package/Tests/App/Dashboard/ExceptionSummary.test.tsx +381 -0
- package/Tests/App/Dashboard/ExceptionTriage.test.tsx +306 -0
- package/Tests/App/Dashboard/ExceptionsResourceFacets.test.tsx +604 -0
- package/Tests/App/Dashboard/ExceptionsViewerEntityChips.test.tsx +706 -0
- package/Tests/App/Dashboard/FeedOrdering.test.ts +32 -0
- package/Tests/App/Dashboard/GoogleSecOpsConnectionForm.test.tsx +838 -0
- package/Tests/App/Dashboard/GoogleSecOpsConnectionsErrors.test.tsx +18 -0
- package/Tests/App/Dashboard/GoogleSecOpsDiagnostics.test.tsx +297 -20
- package/Tests/App/Dashboard/IncidentEpisodeViewFields.test.tsx +618 -13
- package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +254 -207
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +303 -135
- package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +1251 -0
- package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +303 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +876 -8
- package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +35 -0
- package/Tests/App/Dashboard/InvestigationReferenceLink.test.tsx +177 -0
- package/Tests/App/Dashboard/InvestigationReportView.test.tsx +1295 -0
- package/Tests/App/Dashboard/KubernetesImageReferenceView.test.tsx +114 -0
- package/Tests/App/Dashboard/KubernetesLogsTabChips.test.tsx +285 -0
- package/Tests/App/Dashboard/LogsEntityChipNames.test.tsx +316 -0
- package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +361 -0
- package/Tests/App/Dashboard/ProfileTableEntityNames.test.tsx +432 -0
- package/Tests/App/Dashboard/ProfileViewEntityName.test.tsx +250 -0
- package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +10 -0
- package/Tests/App/Dashboard/ResourceLogsTabsBareLayout.test.tsx +700 -0
- package/Tests/App/Dashboard/ResourcePageEntityNameProps.test.tsx +803 -0
- package/Tests/App/Dashboard/RumSessionReplaySideMenu.test.tsx +11 -1
- package/Tests/App/Dashboard/ScheduledMaintenanceChangeState.test.tsx +1026 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +436 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +1195 -0
- package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +1022 -0
- package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +905 -0
- package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +247 -0
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +375 -274
- package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +410 -0
- package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +774 -0
- package/Tests/App/Dashboard/TopErrorsPanelResourceNames.test.tsx +316 -0
- package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +30 -0
- package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +88 -24
- package/Tests/App/Dashboard/TraceExplorer.test.tsx +1590 -0
- package/Tests/App/Dashboard/TraceWaterfall.test.tsx +488 -0
- package/Tests/App/Dashboard/TracesAnalyticsSeriesLabels.test.tsx +367 -0
- package/Tests/App/Dashboard/TracesEntityNames.test.tsx +585 -0
- package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +613 -0
- package/Tests/App/Dashboard/UseServiceNames.test.tsx +359 -0
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +7 -0
- package/Tests/Models/InventoryItemNaming.test.ts +132 -16
- package/Tests/Models/SecurityDomainAccessControl.test.ts +61 -17
- package/Tests/Server/API/AIInvestigationAPI.test.ts +611 -2
- package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +1098 -0
- package/Tests/Server/API/GoogleSecOpsConnectionAPI.test.ts +409 -0
- package/Tests/Server/API/SecurityEventConnectionAPI.test.ts +856 -0
- package/Tests/Server/API/SessionReplayAPI.test.ts +528 -1
- package/Tests/Server/API/TelemetryFacetsAPI.test.ts +810 -0
- package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +240 -0
- package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +229 -0
- package/Tests/Server/Services/InventoryItemDisplayName.test.ts +66 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
- package/Tests/Server/Services/SecurityEventConnectionService.test.ts +1233 -0
- package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +53 -0
- package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +218 -0
- package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +155 -1
- package/Tests/Server/Services/TraceAggregationExceptionScope.test.ts +142 -0
- package/Tests/Server/Services/TraceAnalyticsResourceDisplayNames.test.ts +85 -24
- package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +33 -0
- package/Tests/Server/Utils/AI/InvestigationEvidence.test.ts +1395 -0
- package/Tests/Server/Utils/AI/InvestigationReferences.test.ts +616 -0
- package/Tests/Server/Utils/AI/TimelineTools.test.ts +119 -0
- package/Tests/Server/Utils/AI/Toolbox/AIToolbox.test.ts +151 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +65 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorExceptionScope.test.ts +224 -0
- package/Tests/Server/Utils/LoggerCore.test.ts +597 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPerSeriesFanout.test.ts +55 -2
- package/Tests/Server/Utils/Monitor/MonitorTemplateUtil.test.ts +1109 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.test.ts +1240 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.test.ts +1853 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.test.ts +1129 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.test.ts +1066 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.test.ts +1568 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.test.ts +930 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.test.ts +1409 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.test.ts +763 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.test.ts +1296 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.test.ts +1102 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.test.ts +1174 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.test.ts +1032 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.test.ts +1558 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.test.ts +3041 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.test.ts +1168 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.test.ts +906 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.test.ts +1068 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.test.ts +1004 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.test.ts +784 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +113 -1
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +5 -1
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +93 -13
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsHttpIntegration.test.ts +23 -1
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +25 -3
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +22 -8
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +82 -16
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSearchDetections.test.ts +730 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsThreePassPoller.test.ts +1577 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayOriginAllowlist.test.ts +41 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1453 -18
- package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +711 -0
- package/Tests/Server/Utils/Telemetry/KubernetesResourceAttributes.test.ts +162 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +460 -13
- package/Tests/Server/Utils/Telemetry/ResourceFacetPlanner.test.ts +678 -0
- package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +868 -0
- package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +525 -0
- package/Tests/Server/Utils/Telemetry/TraceContextPropagation.test.ts +420 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilCorePaths.test.ts +1014 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveRotation.test.ts +9 -6
- package/Tests/Types/Rules/RuleCriteriaFieldRegistry.test.ts +276 -0
- package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +73 -0
- package/Tests/Types/Rum/SessionReplayTransportContracts.test.ts +95 -0
- package/Tests/Types/SecurityEvent/Connectors/ConnectorDiagnostics.test.ts +82 -0
- package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +314 -0
- package/Tests/Types/Telemetry/ExceptionSpanScope.test.ts +89 -0
- package/Tests/Types/Telemetry/LlmConventions.test.ts +495 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +96 -0
- package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +304 -0
- package/Tests/UI/Components/ActiveFilterChipsLockedFilters.test.tsx +357 -0
- package/Tests/UI/Components/Card.test.tsx +312 -1
- package/Tests/UI/Components/CardModelDetailHeaderLayout.test.tsx +253 -0
- package/Tests/UI/Components/CardModelDetailRefresher.test.tsx +342 -0
- package/Tests/UI/Components/Checkbox.test.tsx +79 -0
- package/Tests/UI/Components/CopyTextButton.test.tsx +142 -0
- package/Tests/UI/Components/DetailCompactStyle.test.tsx +621 -0
- package/Tests/UI/Components/ErrorBoundary.test.tsx +60 -0
- package/Tests/UI/Components/FacetSections.test.tsx +581 -0
- package/Tests/UI/Components/FacetSidebarControls.test.tsx +812 -0
- package/Tests/UI/Components/FacetVisibility.test.ts +429 -0
- package/Tests/UI/Components/LockedFilterActions.test.tsx +396 -0
- package/Tests/UI/Components/LockedFilterChip.test.tsx +651 -0
- package/Tests/UI/Components/LogsEntityNames.test.ts +1769 -0
- package/Tests/UI/Components/LogsEntityNamesComponents.test.tsx +696 -0
- package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +600 -0
- package/Tests/UI/Components/LogsViewerEntityNames.test.tsx +713 -0
- package/Tests/UI/Components/MarkdownInlineReferences.test.tsx +2079 -0
- package/Tests/UI/Components/MemberRoleAssignment.test.tsx +446 -0
- package/Tests/UI/Components/ModelDetailRefetch.test.tsx +397 -0
- package/Tests/UI/Components/ModelListRefetch.test.tsx +233 -0
- package/Tests/UI/Components/ModelPageModelChange.test.tsx +409 -0
- package/Tests/UI/Components/PaginationIntegration.test.tsx +25 -0
- package/Tests/UI/Components/ResourceFacetConfigs.test.ts +172 -0
- package/Tests/UI/Components/SavedViewsSidebarIntegration.test.tsx +32 -14
- package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +44 -1
- package/Tests/UI/Components/TelemetryActiveFilterChipsLockedFilters.test.tsx +304 -0
- package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +718 -0
- package/Tests/UI/Monitor/EvaluationLogList.test.tsx +303 -0
- package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +55 -1
- package/Tests/UI/Rum/FidelityNotices.test.ts +22 -0
- package/Tests/UI/Rum/RecordingHealthCard.test.tsx +120 -136
- package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +988 -0
- package/Tests/UI/Rum/ReplayCard.test.tsx +32 -0
- package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +709 -12
- package/Tests/UI/Rum/ReplayHeader.test.tsx +50 -1
- package/Tests/UI/Rum/ReplayPinControl.test.tsx +67 -10
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +41 -12
- package/Tests/UI/Rum/ReplayStage.test.tsx +663 -1
- package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +173 -0
- package/Tests/UI/Rum/ReplayUi.test.tsx +189 -2
- package/Tests/UI/Rum/ReplayUserSessionsMenu.test.tsx +91 -0
- package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +1 -1
- package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +585 -0
- package/Tests/UI/Rum/SessionReplayTable.test.tsx +844 -51
- package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +29 -1
- package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +288 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +31 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +6 -0
- package/Tests/UI/Utils/Clipboard.test.ts +154 -0
- package/Tests/UI/Utils/Navigation.test.ts +24 -0
- package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +2205 -0
- package/Tests/UI/Utils/Telemetry/UseTelemetryEntityNames.test.tsx +844 -0
- package/Tests/Utils/AI/InvestigationReport.test.ts +2430 -0
- package/Tests/Utils/APIOutgoingRequestTracer.test.ts +137 -0
- package/Tests/Utils/Rum/SessionReplayHealth.test.ts +884 -0
- package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +40 -0
- package/Tests/Utils/Rum/SessionReplayRecordingEnded.test.ts +619 -0
- package/Tests/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.test.ts +631 -0
- package/Tests/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.test.ts +479 -0
- package/Tests/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.test.ts +507 -0
- package/Tests/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.test.ts +686 -0
- package/Tests/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.test.ts +474 -0
- package/Tests/Utils/SecurityEvent/Connectors/OktaNormalizer.test.ts +736 -0
- package/Tests/Utils/SecurityEvent/Connectors/SplunkNormalizer.test.ts +407 -0
- package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.test.ts +129 -0
- package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +57 -1
- package/Tests/Utils/Telemetry/EntityRelationship.test.ts +36 -0
- package/Tests/Utils/Telemetry/LockedFilterSearch.test.ts +600 -0
- package/Tests/Utils/Telemetry/NetworkHost.test.ts +48 -0
- package/Tests/Utils/Telemetry/OriginAllowList.test.ts +154 -0
- package/Tests/Utils/Traces/CriticalPath.test.ts +25 -0
- package/Types/AI/AIChatTypes.ts +8 -0
- package/Types/AI/InvestigationEvidence.ts +96 -0
- package/Types/Monitor/MonitorEvaluationSummary.ts +5 -0
- package/Types/OnCallDutyPolicy/Layer.ts +12 -0
- package/Types/Permission.ts +2 -2
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
- package/Types/Rum/SessionReplay.ts +109 -0
- package/Types/Rum/SessionReplayApi.ts +31 -0
- package/Types/SecurityEvent/Connectors/ConnectorDiagnostics.ts +111 -0
- package/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.ts +87 -0
- package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +492 -0
- package/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.ts +41 -0
- package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +56 -1
- package/Types/SecurityEvent/GoogleSecOpsRegion.ts +34 -0
- package/Types/Telemetry/EntityType.ts +14 -0
- package/Types/Telemetry/ExceptionSpanScope.ts +83 -0
- package/Types/Telemetry/LockedFilterDetail.ts +46 -0
- package/Types/Telemetry/ResourceEntityFacet.ts +17 -10
- package/Types/Telemetry/ResourceFacetCatalog.ts +171 -0
- package/UI/Components/Card/Card.tsx +118 -83
- package/UI/Components/Checkbox/Checkbox.tsx +8 -5
- package/UI/Components/CopyTextButton/CopyTextButton.tsx +7 -1
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +4 -1
- package/UI/Components/Detail/Detail.tsx +137 -22
- package/UI/Components/ErrorBoundary.tsx +38 -0
- package/UI/Components/LogsViewer/LogsEntityNames.ts +912 -0
- package/UI/Components/LogsViewer/LogsViewer.tsx +156 -77
- package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +28 -11
- package/UI/Components/LogsViewer/components/FacetSection.tsx +66 -79
- package/UI/Components/LogsViewer/components/FacetValueRow.tsx +17 -2
- package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +45 -5
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +100 -19
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +156 -39
- package/UI/Components/LogsViewer/components/LogsTable.tsx +30 -8
- package/UI/Components/LogsViewer/types.ts +6 -0
- package/UI/Components/Markdown.tsx/InlineReferences.tsx +628 -0
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +385 -312
- package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +50 -22
- package/UI/Components/ModelDetail/CardModelDetail.tsx +15 -0
- package/UI/Components/ModelDetail/ModelDetail.tsx +64 -19
- package/UI/Components/ModelList/ModelList.tsx +33 -8
- package/UI/Components/Page/ModelPage.tsx +119 -54
- package/UI/Components/Table/Table.tsx +8 -0
- package/UI/Components/Table/TableRow.tsx +13 -5
- package/UI/Components/TelemetryViewer/FacetVisibility.ts +229 -0
- package/UI/Components/TelemetryViewer/ResourceFacetConfigs.ts +46 -0
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +11 -0
- package/UI/Components/TelemetryViewer/components/FacetSearchInput.tsx +79 -0
- package/UI/Components/TelemetryViewer/components/FacetSectionHeader.tsx +69 -0
- package/UI/Components/TelemetryViewer/components/FacetShowMoreButton.tsx +36 -0
- package/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.tsx +88 -0
- package/UI/Components/TelemetryViewer/components/LockedFilterActions.tsx +205 -0
- package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +496 -0
- package/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.tsx +30 -10
- package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +203 -10
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSection.tsx +60 -73
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +94 -7
- package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +17 -2
- package/UI/Components/TelemetryViewer/types.ts +19 -0
- package/UI/Components/TelemetryViewer/useFacetSearchExemptions.ts +158 -0
- package/UI/Components/TelemetryViewer/useFacetSectionSearch.ts +102 -0
- package/UI/Utils/Clipboard.ts +68 -2
- package/UI/Utils/Navigation.ts +17 -2
- package/UI/Utils/Telemetry/TelemetryEntityNames.ts +620 -0
- package/UI/Utils/Telemetry/UseTelemetryEntityNames.ts +151 -0
- package/Utils/AI/InvestigationReport.ts +1789 -0
- package/Utils/API.ts +90 -1
- package/Utils/Rum/SessionReplayHealth.ts +11 -0
- package/Utils/Rum/SessionReplayRecordingEnded.ts +134 -0
- package/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.ts +427 -0
- package/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.ts +197 -0
- package/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.ts +464 -0
- package/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.ts +567 -0
- package/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.ts +299 -0
- package/Utils/SecurityEvent/Connectors/OktaNormalizer.ts +467 -0
- package/Utils/SecurityEvent/Connectors/SplunkNormalizer.ts +439 -0
- package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +124 -12
- package/Utils/Telemetry/CrossSignalScope.ts +22 -8
- package/Utils/Telemetry/EntityRelationship.ts +8 -0
- package/Utils/Telemetry/LockedFilterSearch.ts +412 -0
- package/Utils/Telemetry/NetworkHost.ts +43 -0
- package/Utils/Telemetry/OriginAllowList.ts +139 -4
- package/Utils/Traces/CriticalPath.ts +10 -4
- package/build/dist/Models/DatabaseModels/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
- package/build/dist/Models/DatabaseModels/SecurityEventConnection.js +490 -0
- package/build/dist/Models/DatabaseModels/SecurityEventConnection.js.map +1 -0
- package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js +287 -0
- package/build/dist/Models/DatabaseModels/SecurityEventConnectionRun.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +2 -2
- package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +336 -27
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +182 -7
- package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +1 -1
- package/build/dist/Server/API/SecurityEventConnectionAPI.js +171 -0
- package/build/dist/Server/API/SecurityEventConnectionAPI.js.map +1 -0
- package/build/dist/Server/API/TelemetryAPI.js +248 -170
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792700000000-AddSecurityEventConnections.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +57 -4
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/ExceptionAggregationService.js +7 -16
- package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
- package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +8 -0
- package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +4 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +22 -0
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +8 -17
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricAggregationService.js +4 -14
- package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
- package/build/dist/Server/Services/SecurityEventConnectionRunService.js +9 -0
- package/build/dist/Server/Services/SecurityEventConnectionRunService.js.map +1 -0
- package/build/dist/Server/Services/SecurityEventConnectionService.js +356 -0
- package/build/dist/Server/Services/SecurityEventConnectionService.js.map +1 -0
- package/build/dist/Server/Services/TraceAggregationService.js +51 -25
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +14 -7
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js +468 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationEvidence.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js +230 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationReferences.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/Index.js +32 -0
- package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js +6 -2
- package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +59 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +5 -3
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js +752 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js +493 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/AwsSecurityHub/AwsSecurityHubConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js +352 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ConnectorPlatformHealth.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js +405 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js +466 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/CrowdStrikeFalcon/CrowdStrikeFalconConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js +344 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js +511 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/ElasticSecurity/ElasticSecurityConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js +406 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js +336 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdr/MicrosoftDefenderXdrConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js +474 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js +417 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/MicrosoftSentinel/MicrosoftSentinelConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js +314 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js +494 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Okta/OktaConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js +719 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionPoller.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js +404 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionRunExecutor.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js +209 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectionTester.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js +40 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/SecurityEventConnectorRegistry.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js +494 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkClient.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js +379 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Splunk/SplunkConnector.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js +27 -0
- package/build/dist/Server/Utils/SecurityEvent/Connectors/Types.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +234 -61
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js +537 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsConnectionTester.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +572 -115
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +35 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js +52 -0
- package/build/dist/Server/Utils/SecurityEvent/SecurityEventDedupe.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +521 -32
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +10 -0
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +8 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js +80 -0
- package/build/dist/Server/Utils/Telemetry/KubernetesResourceAttributes.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +122 -67
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js +146 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetPlanner.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +174 -248
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +492 -0
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js +259 -0
- package/build/dist/Server/Utils/Telemetry/TraceContextPropagation.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry.js +11 -5
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Types/AI/InvestigationEvidence.js +2 -0
- package/build/dist/Types/AI/InvestigationEvidence.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/Layer.js +11 -0
- package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
- package/build/dist/Types/Permission.js +2 -2
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +9 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplay.js +95 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
- package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js +18 -0
- package/build/dist/Types/SecurityEvent/Connectors/ConnectorDiagnostics.js.map +1 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js +2 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectionDiagnostics.js.map +1 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +374 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js +35 -0
- package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorProvider.js.map +1 -0
- package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js +35 -0
- package/build/dist/Types/SecurityEvent/GoogleSecOpsRegion.js.map +1 -0
- package/build/dist/Types/Telemetry/EntityType.js +14 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/ExceptionSpanScope.js +59 -0
- package/build/dist/Types/Telemetry/ExceptionSpanScope.js.map +1 -0
- package/build/dist/Types/Telemetry/LockedFilterDetail.js +16 -0
- package/build/dist/Types/Telemetry/LockedFilterDetail.js.map +1 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js +16 -10
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -1
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +119 -0
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -0
- package/build/dist/UI/Components/Card/Card.js +34 -17
- package/build/dist/UI/Components/Card/Card.js.map +1 -1
- package/build/dist/UI/Components/Checkbox/Checkbox.js +6 -4
- package/build/dist/UI/Components/Checkbox/Checkbox.js.map +1 -1
- package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
- package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Detail/Detail.js +63 -13
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/ErrorBoundary.js +34 -0
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js +535 -0
- package/build/dist/UI/Components/LogsViewer/LogsEntityNames.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +117 -57
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +5 -7
- package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetSection.js +31 -44
- package/build/dist/UI/Components/LogsViewer/components/FacetSection.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +17 -3
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +19 -3
- package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +64 -18
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +100 -41
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +13 -5
- package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/types.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js +403 -0
- package/build/dist/UI/Components/Markdown.tsx/InlineReferences.js.map +1 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +197 -179
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +30 -21
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +12 -0
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/ModelDetail.js +46 -12
- package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelList/ModelList.js +26 -7
- package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
- package/build/dist/UI/Components/Page/ModelPage.js +62 -34
- package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
- package/build/dist/UI/Components/Table/Table.js +3 -1
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +8 -1
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +111 -0
- package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js +22 -0
- package/build/dist/UI/Components/TelemetryViewer/ResourceFacetConfigs.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js +36 -0
- package/build/dist/UI/Components/TelemetryViewer/components/FacetSearchInput.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js +21 -0
- package/build/dist/UI/Components/TelemetryViewer/components/FacetSectionHeader.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js +14 -0
- package/build/dist/UI/Components/TelemetryViewer/components/FacetShowMoreButton.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js +27 -0
- package/build/dist/UI/Components/TelemetryViewer/components/HiddenFacetsFooter.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js +88 -0
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterActions.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +228 -0
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js +6 -6
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +111 -12
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js +27 -40
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +70 -10
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +17 -3
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/types.js +0 -4
- package/build/dist/UI/Components/TelemetryViewer/types.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js +70 -0
- package/build/dist/UI/Components/TelemetryViewer/useFacetSearchExemptions.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js +52 -0
- package/build/dist/UI/Components/TelemetryViewer/useFacetSectionSearch.js.map +1 -0
- package/build/dist/UI/Utils/Clipboard.js +59 -2
- package/build/dist/UI/Utils/Clipboard.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +11 -2
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +471 -0
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -0
- package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js +113 -0
- package/build/dist/UI/Utils/Telemetry/UseTelemetryEntityNames.js.map +1 -0
- package/build/dist/Utils/AI/InvestigationReport.js +1241 -0
- package/build/dist/Utils/AI/InvestigationReport.js.map +1 -0
- package/build/dist/Utils/API.js +25 -0
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Rum/SessionReplayHealth.js +10 -0
- package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -1
- package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js +54 -0
- package/build/dist/Utils/Rum/SessionReplayRecordingEnded.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js +311 -0
- package/build/dist/Utils/SecurityEvent/Connectors/AwsSecurityHubNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js +150 -0
- package/build/dist/Utils/SecurityEvent/Connectors/CrowdStrikeFalconNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js +328 -0
- package/build/dist/Utils/SecurityEvent/Connectors/ElasticSecurityNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js +405 -0
- package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftDefenderXdrNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js +212 -0
- package/build/dist/Utils/SecurityEvent/Connectors/MicrosoftSentinelNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js +351 -0
- package/build/dist/Utils/SecurityEvent/Connectors/OktaNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js +348 -0
- package/build/dist/Utils/SecurityEvent/Connectors/SplunkNormalizer.js.map +1 -0
- package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +103 -10
- package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
- package/build/dist/Utils/Telemetry/CrossSignalScope.js +16 -5
- package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
- package/build/dist/Utils/Telemetry/EntityRelationship.js +7 -0
- package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
- package/build/dist/Utils/Telemetry/LockedFilterSearch.js +277 -0
- package/build/dist/Utils/Telemetry/LockedFilterSearch.js.map +1 -0
- package/build/dist/Utils/Telemetry/NetworkHost.js +39 -0
- package/build/dist/Utils/Telemetry/NetworkHost.js.map +1 -0
- package/build/dist/Utils/Telemetry/OriginAllowList.js +105 -4
- package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -1
- package/build/dist/Utils/Traces/CriticalPath.js +9 -4
- package/build/dist/Utils/Traces/CriticalPath.js.map +1 -1
- package/package.json +1 -1
- package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +0 -600
- package/UI/Components/GanttChart/Bar/BarLabel.tsx +0 -17
- package/UI/Components/GanttChart/Bar/Index.tsx +0 -149
- package/UI/Components/GanttChart/ChartContainer.tsx +0 -50
- package/UI/Components/GanttChart/Index.tsx +0 -90
- package/UI/Components/GanttChart/Row/Index.tsx +0 -22
- package/UI/Components/GanttChart/Row/Row.tsx +0 -231
- package/UI/Components/GanttChart/Row/RowLabel.tsx +0 -30
- package/UI/Components/GanttChart/Rows.tsx +0 -59
- package/UI/Components/GanttChart/Timeline/Index.tsx +0 -46
- package/UI/Components/GanttChart/Timeline/TimelineInterval.tsx +0 -33
- package/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.tsx +0 -43
- package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js +0 -8
- package/build/dist/UI/Components/GanttChart/Bar/BarLabel.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Bar/Index.js +0 -77
- package/build/dist/UI/Components/GanttChart/Bar/Index.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/ChartContainer.js +0 -33
- package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Index.js +0 -39
- package/build/dist/UI/Components/GanttChart/Index.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Row/Index.js +0 -7
- package/build/dist/UI/Components/GanttChart/Row/Index.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Row/Row.js +0 -106
- package/build/dist/UI/Components/GanttChart/Row/Row.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Row/RowLabel.js +0 -10
- package/build/dist/UI/Components/GanttChart/Row/RowLabel.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Rows.js +0 -19
- package/build/dist/UI/Components/GanttChart/Rows.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Timeline/Index.js +0 -16
- package/build/dist/UI/Components/GanttChart/Timeline/Index.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js +0 -13
- package/build/dist/UI/Components/GanttChart/Timeline/TimelineInterval.js.map +0 -1
- package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js +0 -13
- package/build/dist/UI/Components/GanttChart/Timeline/TimelineIntervalMarks.js.map +0 -1
|
@@ -15,6 +15,10 @@ import { JSONObject } from "../../../Types/JSON";
|
|
|
15
15
|
import ObjectID from "../../../Types/ObjectID";
|
|
16
16
|
import OneUptimeDate from "../../../Types/Date";
|
|
17
17
|
import ChunkMath from "../../../Utils/Rum/ChunkMath";
|
|
18
|
+
import {
|
|
19
|
+
SessionReplayTabEndFacts,
|
|
20
|
+
hasSessionRecordingEnded,
|
|
21
|
+
} from "../../../Utils/Rum/SessionReplayRecordingEnded";
|
|
18
22
|
import {
|
|
19
23
|
MAX_SESSION_REPLAY_CHUNKS_PER_READ,
|
|
20
24
|
MAX_SESSION_REPLAY_READ_BYTES,
|
|
@@ -35,6 +39,7 @@ import {
|
|
|
35
39
|
} from "../../../Types/Rum/SessionReplayApi";
|
|
36
40
|
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
37
41
|
import CaptureSpan from "../Telemetry/CaptureSpan";
|
|
42
|
+
import ServiceType from "../../../Types/Telemetry/ServiceType";
|
|
38
43
|
|
|
39
44
|
/*
|
|
40
45
|
* Bespoke ClickHouse reads for session-replay playback.
|
|
@@ -95,6 +100,15 @@ const READ_QUERY_SETTINGS: string = getQuerySettings({
|
|
|
95
100
|
export const DEFAULT_SESSION_REPLAY_LIST_LIMIT: number = 50;
|
|
96
101
|
export const MAX_SESSION_REPLAY_LIST_LIMIT: number = 200;
|
|
97
102
|
|
|
103
|
+
/*
|
|
104
|
+
* Audit tables resolve the opaque session ids on one page in a single
|
|
105
|
+
* ClickHouse read. Keep both the number of bound IN values and each value's
|
|
106
|
+
* size bounded; session ids are browser-minted 32-character hex strings, but
|
|
107
|
+
* older recorders and hand-written API callers may have stored another shape.
|
|
108
|
+
*/
|
|
109
|
+
export const MAX_SESSION_REPLAY_SUMMARIES_BATCH_SIZE: number = 200;
|
|
110
|
+
export const MAX_SESSION_REPLAY_SESSION_ID_LENGTH: number = 128;
|
|
111
|
+
|
|
98
112
|
/*
|
|
99
113
|
* Page sizes for the per-user rollup (listUsers). Same figures as the
|
|
100
114
|
* list, but the cost model differs: every page of the rollup
|
|
@@ -219,6 +233,11 @@ export interface SessionReplayListRequest {
|
|
|
219
233
|
* as well.
|
|
220
234
|
*/
|
|
221
235
|
includeIdentifiedUserLabel: boolean;
|
|
236
|
+
/*
|
|
237
|
+
* Server "now" in unix ms for the hasRecordingEnded grace. Absent means
|
|
238
|
+
* Date.now(); a test seam, like getApplicationActivitySummary's.
|
|
239
|
+
*/
|
|
240
|
+
nowUnixMs?: number | undefined;
|
|
222
241
|
}
|
|
223
242
|
|
|
224
243
|
export interface SessionReplayListItem {
|
|
@@ -278,6 +297,22 @@ export interface SessionReplayListItem {
|
|
|
278
297
|
tags: Record<string, string>;
|
|
279
298
|
startTimeUnixMs: number;
|
|
280
299
|
endTimeUnixMs: number;
|
|
300
|
+
/*
|
|
301
|
+
* True when the session is not finalized yet but every tab of it has
|
|
302
|
+
* ended (sent its final chunk, or stored its last permitted chunk
|
|
303
|
+
* index) and nothing has been stored for any of them for
|
|
304
|
+
* SESSION_REPLAY_ENDED_FINALIZE_GRACE_MS, judged from the chunk rows by
|
|
305
|
+
* the shared rule in Common/Utils/Rum/SessionReplayRecordingEnded.ts.
|
|
306
|
+
* "Not finalized" only says the finalizer has not run; this says the
|
|
307
|
+
* recording itself is over, which is what the Dashboard needs to stop
|
|
308
|
+
* calling a closed tab "Recording now". The grace is the finalizer's
|
|
309
|
+
* own, measured on the same server clock, so a multi-page app's next
|
|
310
|
+
* page (a new tab id whose first chunk is still on its way) does not
|
|
311
|
+
* flip a live session to "ended" for a poll. Always false for a
|
|
312
|
+
* finalized session, and false when the chunk rows could not be read -
|
|
313
|
+
* the list never fails for it.
|
|
314
|
+
*/
|
|
315
|
+
hasRecordingEnded: boolean;
|
|
281
316
|
}
|
|
282
317
|
|
|
283
318
|
export interface SessionReplayListResult {
|
|
@@ -285,6 +320,29 @@ export interface SessionReplayListResult {
|
|
|
285
320
|
nextCursor: SessionReplayListCursor | null;
|
|
286
321
|
}
|
|
287
322
|
|
|
323
|
+
export interface SessionReplaySummariesRequest {
|
|
324
|
+
projectId: ObjectID;
|
|
325
|
+
rumApplicationId: ObjectID;
|
|
326
|
+
sessionIds: Array<string>;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/*
|
|
330
|
+
* Deliberately excludes every identity field. An audit list needs enough
|
|
331
|
+
* context to distinguish recordings, not the person or browser identifier
|
|
332
|
+
* attached to them.
|
|
333
|
+
*/
|
|
334
|
+
export interface SessionReplaySummary {
|
|
335
|
+
sessionId: string;
|
|
336
|
+
startTime: Date;
|
|
337
|
+
startTimeUnixMs: number;
|
|
338
|
+
durationMs: number;
|
|
339
|
+
entryUrl: string;
|
|
340
|
+
browserName: string;
|
|
341
|
+
browserVersion: string;
|
|
342
|
+
osName: string;
|
|
343
|
+
deviceType: string;
|
|
344
|
+
}
|
|
345
|
+
|
|
288
346
|
/* Routes projected onto a list row; the table shows three and says "(N pages)". */
|
|
289
347
|
export const MAX_LIST_ROUTES: number = 5;
|
|
290
348
|
|
|
@@ -425,6 +483,19 @@ export interface SessionReplaySessionHeader {
|
|
|
425
483
|
*/
|
|
426
484
|
identifiedUserKey: string;
|
|
427
485
|
visitorId: string;
|
|
486
|
+
/*
|
|
487
|
+
* Same meaning as SessionReplayListItem.hasRecordingEnded.
|
|
488
|
+
*
|
|
489
|
+
* JUDGED ONLY BY getManifest; getSessionHeader always answers false.
|
|
490
|
+
* The header read is also the authorization lookup behind every chunk
|
|
491
|
+
* and heartbeat request, and its result is cached for 30s there, so a
|
|
492
|
+
* chunk-table read on it would add a query to every uncached seek and
|
|
493
|
+
* cache an answer that goes stale the moment a tab closes. The manifest
|
|
494
|
+
* is the one read that hands the header to the Dashboard, it always
|
|
495
|
+
* resolves the header fresh, and it is pinned to the application the
|
|
496
|
+
* caller was authorized against - which the chunk read needs.
|
|
497
|
+
*/
|
|
498
|
+
hasRecordingEnded: boolean;
|
|
428
499
|
/*
|
|
429
500
|
* Never populated by getSessionHeader. The manifest handler fills them
|
|
430
501
|
* from getSessionIdentity ONLY after canReadIdentifiedUserLabel passes,
|
|
@@ -694,6 +765,36 @@ const HEADER_AGGREGATES: Array<AggregatedColumn> = [
|
|
|
694
765
|
{ alias: "aggTags", expression: argMaxColumn("tags") },
|
|
695
766
|
];
|
|
696
767
|
|
|
768
|
+
/*
|
|
769
|
+
* The narrow projection used by the audit-table summary lookup. Derive it
|
|
770
|
+
* from the list's aggregates so live duration and replacement-row handling
|
|
771
|
+
* cannot drift between the two reads.
|
|
772
|
+
*/
|
|
773
|
+
const SESSION_SUMMARY_AGGREGATE_ALIASES: ReadonlyArray<string> = [
|
|
774
|
+
"aggStartTime",
|
|
775
|
+
"aggDurationMs",
|
|
776
|
+
"aggEntryUrl",
|
|
777
|
+
"aggBrowserName",
|
|
778
|
+
"aggBrowserVersion",
|
|
779
|
+
"aggOsName",
|
|
780
|
+
"aggDeviceType",
|
|
781
|
+
];
|
|
782
|
+
|
|
783
|
+
const SESSION_SUMMARY_AGGREGATES: Array<AggregatedColumn> =
|
|
784
|
+
SESSION_SUMMARY_AGGREGATE_ALIASES.map((alias: string): AggregatedColumn => {
|
|
785
|
+
const column: AggregatedColumn | undefined = HEADER_AGGREGATES.find(
|
|
786
|
+
(candidate: AggregatedColumn): boolean => {
|
|
787
|
+
return candidate.alias === alias;
|
|
788
|
+
},
|
|
789
|
+
);
|
|
790
|
+
|
|
791
|
+
if (!column) {
|
|
792
|
+
throw new Error(`HEADER_AGGREGATES has no column aliased ${alias}`);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
return column;
|
|
796
|
+
});
|
|
797
|
+
|
|
697
798
|
/* Only the manifest needs these; the list never renders them. */
|
|
698
799
|
const HEADER_DETAIL_AGGREGATES: Array<AggregatedColumn> = [
|
|
699
800
|
{ alias: "aggMaskingMode", expression: argMaxColumn("maskingMode") },
|
|
@@ -1015,6 +1116,82 @@ function readDate(row: JSONObject, key: string): Date {
|
|
|
1015
1116
|
return new Date(readNumber(row, key));
|
|
1016
1117
|
}
|
|
1017
1118
|
|
|
1119
|
+
/*
|
|
1120
|
+
* A number that has to be MEASURED, not defaulted. readNumber answers 0 for
|
|
1121
|
+
* a missing or garbled value, which is the right degradation for a counter
|
|
1122
|
+
* on a table row but the wrong one for a clock the "has this tab ended?"
|
|
1123
|
+
* rule compares: a missing last-chunk start read as 0 would sit before
|
|
1124
|
+
* every final chunk and call a live tab ended. NaN instead, which the
|
|
1125
|
+
* shared rule refuses outright.
|
|
1126
|
+
*/
|
|
1127
|
+
function readMeasuredNumber(row: JSONObject, key: string): number {
|
|
1128
|
+
const value: unknown = row[key];
|
|
1129
|
+
|
|
1130
|
+
if (typeof value === "number") {
|
|
1131
|
+
return Number.isFinite(value) ? value : Number.NaN;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/* Number("") and Number(" ") are 0, which is exactly the default above. */
|
|
1135
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
1136
|
+
const parsed: number = Number(value);
|
|
1137
|
+
return Number.isFinite(parsed) ? parsed : Number.NaN;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
return Number.NaN;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
/*
|
|
1144
|
+
* The per-tab facts the shared rule in
|
|
1145
|
+
* Common/Utils/Rum/SessionReplayRecordingEnded.ts is judged on, written
|
|
1146
|
+
* exactly as that file documents them. The clocks and the version are
|
|
1147
|
+
* wrapped in toFloat64 for the same reason as every wide column above:
|
|
1148
|
+
* ClickHouse's JSON format quotes Int64 and UInt64 as strings. The chunk
|
|
1149
|
+
* index is an Int32 and would come back as a number anyway; it is wrapped
|
|
1150
|
+
* too so every fact in the group parses the same way. The aliases do not
|
|
1151
|
+
* collide with a real column (see the NOTE on aliases at the top of this
|
|
1152
|
+
* file).
|
|
1153
|
+
*
|
|
1154
|
+
* Two of the five are not about the tab's own clock:
|
|
1155
|
+
*
|
|
1156
|
+
* - tabMaxChunkIndex lets the rule call a tab that stored its last
|
|
1157
|
+
* permitted chunk index ended. The ingest gate refuses everything past
|
|
1158
|
+
* it, the recorder's own truncation seal included, so that tab never
|
|
1159
|
+
* gets a final chunk and would otherwise read as "recording" until the
|
|
1160
|
+
* idle finalizer.
|
|
1161
|
+
* - tabLastChunkStoredAtUnixMs is max(version): the SERVER unix ms at
|
|
1162
|
+
* which the tab's newest chunk row was written. The grace is measured
|
|
1163
|
+
* on it, never on the device clock the chunk times come from.
|
|
1164
|
+
*/
|
|
1165
|
+
const TAB_HAS_FINAL_CHUNK_ALIAS: string = "tabHasFinalChunk";
|
|
1166
|
+
const TAB_FINAL_CHUNK_END_ALIAS: string = "tabFinalChunkEndUnixMs";
|
|
1167
|
+
const TAB_LAST_CHUNK_START_ALIAS: string = "tabLastChunkStartUnixMs";
|
|
1168
|
+
const TAB_MAX_CHUNK_INDEX_ALIAS: string = "tabMaxChunkIndex";
|
|
1169
|
+
const TAB_LAST_CHUNK_STORED_AT_ALIAS: string = "tabLastChunkStoredAtUnixMs";
|
|
1170
|
+
|
|
1171
|
+
const TAB_END_FACT_AGGREGATES: Array<AggregatedColumn> = [
|
|
1172
|
+
{
|
|
1173
|
+
alias: TAB_HAS_FINAL_CHUNK_ALIAS,
|
|
1174
|
+
expression: "max(toUInt8(isFinal))",
|
|
1175
|
+
},
|
|
1176
|
+
{
|
|
1177
|
+
alias: TAB_FINAL_CHUNK_END_ALIAS,
|
|
1178
|
+
expression:
|
|
1179
|
+
"toFloat64(toUnixTimestamp64Milli(maxIf(chunkEndTime, isFinal)))",
|
|
1180
|
+
},
|
|
1181
|
+
{
|
|
1182
|
+
alias: TAB_LAST_CHUNK_START_ALIAS,
|
|
1183
|
+
expression: "toFloat64(toUnixTimestamp64Milli(max(chunkStartTime)))",
|
|
1184
|
+
},
|
|
1185
|
+
{
|
|
1186
|
+
alias: TAB_MAX_CHUNK_INDEX_ALIAS,
|
|
1187
|
+
expression: "toFloat64(max(chunkIndex))",
|
|
1188
|
+
},
|
|
1189
|
+
{
|
|
1190
|
+
alias: TAB_LAST_CHUNK_STORED_AT_ALIAS,
|
|
1191
|
+
expression: "toFloat64(max(version))",
|
|
1192
|
+
},
|
|
1193
|
+
];
|
|
1194
|
+
|
|
1018
1195
|
/*
|
|
1019
1196
|
* The capability list chunk 0 declared, filtered to the vocabulary this
|
|
1020
1197
|
* build knows so a stored typo never reaches the player as a capability.
|
|
@@ -1088,6 +1265,120 @@ export default class SessionReplayReadService {
|
|
|
1088
1265
|
activitySummaryCache.clear();
|
|
1089
1266
|
}
|
|
1090
1267
|
|
|
1268
|
+
/*
|
|
1269
|
+
* Resolve the opaque ids stored on audit rows into compact session facts.
|
|
1270
|
+
* This is intentionally one bespoke query instead of N getSessionHeader
|
|
1271
|
+
* calls (or AnalyticsModelAPI, which RumSession does not expose). The
|
|
1272
|
+
* project and application are both pinned before the caller-controlled IN
|
|
1273
|
+
* list, and argMax collapses provisional/finalized ReplacingMergeTree rows.
|
|
1274
|
+
*/
|
|
1275
|
+
@CaptureSpan()
|
|
1276
|
+
public static async getSessionSummaries(
|
|
1277
|
+
request: SessionReplaySummariesRequest,
|
|
1278
|
+
): Promise<Array<SessionReplaySummary>> {
|
|
1279
|
+
if (request.sessionIds.length === 0) {
|
|
1280
|
+
throw new BadDataException("sessionIds must contain at least one id");
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
if (request.sessionIds.length > MAX_SESSION_REPLAY_SUMMARIES_BATCH_SIZE) {
|
|
1284
|
+
throw new BadDataException(
|
|
1285
|
+
`sessionIds must contain at most ${MAX_SESSION_REPLAY_SUMMARIES_BATCH_SIZE} ids`,
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
for (const sessionId of request.sessionIds) {
|
|
1290
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
1291
|
+
throw new BadDataException(
|
|
1292
|
+
"Every sessionId must be a non-empty string",
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
if (sessionId.length > MAX_SESSION_REPLAY_SESSION_ID_LENGTH) {
|
|
1297
|
+
throw new BadDataException(
|
|
1298
|
+
`Every sessionId must be at most ${MAX_SESSION_REPLAY_SESSION_ID_LENGTH} characters.`,
|
|
1299
|
+
);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
/* Preserve first occurrence order while binding every id only once. */
|
|
1304
|
+
const sessionIds: Array<string> = Array.from(
|
|
1305
|
+
new Set<string>(request.sessionIds),
|
|
1306
|
+
);
|
|
1307
|
+
|
|
1308
|
+
const statement: Statement = SQL`
|
|
1309
|
+
SELECT
|
|
1310
|
+
sessionId,
|
|
1311
|
+
`;
|
|
1312
|
+
|
|
1313
|
+
statement.append(` ${toSelectList(SESSION_SUMMARY_AGGREGATES)}`);
|
|
1314
|
+
|
|
1315
|
+
statement.append(SQL`
|
|
1316
|
+
FROM ${AnalyticsTableName.RumSession}
|
|
1317
|
+
WHERE projectId = ${{
|
|
1318
|
+
type: TableColumnType.ObjectID,
|
|
1319
|
+
value: request.projectId,
|
|
1320
|
+
}}
|
|
1321
|
+
AND rumApplicationId = ${{
|
|
1322
|
+
type: TableColumnType.ObjectID,
|
|
1323
|
+
value: request.rumApplicationId,
|
|
1324
|
+
}}
|
|
1325
|
+
AND sessionId IN (${{
|
|
1326
|
+
type: TableColumnType.Text,
|
|
1327
|
+
value: new Includes(sessionIds),
|
|
1328
|
+
}})
|
|
1329
|
+
`);
|
|
1330
|
+
|
|
1331
|
+
statement.append(RETENTION_FILTER);
|
|
1332
|
+
statement.append(
|
|
1333
|
+
" GROUP BY projectId, rumApplicationId, sessionId ORDER BY aggStartTime DESC",
|
|
1334
|
+
);
|
|
1335
|
+
statement.append(READ_QUERY_SETTINGS);
|
|
1336
|
+
|
|
1337
|
+
const dbResult: Results = await RumSessionService.executeQuery(statement);
|
|
1338
|
+
const response: DbJSONResponse = await dbResult.json<{
|
|
1339
|
+
data?: Array<JSONObject>;
|
|
1340
|
+
}>();
|
|
1341
|
+
|
|
1342
|
+
const requestedIds: Set<string> = new Set<string>(sessionIds);
|
|
1343
|
+
const summariesById: Map<string, SessionReplaySummary> = new Map<
|
|
1344
|
+
string,
|
|
1345
|
+
SessionReplaySummary
|
|
1346
|
+
>();
|
|
1347
|
+
|
|
1348
|
+
for (const row of response.data || []) {
|
|
1349
|
+
const sessionId: string = readString(row, "sessionId");
|
|
1350
|
+
|
|
1351
|
+
/* A malformed/unexpected driver row can never add data to the reply. */
|
|
1352
|
+
if (!requestedIds.has(sessionId) || summariesById.has(sessionId)) {
|
|
1353
|
+
continue;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
const startTime: Date = readDate(row, "aggStartTime");
|
|
1357
|
+
|
|
1358
|
+
summariesById.set(sessionId, {
|
|
1359
|
+
sessionId: sessionId,
|
|
1360
|
+
startTime: startTime,
|
|
1361
|
+
startTimeUnixMs: startTime.getTime(),
|
|
1362
|
+
durationMs: readNumber(row, "aggDurationMs"),
|
|
1363
|
+
entryUrl: readString(row, "aggEntryUrl"),
|
|
1364
|
+
browserName: readString(row, "aggBrowserName"),
|
|
1365
|
+
browserVersion: readString(row, "aggBrowserVersion"),
|
|
1366
|
+
osName: readString(row, "aggOsName"),
|
|
1367
|
+
deviceType: readString(row, "aggDeviceType"),
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
/* Stable request order makes consumers deterministic; missing ids omit. */
|
|
1372
|
+
return sessionIds.flatMap(
|
|
1373
|
+
(sessionId: string): Array<SessionReplaySummary> => {
|
|
1374
|
+
const summary: SessionReplaySummary | undefined =
|
|
1375
|
+
summariesById.get(sessionId);
|
|
1376
|
+
|
|
1377
|
+
return summary ? [summary] : [];
|
|
1378
|
+
},
|
|
1379
|
+
);
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1091
1382
|
/*
|
|
1092
1383
|
* Session list.
|
|
1093
1384
|
*
|
|
@@ -1304,6 +1595,8 @@ export default class SessionReplayReadService {
|
|
|
1304
1595
|
tags: readStringMap(row, "aggTags"),
|
|
1305
1596
|
startTimeUnixMs: startTime.getTime(),
|
|
1306
1597
|
endTimeUnixMs: endTime.getTime(),
|
|
1598
|
+
/* Judged below, only for the page's unfinalized sessions. */
|
|
1599
|
+
hasRecordingEnded: false,
|
|
1307
1600
|
};
|
|
1308
1601
|
|
|
1309
1602
|
if (request.includeIdentifiedUserLabel) {
|
|
@@ -1318,6 +1611,44 @@ export default class SessionReplayReadService {
|
|
|
1318
1611
|
},
|
|
1319
1612
|
);
|
|
1320
1613
|
|
|
1614
|
+
/*
|
|
1615
|
+
* "Recording now" or "recording ended"? The header cannot say: a
|
|
1616
|
+
* provisional header stays unfinalized for the whole idle window
|
|
1617
|
+
* after its last tab closed, which is how a closed tab kept its
|
|
1618
|
+
* "Recording now" badge for 10-15 minutes. The chunk rows can, so the
|
|
1619
|
+
* page's unfinalized sessions - and only those - get ONE follow-up
|
|
1620
|
+
* read over the chunk table. A page of finalized sessions (the
|
|
1621
|
+
* overwhelming majority of any list older than a few minutes) runs
|
|
1622
|
+
* no second query at all.
|
|
1623
|
+
*
|
|
1624
|
+
* It is a separate statement rather than a JOIN on the list query
|
|
1625
|
+
* because the list's own read is a range over the HEADER table's sort
|
|
1626
|
+
* key, and joining the chunk table there would aggregate chunk rows
|
|
1627
|
+
* for every session in the window before the LIMIT picked a page.
|
|
1628
|
+
*/
|
|
1629
|
+
const unfinalizedSessionIds: Array<string> = sessions
|
|
1630
|
+
.filter((session: SessionReplayListItem): boolean => {
|
|
1631
|
+
return !session.isFinalized;
|
|
1632
|
+
})
|
|
1633
|
+
.map((session: SessionReplayListItem): string => {
|
|
1634
|
+
return session.sessionId;
|
|
1635
|
+
});
|
|
1636
|
+
|
|
1637
|
+
if (unfinalizedSessionIds.length > 0) {
|
|
1638
|
+
const endedSessionIds: Set<string> =
|
|
1639
|
+
await SessionReplayReadService.readRecordingEndedSessionIds({
|
|
1640
|
+
projectId: request.projectId,
|
|
1641
|
+
rumApplicationId: request.rumApplicationId,
|
|
1642
|
+
sessionIds: unfinalizedSessionIds,
|
|
1643
|
+
nowUnixMs: request.nowUnixMs ?? Date.now(),
|
|
1644
|
+
});
|
|
1645
|
+
|
|
1646
|
+
for (const session of sessions) {
|
|
1647
|
+
session.hasRecordingEnded =
|
|
1648
|
+
!session.isFinalized && endedSessionIds.has(session.sessionId);
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1321
1652
|
const lastSession: SessionReplayListItem | undefined =
|
|
1322
1653
|
sessions[sessions.length - 1];
|
|
1323
1654
|
|
|
@@ -1719,6 +2050,12 @@ export default class SessionReplayReadService {
|
|
|
1719
2050
|
recorderCapabilities: readRecorderCapabilities(row),
|
|
1720
2051
|
identifiedUserKey: readString(row, "aggIdentifiedUserKey"),
|
|
1721
2052
|
visitorId: readString(row, "aggVisitorId"),
|
|
2053
|
+
/*
|
|
2054
|
+
* Not judged here: see SessionReplaySessionHeader.hasRecordingEnded.
|
|
2055
|
+
* getManifest, the read that returns this header to the Dashboard,
|
|
2056
|
+
* replaces it for an unfinalized session.
|
|
2057
|
+
*/
|
|
2058
|
+
hasRecordingEnded: false,
|
|
1722
2059
|
};
|
|
1723
2060
|
}
|
|
1724
2061
|
|
|
@@ -1870,6 +2207,11 @@ export default class SessionReplayReadService {
|
|
|
1870
2207
|
*/
|
|
1871
2208
|
rumApplicationId: ObjectID;
|
|
1872
2209
|
sessionId: string;
|
|
2210
|
+
/*
|
|
2211
|
+
* Server "now" in unix ms for the hasRecordingEnded grace. Absent
|
|
2212
|
+
* means Date.now(); a test seam, like listSessions'.
|
|
2213
|
+
*/
|
|
2214
|
+
nowUnixMs?: number | undefined;
|
|
1873
2215
|
}): Promise<SessionReplayManifest> {
|
|
1874
2216
|
/*
|
|
1875
2217
|
* LIMIT 1 BY (tabId, chunkIndex) after ORDER BY ... version DESC
|
|
@@ -1929,8 +2271,38 @@ export default class SessionReplayReadService {
|
|
|
1929
2271
|
|
|
1930
2272
|
statement.append(READ_QUERY_SETTINGS);
|
|
1931
2273
|
|
|
1932
|
-
|
|
1933
|
-
|
|
2274
|
+
/*
|
|
2275
|
+
* Whether this unfinalized session's recording is already over, read
|
|
2276
|
+
* alongside the manifest rather than after it: the player re-fetches
|
|
2277
|
+
* the manifest every 30s while a session is not finalized, and this
|
|
2278
|
+
* is what lets it stop calling a closed session "Live" once the
|
|
2279
|
+
* ended grace has passed, instead of waiting for a finalizer run to
|
|
2280
|
+
* seal the header. The same helper, the same grace and the same
|
|
2281
|
+
* clock the list uses, so the list badge and the player pill can
|
|
2282
|
+
* never disagree about one session.
|
|
2283
|
+
*
|
|
2284
|
+
* Its own grouped read rather than a fold over the rows below: those
|
|
2285
|
+
* rows are capped at MAX_MANIFEST_ROWS in (tabId, chunkIndex) order, so
|
|
2286
|
+
* a truncated manifest would lose a tab's newest chunks - exactly the
|
|
2287
|
+
* rows that say whether it kept recording after its final chunk. A
|
|
2288
|
+
* finalized header is authoritative and runs no second read. The
|
|
2289
|
+
* helper never rejects (a failure answers "not ended"), so it cannot
|
|
2290
|
+
* fail the manifest. The manifest statement is issued first.
|
|
2291
|
+
*/
|
|
2292
|
+
const manifestResultPromise: Promise<Results> =
|
|
2293
|
+
RumSessionChunkService.executeQuery(statement);
|
|
2294
|
+
|
|
2295
|
+
const endedSessionIdsPromise: Promise<Set<string>> = data.header.isFinalized
|
|
2296
|
+
? Promise.resolve(new Set<string>())
|
|
2297
|
+
: SessionReplayReadService.readRecordingEndedSessionIds({
|
|
2298
|
+
projectId: data.projectId,
|
|
2299
|
+
rumApplicationId: data.rumApplicationId,
|
|
2300
|
+
sessionIds: [data.sessionId],
|
|
2301
|
+
nowUnixMs: data.nowUnixMs ?? Date.now(),
|
|
2302
|
+
});
|
|
2303
|
+
|
|
2304
|
+
const [dbResult, endedSessionIds]: [Results, Set<string>] =
|
|
2305
|
+
await Promise.all([manifestResultPromise, endedSessionIdsPromise]);
|
|
1934
2306
|
const response: DbJSONResponse = await dbResult.json<{
|
|
1935
2307
|
data?: Array<JSONObject>;
|
|
1936
2308
|
}>();
|
|
@@ -2040,6 +2412,7 @@ export default class SessionReplayReadService {
|
|
|
2040
2412
|
liveDurationMs: liveDurationMs,
|
|
2041
2413
|
liveEventCount: liveEventCount,
|
|
2042
2414
|
liveMaxChunkIndex: liveMaxChunkIndex,
|
|
2415
|
+
hasRecordingEnded: endedSessionIds.has(data.sessionId),
|
|
2043
2416
|
}),
|
|
2044
2417
|
tabs: tabs,
|
|
2045
2418
|
isChunkIndexTruncated: rows.length >= MAX_MANIFEST_ROWS,
|
|
@@ -2051,6 +2424,10 @@ export default class SessionReplayReadService {
|
|
|
2051
2424
|
* 0 and eventCount 0 while its chunk rows say otherwise; the manifest
|
|
2052
2425
|
* has just read every chunk row, so it reports what the rows prove. A
|
|
2053
2426
|
* finalized header is authoritative and returned untouched.
|
|
2427
|
+
*
|
|
2428
|
+
* hasRecordingEnded is set on every unfinalized header, including one
|
|
2429
|
+
* whose chunk rows have not landed yet: getSessionHeader never judges
|
|
2430
|
+
* it, so the manifest is the only place the field is ever true.
|
|
2054
2431
|
*/
|
|
2055
2432
|
private static reconcileLiveHeader(data: {
|
|
2056
2433
|
header: SessionReplaySessionHeader;
|
|
@@ -2058,11 +2435,19 @@ export default class SessionReplayReadService {
|
|
|
2058
2435
|
liveDurationMs: number;
|
|
2059
2436
|
liveEventCount: number;
|
|
2060
2437
|
liveMaxChunkIndex: number;
|
|
2438
|
+
hasRecordingEnded: boolean;
|
|
2061
2439
|
}): SessionReplaySessionHeader {
|
|
2062
|
-
if (data.header.isFinalized
|
|
2440
|
+
if (data.header.isFinalized) {
|
|
2063
2441
|
return data.header;
|
|
2064
2442
|
}
|
|
2065
2443
|
|
|
2444
|
+
if (data.chunkRowCount === 0) {
|
|
2445
|
+
return {
|
|
2446
|
+
...data.header,
|
|
2447
|
+
hasRecordingEnded: data.hasRecordingEnded,
|
|
2448
|
+
};
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2066
2451
|
const durationMs: number = Math.max(
|
|
2067
2452
|
data.header.durationMs,
|
|
2068
2453
|
data.liveDurationMs,
|
|
@@ -2083,9 +2468,174 @@ export default class SessionReplayReadService {
|
|
|
2083
2468
|
data.header.maxChunkIndex,
|
|
2084
2469
|
data.liveMaxChunkIndex,
|
|
2085
2470
|
),
|
|
2471
|
+
hasRecordingEnded: data.hasRecordingEnded,
|
|
2086
2472
|
};
|
|
2087
2473
|
}
|
|
2088
2474
|
|
|
2475
|
+
/*
|
|
2476
|
+
* Which of these unfinalized sessions have stopped recording, judged by
|
|
2477
|
+
* the shared rule (Common/Utils/Rum/SessionReplayRecordingEnded.ts) over
|
|
2478
|
+
* their chunk rows. The one helper behind both the list badge and the
|
|
2479
|
+
* player's Live pill.
|
|
2480
|
+
*
|
|
2481
|
+
* One statement for any number of sessions:
|
|
2482
|
+
*
|
|
2483
|
+
* WHERE projectId = ? AND sessionId IN (...) AND rumApplicationId = ?
|
|
2484
|
+
* GROUP BY sessionId, tabId
|
|
2485
|
+
*
|
|
2486
|
+
* A KEY-RANGE READ. RumSessionChunk is sorted (and primary-keyed) by
|
|
2487
|
+
* (projectId, sessionId, tabId, chunkIndex), so projectId plus a
|
|
2488
|
+
* sessionId IN list is a prefix of the primary index: ClickHouse reads
|
|
2489
|
+
* only the granules of the named sessions - a handful of narrow columns
|
|
2490
|
+
* over at most a few hundred rows each - and never the payload column.
|
|
2491
|
+
* The GROUP BY follows the same key order. rumApplicationId is a plain
|
|
2492
|
+
* column filtered over those granules, and it is not optional: the
|
|
2493
|
+
* table's replace key has no application in it, so two applications
|
|
2494
|
+
* that share a browser-minted sessionId share one key space, and
|
|
2495
|
+
* without the pin one application's closed tab could end another's
|
|
2496
|
+
* recording.
|
|
2497
|
+
*
|
|
2498
|
+
* Grouped per tab, never per session, because the rule is per tab: a
|
|
2499
|
+
* session shared by several tabs (or several page loads of a multi-page
|
|
2500
|
+
* app) is over only when every one of them is. The five aggregates are
|
|
2501
|
+
* maxima, so a redelivered chunk's duplicate row - or a pinned copy -
|
|
2502
|
+
* cannot make a live tab look ended and no LIMIT 1 BY is needed. Such a
|
|
2503
|
+
* row can carry a NEWER version than the original, which only restarts
|
|
2504
|
+
* the grace once; it never shortens it. The retention filter is kept
|
|
2505
|
+
* like on every other replay read.
|
|
2506
|
+
*
|
|
2507
|
+
* The grace. Every tab having ended is not enough on its own: in a
|
|
2508
|
+
* multi-page app, page A's final chunk lands while page B - a new tab id
|
|
2509
|
+
* under the same session - has not stored its first chunk yet, and for
|
|
2510
|
+
* that moment the only tab the rows know about has ended. So the rule
|
|
2511
|
+
* also wants the newest stored chunk of the session to be at least
|
|
2512
|
+
* SESSION_REPLAY_ENDED_FINALIZE_GRACE_MS older than nowUnixMs, the same
|
|
2513
|
+
* grace the finalizer waits on, measured on the same server clock (the
|
|
2514
|
+
* rows' version against this process's Date.now()). The list, the player
|
|
2515
|
+
* and the finalizer therefore call a session ended at the same moment,
|
|
2516
|
+
* give or take the finalizer's one-minute schedule, and none of them
|
|
2517
|
+
* depends on Redis for it.
|
|
2518
|
+
*
|
|
2519
|
+
* Best-effort. A failure logs a warning and answers "nothing has ended",
|
|
2520
|
+
* which is what the Dashboard showed before this existed; neither the
|
|
2521
|
+
* list nor the manifest may fail because of it. A session with no chunk
|
|
2522
|
+
* rows has no tabs, and no tabs is "not known", never "ended".
|
|
2523
|
+
*/
|
|
2524
|
+
private static async readRecordingEndedSessionIds(data: {
|
|
2525
|
+
projectId: ObjectID;
|
|
2526
|
+
rumApplicationId: ObjectID;
|
|
2527
|
+
sessionIds: Array<string>;
|
|
2528
|
+
/* Server unix ms the grace is measured against. */
|
|
2529
|
+
nowUnixMs: number;
|
|
2530
|
+
}): Promise<Set<string>> {
|
|
2531
|
+
const endedSessionIds: Set<string> = new Set<string>();
|
|
2532
|
+
|
|
2533
|
+
const sessionIds: Array<string> = Array.from(
|
|
2534
|
+
new Set<string>(
|
|
2535
|
+
data.sessionIds.filter((sessionId: string): boolean => {
|
|
2536
|
+
return sessionId.length > 0;
|
|
2537
|
+
}),
|
|
2538
|
+
),
|
|
2539
|
+
);
|
|
2540
|
+
|
|
2541
|
+
if (sessionIds.length === 0) {
|
|
2542
|
+
return endedSessionIds;
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
const statement: Statement = SQL`
|
|
2546
|
+
SELECT
|
|
2547
|
+
sessionId,
|
|
2548
|
+
tabId,
|
|
2549
|
+
`;
|
|
2550
|
+
|
|
2551
|
+
statement.append(` ${toSelectList(TAB_END_FACT_AGGREGATES)}`);
|
|
2552
|
+
|
|
2553
|
+
statement.append(SQL`
|
|
2554
|
+
FROM ${AnalyticsTableName.RumSessionChunk}
|
|
2555
|
+
WHERE projectId = ${{
|
|
2556
|
+
type: TableColumnType.ObjectID,
|
|
2557
|
+
value: data.projectId,
|
|
2558
|
+
}}
|
|
2559
|
+
AND sessionId IN (${{
|
|
2560
|
+
type: TableColumnType.Text,
|
|
2561
|
+
value: new Includes(sessionIds),
|
|
2562
|
+
}})
|
|
2563
|
+
AND rumApplicationId = ${{
|
|
2564
|
+
type: TableColumnType.ObjectID,
|
|
2565
|
+
value: data.rumApplicationId,
|
|
2566
|
+
}}
|
|
2567
|
+
`);
|
|
2568
|
+
|
|
2569
|
+
statement.append(RETENTION_FILTER);
|
|
2570
|
+
statement.append(" GROUP BY sessionId, tabId");
|
|
2571
|
+
statement.append(READ_QUERY_SETTINGS);
|
|
2572
|
+
|
|
2573
|
+
let rows: Array<JSONObject>;
|
|
2574
|
+
|
|
2575
|
+
try {
|
|
2576
|
+
const dbResult: Results =
|
|
2577
|
+
await RumSessionChunkService.executeQuery(statement);
|
|
2578
|
+
const response: DbJSONResponse = await dbResult.json<{
|
|
2579
|
+
data?: Array<JSONObject>;
|
|
2580
|
+
}>();
|
|
2581
|
+
|
|
2582
|
+
rows = response.data || [];
|
|
2583
|
+
} catch (err: unknown) {
|
|
2584
|
+
logger.warn(
|
|
2585
|
+
"SessionReplayReadService: could not read chunk rows to tell whether unfinalized sessions have ended; reporting them as still recording",
|
|
2586
|
+
);
|
|
2587
|
+
logger.warn(err);
|
|
2588
|
+
|
|
2589
|
+
return endedSessionIds;
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
const requested: Set<string> = new Set<string>(sessionIds);
|
|
2593
|
+
const tabsBySessionId: Map<
|
|
2594
|
+
string,
|
|
2595
|
+
Array<SessionReplayTabEndFacts>
|
|
2596
|
+
> = new Map<string, Array<SessionReplayTabEndFacts>>();
|
|
2597
|
+
|
|
2598
|
+
for (const row of rows) {
|
|
2599
|
+
const sessionId: string = readString(row, "sessionId");
|
|
2600
|
+
|
|
2601
|
+
/* Defensive: a row for a session nobody asked about decides nothing. */
|
|
2602
|
+
if (!requested.has(sessionId)) {
|
|
2603
|
+
continue;
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
const tab: SessionReplayTabEndFacts = {
|
|
2607
|
+
hasFinalChunk: readBoolean(row, TAB_HAS_FINAL_CHUNK_ALIAS),
|
|
2608
|
+
finalChunkEndUnixMs: readMeasuredNumber(row, TAB_FINAL_CHUNK_END_ALIAS),
|
|
2609
|
+
lastChunkStartUnixMs: readMeasuredNumber(
|
|
2610
|
+
row,
|
|
2611
|
+
TAB_LAST_CHUNK_START_ALIAS,
|
|
2612
|
+
),
|
|
2613
|
+
maxChunkIndex: readMeasuredNumber(row, TAB_MAX_CHUNK_INDEX_ALIAS),
|
|
2614
|
+
lastChunkStoredAtUnixMs: readMeasuredNumber(
|
|
2615
|
+
row,
|
|
2616
|
+
TAB_LAST_CHUNK_STORED_AT_ALIAS,
|
|
2617
|
+
),
|
|
2618
|
+
};
|
|
2619
|
+
|
|
2620
|
+
const existing: Array<SessionReplayTabEndFacts> | undefined =
|
|
2621
|
+
tabsBySessionId.get(sessionId);
|
|
2622
|
+
|
|
2623
|
+
if (existing) {
|
|
2624
|
+
existing.push(tab);
|
|
2625
|
+
} else {
|
|
2626
|
+
tabsBySessionId.set(sessionId, [tab]);
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2630
|
+
for (const [sessionId, tabs] of tabsBySessionId) {
|
|
2631
|
+
if (hasSessionRecordingEnded(tabs, data.nowUnixMs)) {
|
|
2632
|
+
endedSessionIds.add(sessionId);
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2636
|
+
return endedSessionIds;
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2089
2639
|
/*
|
|
2090
2640
|
* The payload read. The only query in the system that names the
|
|
2091
2641
|
* `payload` column.
|
|
@@ -2263,14 +2813,28 @@ export default class SessionReplayReadService {
|
|
|
2263
2813
|
* fingerprint present only on a superseded row does not produce a false
|
|
2264
2814
|
* positive.
|
|
2265
2815
|
*
|
|
2266
|
-
*
|
|
2267
|
-
*
|
|
2268
|
-
*
|
|
2816
|
+
* Typed RUM and fully unscoped legacy lookups are windowed in WHERE for
|
|
2817
|
+
* partition pruning. Scoped non-RUM and ID-only type-unknown lookups apply
|
|
2818
|
+
* the window in QUALIFY: their instance-proven session ids must first be
|
|
2819
|
+
* checked across every retained application in the project so a duplicate
|
|
2820
|
+
* id cannot be hidden outside the caller's time or authorization scope.
|
|
2269
2821
|
*/
|
|
2270
2822
|
@CaptureSpan()
|
|
2271
2823
|
public static async getSessionsForException(data: {
|
|
2272
2824
|
projectId: ObjectID;
|
|
2273
2825
|
exceptionFingerprint: string;
|
|
2826
|
+
/*
|
|
2827
|
+
* Exception fingerprints are unique per primary entity, not per project.
|
|
2828
|
+
* Keep this optional for older callers, but exception pages should always
|
|
2829
|
+
* provide it so neither the live side index nor finalized headers can mix
|
|
2830
|
+
* identically fingerprinted groups from different services.
|
|
2831
|
+
*/
|
|
2832
|
+
primaryEntityId?: ObjectID | undefined;
|
|
2833
|
+
/*
|
|
2834
|
+
* Identifies the owning entity table. ID-only is accepted as a rolling
|
|
2835
|
+
* compatibility mode and uses the conservative scoped-unknown branch.
|
|
2836
|
+
*/
|
|
2837
|
+
primaryEntityType?: ServiceType | undefined;
|
|
2274
2838
|
/*
|
|
2275
2839
|
* null means "no label restriction". An EMPTY array means the caller
|
|
2276
2840
|
* can reach no applications at all and must get no rows - the two are
|
|
@@ -2284,6 +2848,20 @@ export default class SessionReplayReadService {
|
|
|
2284
2848
|
sessionId?: string | undefined;
|
|
2285
2849
|
limit: number;
|
|
2286
2850
|
}): Promise<Array<SessionReplayExceptionSession>> {
|
|
2851
|
+
const hasPrimaryEntityId: boolean = data.primaryEntityId !== undefined;
|
|
2852
|
+
const hasPrimaryEntityType: boolean = data.primaryEntityType !== undefined;
|
|
2853
|
+
|
|
2854
|
+
if (!hasPrimaryEntityId && hasPrimaryEntityType) {
|
|
2855
|
+
throw new BadDataException("primaryEntityId is required with its type");
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2858
|
+
if (
|
|
2859
|
+
data.primaryEntityType !== undefined &&
|
|
2860
|
+
!Object.values(ServiceType).includes(data.primaryEntityType)
|
|
2861
|
+
) {
|
|
2862
|
+
throw new BadDataException("primaryEntityType is not valid");
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2287
2865
|
if (
|
|
2288
2866
|
data.accessibleRumApplicationIds &&
|
|
2289
2867
|
data.accessibleRumApplicationIds.length === 0
|
|
@@ -2308,11 +2886,28 @@ export default class SessionReplayReadService {
|
|
|
2308
2886
|
await SessionReplayReadService.getSessionIdsForExceptionInstances({
|
|
2309
2887
|
projectId: data.projectId,
|
|
2310
2888
|
exceptionFingerprint: data.exceptionFingerprint,
|
|
2889
|
+
primaryEntityId: data.primaryEntityId,
|
|
2890
|
+
primaryEntityType: data.primaryEntityType,
|
|
2311
2891
|
startTime: startTime,
|
|
2312
2892
|
endTime: endTime,
|
|
2313
2893
|
sessionId: data.sessionId,
|
|
2314
2894
|
});
|
|
2315
2895
|
|
|
2896
|
+
const isScopedRumException: boolean =
|
|
2897
|
+
data.primaryEntityType === ServiceType.RealUserMonitor;
|
|
2898
|
+
const isScopedNonRumOrUnknownException: boolean =
|
|
2899
|
+
hasPrimaryEntityId && !isScopedRumException;
|
|
2900
|
+
|
|
2901
|
+
/*
|
|
2902
|
+
* A finalized replay header has only a flat fingerprint list. For a
|
|
2903
|
+
* non-RUM or legacy type-unknown entity that list cannot prove ownership,
|
|
2904
|
+
* so only the scoped instance side index may admit a session. Failure or
|
|
2905
|
+
* an empty lookup must therefore fail closed.
|
|
2906
|
+
*/
|
|
2907
|
+
if (isScopedNonRumOrUnknownException && instanceSessionIds.length === 0) {
|
|
2908
|
+
return [];
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2316
2911
|
const selectList: string = toSelectList([
|
|
2317
2912
|
{ alias: "aggStartTime", expression: argMaxDateTime("startTime") },
|
|
2318
2913
|
{ alias: "aggEndTime", expression: argMaxDateTime("endTime") },
|
|
@@ -2362,6 +2957,13 @@ export default class SessionReplayReadService {
|
|
|
2362
2957
|
|
|
2363
2958
|
statement.append(` ${selectList}`);
|
|
2364
2959
|
|
|
2960
|
+
if (isScopedNonRumOrUnknownException) {
|
|
2961
|
+
/* One grouped row per application makes this a cross-app collision count. */
|
|
2962
|
+
statement.append(
|
|
2963
|
+
", count() OVER (PARTITION BY sessionId) AS matchedApplicationCount",
|
|
2964
|
+
);
|
|
2965
|
+
}
|
|
2966
|
+
|
|
2365
2967
|
statement.append(SQL`
|
|
2366
2968
|
FROM ${AnalyticsTableName.RumSession}
|
|
2367
2969
|
WHERE projectId = ${{
|
|
@@ -2370,7 +2972,12 @@ export default class SessionReplayReadService {
|
|
|
2370
2972
|
}}
|
|
2371
2973
|
`);
|
|
2372
2974
|
|
|
2373
|
-
|
|
2975
|
+
/*
|
|
2976
|
+
* For non-RUM and legacy type-unknown exceptions, authorization belongs
|
|
2977
|
+
* in QUALIFY after the window has counted inaccessible applications too.
|
|
2978
|
+
* Applying it here would make an ambiguous id appear unique.
|
|
2979
|
+
*/
|
|
2980
|
+
if (!isScopedNonRumOrUnknownException && data.accessibleRumApplicationIds) {
|
|
2374
2981
|
statement.append(
|
|
2375
2982
|
SQL` AND rumApplicationId IN (${{
|
|
2376
2983
|
type: TableColumnType.ObjectID,
|
|
@@ -2379,15 +2986,17 @@ export default class SessionReplayReadService {
|
|
|
2379
2986
|
);
|
|
2380
2987
|
}
|
|
2381
2988
|
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2989
|
+
if (!isScopedNonRumOrUnknownException) {
|
|
2990
|
+
statement.append(
|
|
2991
|
+
SQL` AND startTime >= ${{
|
|
2992
|
+
type: TableColumnType.DateTime64,
|
|
2993
|
+
value: startTime,
|
|
2994
|
+
}} AND startTime <= ${{
|
|
2995
|
+
type: TableColumnType.DateTime64,
|
|
2996
|
+
value: endTime,
|
|
2997
|
+
}}`,
|
|
2998
|
+
);
|
|
2999
|
+
}
|
|
2391
3000
|
|
|
2392
3001
|
statement.append(RETENTION_FILTER);
|
|
2393
3002
|
|
|
@@ -2400,33 +3009,35 @@ export default class SessionReplayReadService {
|
|
|
2400
3009
|
);
|
|
2401
3010
|
}
|
|
2402
3011
|
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
3012
|
+
if (isScopedRumException && data.primaryEntityId) {
|
|
3013
|
+
/* Both finalized fingerprints and instance-proven ids stay in this RUM app. */
|
|
3014
|
+
statement.append(
|
|
3015
|
+
SQL` AND rumApplicationId = ${{
|
|
3016
|
+
type: TableColumnType.ObjectID,
|
|
3017
|
+
value: data.primaryEntityId,
|
|
3018
|
+
}}`,
|
|
3019
|
+
);
|
|
3020
|
+
}
|
|
3021
|
+
|
|
3022
|
+
statement.append(" AND (");
|
|
2409
3023
|
|
|
2410
|
-
if (
|
|
3024
|
+
if (isScopedNonRumOrUnknownException) {
|
|
2411
3025
|
statement.append(
|
|
2412
|
-
SQL`
|
|
3026
|
+
SQL`sessionId IN (${{
|
|
2413
3027
|
type: TableColumnType.Text,
|
|
2414
3028
|
value: new Includes(instanceSessionIds),
|
|
2415
3029
|
}})`,
|
|
2416
3030
|
);
|
|
3031
|
+
} else {
|
|
3032
|
+
statement.append(
|
|
3033
|
+
SQL`hasAny(exceptionFingerprints, [${{
|
|
3034
|
+
type: TableColumnType.Text,
|
|
3035
|
+
value: data.exceptionFingerprint,
|
|
3036
|
+
}}])`,
|
|
3037
|
+
);
|
|
2417
3038
|
}
|
|
2418
3039
|
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
statement.append(
|
|
2422
|
-
SQL` GROUP BY projectId, rumApplicationId, sessionId
|
|
2423
|
-
HAVING (hasAny(aggExceptionFingerprints, [${{
|
|
2424
|
-
type: TableColumnType.Text,
|
|
2425
|
-
value: data.exceptionFingerprint,
|
|
2426
|
-
}}])`,
|
|
2427
|
-
);
|
|
2428
|
-
|
|
2429
|
-
if (instanceSessionIds.length > 0) {
|
|
3040
|
+
if (!isScopedNonRumOrUnknownException && instanceSessionIds.length > 0) {
|
|
2430
3041
|
statement.append(
|
|
2431
3042
|
SQL` OR sessionId IN (${{
|
|
2432
3043
|
type: TableColumnType.Text,
|
|
@@ -2437,6 +3048,53 @@ export default class SessionReplayReadService {
|
|
|
2437
3048
|
|
|
2438
3049
|
statement.append(")");
|
|
2439
3050
|
|
|
3051
|
+
statement.append(" GROUP BY projectId, rumApplicationId, sessionId");
|
|
3052
|
+
|
|
3053
|
+
if (isScopedNonRumOrUnknownException) {
|
|
3054
|
+
/*
|
|
3055
|
+
* Windowing happens over every application before either the time
|
|
3056
|
+
* window or accessible-app filter is applied. QUALIFY also precedes
|
|
3057
|
+
* ORDER/LIMIT, so a second application can never be sorted away.
|
|
3058
|
+
*/
|
|
3059
|
+
statement.append(" QUALIFY matchedApplicationCount = 1");
|
|
3060
|
+
statement.append(
|
|
3061
|
+
SQL` AND aggStartTime >= ${{
|
|
3062
|
+
type: TableColumnType.BigNumber,
|
|
3063
|
+
value: startTime.getTime(),
|
|
3064
|
+
}} AND aggStartTime <= ${{
|
|
3065
|
+
type: TableColumnType.BigNumber,
|
|
3066
|
+
value: endTime.getTime(),
|
|
3067
|
+
}}`,
|
|
3068
|
+
);
|
|
3069
|
+
|
|
3070
|
+
if (data.accessibleRumApplicationIds) {
|
|
3071
|
+
statement.append(
|
|
3072
|
+
SQL` AND rumApplicationId IN (${{
|
|
3073
|
+
type: TableColumnType.ObjectID,
|
|
3074
|
+
value: new Includes(data.accessibleRumApplicationIds),
|
|
3075
|
+
}})`,
|
|
3076
|
+
);
|
|
3077
|
+
}
|
|
3078
|
+
} else {
|
|
3079
|
+
statement.append(" HAVING (");
|
|
3080
|
+
statement.append(
|
|
3081
|
+
SQL`hasAny(aggExceptionFingerprints, [${{
|
|
3082
|
+
type: TableColumnType.Text,
|
|
3083
|
+
value: data.exceptionFingerprint,
|
|
3084
|
+
}}])`,
|
|
3085
|
+
);
|
|
3086
|
+
if (instanceSessionIds.length > 0) {
|
|
3087
|
+
statement.append(
|
|
3088
|
+
SQL` OR sessionId IN (${{
|
|
3089
|
+
type: TableColumnType.Text,
|
|
3090
|
+
value: new Includes(instanceSessionIds),
|
|
3091
|
+
}})`,
|
|
3092
|
+
);
|
|
3093
|
+
}
|
|
3094
|
+
|
|
3095
|
+
statement.append(")");
|
|
3096
|
+
}
|
|
3097
|
+
|
|
2440
3098
|
statement.append(
|
|
2441
3099
|
SQL` ORDER BY aggStartTime DESC
|
|
2442
3100
|
LIMIT ${{
|
|
@@ -2452,7 +3110,21 @@ export default class SessionReplayReadService {
|
|
|
2452
3110
|
data?: Array<JSONObject>;
|
|
2453
3111
|
}>();
|
|
2454
3112
|
|
|
2455
|
-
|
|
3113
|
+
const responseRows: Array<JSONObject> = (response.data || []).filter(
|
|
3114
|
+
(row: JSONObject): boolean => {
|
|
3115
|
+
/*
|
|
3116
|
+
* QUALIFY is authoritative. Its count was computed over every app
|
|
3117
|
+
* before ORDER/LIMIT, so retaining only count=1 is also a fail-closed
|
|
3118
|
+
* guard if a changed driver ever returns a row that should not survive.
|
|
3119
|
+
*/
|
|
3120
|
+
return (
|
|
3121
|
+
!isScopedNonRumOrUnknownException ||
|
|
3122
|
+
readNumber(row, "matchedApplicationCount") === 1
|
|
3123
|
+
);
|
|
3124
|
+
},
|
|
3125
|
+
);
|
|
3126
|
+
|
|
3127
|
+
return responseRows.map(
|
|
2456
3128
|
(row: JSONObject): SessionReplayExceptionSession => {
|
|
2457
3129
|
return {
|
|
2458
3130
|
sessionId: readString(row, "sessionId"),
|
|
@@ -2484,9 +3156,10 @@ export default class SessionReplayReadService {
|
|
|
2484
3156
|
* session, so a session that started inside the window threw inside
|
|
2485
3157
|
* [startTime, endTime + max session length].
|
|
2486
3158
|
*
|
|
2487
|
-
* Best-effort
|
|
2488
|
-
* a failure
|
|
2489
|
-
*
|
|
3159
|
+
* Best-effort for fully unscoped legacy and typed RUM lookups: there it only
|
|
3160
|
+
* ADDS live sessions, so a failure degrades to finalized headers. Scoped
|
|
3161
|
+
* non-RUM and ID-only lookups rely on it as their sole entity-ownership
|
|
3162
|
+
* proof and therefore fail closed.
|
|
2490
3163
|
*
|
|
2491
3164
|
* A caller-pinned sessionId narrows the lookup rather than bypassing it,
|
|
2492
3165
|
* so the pin can never assert that a session threw something the
|
|
@@ -2495,6 +3168,8 @@ export default class SessionReplayReadService {
|
|
|
2495
3168
|
private static async getSessionIdsForExceptionInstances(data: {
|
|
2496
3169
|
projectId: ObjectID;
|
|
2497
3170
|
exceptionFingerprint: string;
|
|
3171
|
+
primaryEntityId?: ObjectID | undefined;
|
|
3172
|
+
primaryEntityType?: ServiceType | undefined;
|
|
2498
3173
|
startTime: Date;
|
|
2499
3174
|
endTime: Date;
|
|
2500
3175
|
sessionId?: string | undefined;
|
|
@@ -2523,6 +3198,32 @@ export default class SessionReplayReadService {
|
|
|
2523
3198
|
}}
|
|
2524
3199
|
`;
|
|
2525
3200
|
|
|
3201
|
+
if (data.primaryEntityId) {
|
|
3202
|
+
statement.append(
|
|
3203
|
+
SQL` AND primaryEntityId = ${{
|
|
3204
|
+
type: TableColumnType.ObjectID,
|
|
3205
|
+
value: data.primaryEntityId,
|
|
3206
|
+
}}`,
|
|
3207
|
+
);
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3210
|
+
if (data.primaryEntityType === ServiceType.OpenTelemetry) {
|
|
3211
|
+
/* NULL/empty is the historical discriminator for an OTel service. */
|
|
3212
|
+
statement.append(
|
|
3213
|
+
SQL` AND (ifNull(primaryEntityType, '') = '' OR primaryEntityType = ${{
|
|
3214
|
+
type: TableColumnType.Text,
|
|
3215
|
+
value: ServiceType.OpenTelemetry as string,
|
|
3216
|
+
}})`,
|
|
3217
|
+
);
|
|
3218
|
+
} else if (data.primaryEntityType) {
|
|
3219
|
+
statement.append(
|
|
3220
|
+
SQL` AND primaryEntityType = ${{
|
|
3221
|
+
type: TableColumnType.Text,
|
|
3222
|
+
value: data.primaryEntityType as string,
|
|
3223
|
+
}}`,
|
|
3224
|
+
);
|
|
3225
|
+
}
|
|
3226
|
+
|
|
2526
3227
|
/*
|
|
2527
3228
|
* A pinned sessionId narrows this lookup; it does NOT replace it.
|
|
2528
3229
|
*
|
|
@@ -2572,7 +3273,7 @@ export default class SessionReplayReadService {
|
|
|
2572
3273
|
});
|
|
2573
3274
|
} catch (err: unknown) {
|
|
2574
3275
|
logger.warn(
|
|
2575
|
-
"SessionReplayReadService: could not look up exception instances by session;
|
|
3276
|
+
"SessionReplayReadService: could not look up exception instances by session; scoped non-RUM lookups fail closed and other lookups answer from finalized headers only",
|
|
2576
3277
|
);
|
|
2577
3278
|
logger.warn(err);
|
|
2578
3279
|
|