@oneuptime/common 10.8.2 → 11.0.0
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/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.ts +16 -18
- package/Models/AnalyticsModels/AuditLog.ts +3 -1
- package/Models/AnalyticsModels/ExceptionInstance.ts +200 -82
- package/Models/AnalyticsModels/Index.ts +7 -2
- package/Models/AnalyticsModels/Log.ts +197 -81
- package/Models/AnalyticsModels/Metric.ts +199 -86
- package/Models/AnalyticsModels/MetricBaselineHourly.ts +44 -25
- package/Models/AnalyticsModels/MetricItemAggMV1m.ts +23 -20
- package/Models/AnalyticsModels/{MetricItemAggMV1mByHost.ts → MetricItemAggMV1mByHostV2.ts} +58 -47
- package/Models/AnalyticsModels/MonitorLog.ts +5 -1
- package/Models/AnalyticsModels/Profile.ts +206 -85
- package/Models/AnalyticsModels/ProfileSample.ts +196 -83
- package/Models/AnalyticsModels/Span.ts +218 -85
- package/Models/DatabaseModels/Index.ts +4 -0
- package/Models/DatabaseModels/Service.ts +29 -0
- package/Models/DatabaseModels/TelemetryEntity.ts +393 -0
- package/Models/DatabaseModels/TelemetryEntityRelationship.ts +294 -0
- package/Models/DatabaseModels/TelemetryException.ts +10 -10
- package/Models/DatabaseModels/TelemetryUsageBilling.ts +5 -5
- package/Server/API/AIAgentDataAPI.ts +13 -12
- package/Server/API/DashboardAPI.ts +2 -2
- package/Server/API/TelemetryAPI.ts +656 -141
- package/Server/API/TelemetryExceptionAPI.ts +2 -2
- package/Server/Infrastructure/ClickhouseConfig.ts +12 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781100000001-RenameTelemetryServiceIdToPrimaryEntityId.ts +48 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781200000000-AddTelemetryEntityTable.ts +70 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781200000001-AddTelemetryEntityRelationshipTable.ts +57 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781250074195-MigrationName.ts +207 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781300000000-AddTelemetryEntityLabels.ts +24 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781400000000-AddServiceTelemetrySdkLanguage.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Infrastructure/Queue.ts +36 -3
- package/Server/Middleware/TelemetryIngest.ts +27 -22
- package/Server/Services/AlertService.ts +9 -9
- package/Server/Services/AnalyticsDatabaseService.ts +204 -35
- package/Server/Services/ExceptionAggregationService.ts +41 -18
- package/Server/Services/HostService.ts +2 -1
- package/Server/Services/IncidentService.ts +19 -19
- package/Server/Services/Index.ts +6 -2
- package/Server/Services/LogAggregationService.ts +116 -43
- package/Server/Services/MetricAggregationService.ts +29 -14
- package/Server/Services/MetricBaselineService.ts +34 -34
- package/Server/Services/MetricItemAggMV1mByHostV2Service.ts +30 -0
- package/Server/Services/MetricService.ts +119 -31
- package/Server/Services/OpenTelemetryIngestService.ts +186 -50
- package/Server/Services/ProfileAggregationService.ts +904 -126
- package/Server/Services/ServiceService.ts +6 -0
- package/Server/Services/SpanService.ts +274 -14
- package/Server/Services/TelemetryEntityRelationshipService.ts +71 -0
- package/Server/Services/TelemetryEntityService.ts +246 -0
- package/Server/Services/TelemetryExceptionService.ts +27 -23
- package/Server/Services/TelemetryUsageBillingService.ts +38 -31
- package/Server/Services/TraceAggregationService.ts +875 -43
- package/Server/Types/AnalyticsDatabase/ModelPermission.ts +43 -2
- package/Server/Types/Database/Permissions/AccessControlPermission.ts +47 -2
- package/Server/Types/Database/Permissions/BasePermission.ts +37 -1
- package/Server/Types/Database/Permissions/OwnedScopePermission.ts +21 -3
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +1 -0
- package/Server/Types/Database/QueryHelper.ts +41 -0
- package/Server/Utils/Alert/AlertPrivacyFilter.ts +9 -2
- package/Server/Utils/AlertEpisode/AlertEpisodePrivacyFilter.ts +9 -2
- package/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.ts +95 -0
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +133 -0
- package/Server/Utils/Incident/IncidentPrivacyFilter.ts +9 -2
- package/Server/Utils/IncidentEpisode/IncidentEpisodePrivacyFilter.ts +9 -2
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +1 -1
- package/Server/Utils/Monitor/MonitorLogUtil.ts +1 -2
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +3 -4
- package/Server/Utils/PrivacyFilterUtil.ts +72 -0
- package/Server/Utils/Profile/PprofEncoder.ts +135 -11
- package/Server/Utils/Telemetry/EntityRegistry.ts +316 -0
- package/Server/Utils/Telemetry/ResourceFacetResolver.ts +5 -0
- package/Server/Utils/Telemetry/TelemetryEntity.ts +783 -0
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +79 -4
- package/Tests/Server/Services/LogAggregationService.test.ts +7 -2
- package/Tests/Server/Services/ProfileAggregationService.test.ts +280 -0
- package/Tests/Server/Services/ProfileBreakdown.test.ts +161 -0
- package/Tests/Server/Services/ProfileFunctionFocus.test.ts +349 -0
- package/Tests/Server/Services/TelemetryAttributeService.test.ts +1 -1
- package/Tests/Server/Services/TraceAggregationService.test.ts +403 -0
- package/Tests/Server/Types/AnalyticsDatabase/ModelPermissionOwnedScope.test.ts +114 -0
- package/Tests/Server/Types/Database/Permissions/AccessControlPermission.test.ts +189 -0
- package/Tests/Server/Types/Database/Permissions/BasePermission.test.ts +118 -0
- package/Tests/Server/Types/Database/Permissions/OwnedScopePermission.test.ts +159 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +275 -8
- package/Tests/Server/Utils/PrivacyFilterUtil.test.ts +177 -0
- package/Tests/Server/Utils/Profile/PprofEncoder.test.ts +276 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +761 -0
- package/Tests/Types/Monitor/MonitorStepEntityScope.test.ts +275 -0
- package/Tests/Types/Text.test.ts +52 -0
- package/Tests/Utils/Telemetry/EntityKey.test.ts +150 -0
- package/Tests/Utils/Telemetry/EntityKeySqlParity.test.ts +40 -0
- package/Tests/Utils/Telemetry/EntityRelationship.test.ts +150 -0
- package/Tests/Utils/UUID.test.ts +47 -0
- package/Types/AnalyticsDatabase/AnalyticsTableName.ts +14 -9
- package/Types/AnalyticsDatabase/TableColumnType.ts +1 -0
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.ts +37 -0
- package/Types/Dashboard/DashboardTemplates.ts +4 -5
- package/Types/Log/LogQueryParser.ts +2 -2
- package/Types/Log/LogQueryToFilter.ts +2 -2
- package/Types/Monitor/MonitorStepExceptionMonitor.ts +19 -1
- package/Types/Monitor/MonitorStepLogMonitor.ts +20 -1
- package/Types/Monitor/MonitorStepMetricMonitor.ts +27 -0
- package/Types/Monitor/MonitorStepProfileMonitor.ts +19 -1
- package/Types/Monitor/MonitorStepTraceMonitor.ts +18 -1
- package/Types/Monitor/MonitorType.ts +8 -1
- package/Types/ObjectID.ts +10 -0
- package/Types/Telemetry/EntityRelationshipType.ts +31 -0
- package/Types/Telemetry/EntityType.ts +33 -0
- package/Types/Telemetry/TelemetrySavedViewState.ts +2 -0
- package/Types/Text.ts +34 -0
- package/Types/Trace/TraceAggregationType.ts +1 -0
- package/Types/Trace/TraceRecordingRuleDefinition.ts +74 -0
- package/UI/Components/LogsViewer/LogsViewer.tsx +12 -9
- package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +10 -9
- package/UI/Components/LogsViewer/components/LogSearchBar.tsx +1 -1
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +2 -2
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +4 -4
- package/UI/Components/LogsViewer/components/LogsTable.tsx +5 -3
- package/UI/Components/Navbar/NavBarMenuModal.tsx +81 -44
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +33 -10
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +18 -3
- package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +91 -68
- package/UI/Components/TelemetryViewer/components/TelemetryHistogramTooltip.tsx +9 -2
- package/UI/Utils/LogExport.ts +2 -2
- package/UI/Utils/TelemetryService.ts +20 -20
- package/Utils/Dashboard/Components/DashboardTraceChartComponent.ts +134 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/Utils/Telemetry/EntityKey.ts +151 -0
- package/Utils/Telemetry/EntityRelationship.ts +113 -0
- package/Utils/Traces/CriticalPath.ts +7 -7
- package/Utils/UUID.ts +57 -0
- package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js +14 -13
- package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/AuditLog.js +2 -1
- package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +125 -22
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Index.js +7 -2
- package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Log.js +123 -22
- package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Metric.js +125 -27
- package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricBaselineHourly.js +38 -21
- package/build/dist/Models/AnalyticsModels/MetricBaselineHourly.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1m.js +17 -16
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1m.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/{MetricItemAggMV1mByHost.js → MetricItemAggMV1mByHostV2.js} +54 -42
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByHostV2.js.map +1 -0
- package/build/dist/Models/AnalyticsModels/MonitorLog.js +4 -1
- package/build/dist/Models/AnalyticsModels/MonitorLog.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Profile.js +132 -26
- package/build/dist/Models/AnalyticsModels/Profile.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ProfileSample.js +121 -23
- package/build/dist/Models/AnalyticsModels/ProfileSample.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Span.js +144 -26
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Service.js +30 -0
- package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryEntity.js +419 -0
- package/build/dist/Models/DatabaseModels/TelemetryEntity.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js +317 -0
- package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js +12 -12
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryUsageBilling.js +7 -7
- package/build/dist/Models/DatabaseModels/TelemetryUsageBilling.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +14 -13
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +2 -2
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +425 -129
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryExceptionAPI.js +2 -2
- package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js +12 -0
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781100000001-RenameTelemetryServiceIdToPrimaryEntityId.js +29 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781100000001-RenameTelemetryServiceIdToPrimaryEntityId.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781200000000-AddTelemetryEntityTable.js +38 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781200000000-AddTelemetryEntityTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781200000001-AddTelemetryEntityRelationshipTable.js +33 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781200000001-AddTelemetryEntityRelationshipTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781250074195-MigrationName.js +78 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781250074195-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781300000000-AddTelemetryEntityLabels.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781300000000-AddTelemetryEntityLabels.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781400000000-AddServiceTelemetrySdkLanguage.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781400000000-AddServiceTelemetrySdkLanguage.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Queue.js +14 -3
- package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +16 -18
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +9 -9
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +115 -40
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/ExceptionAggregationService.js +38 -18
- package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +2 -1
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +19 -19
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +6 -2
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +100 -42
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricAggregationService.js +27 -14
- package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricBaselineService.js +28 -28
- package/build/dist/Server/Services/MetricBaselineService.js.map +1 -1
- package/build/dist/Server/Services/MetricItemAggMV1mByHostV2Service.js +28 -0
- package/build/dist/Server/Services/MetricItemAggMV1mByHostV2Service.js.map +1 -0
- package/build/dist/Server/Services/MetricService.js +116 -31
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +103 -36
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/ProfileAggregationService.js +613 -105
- package/build/dist/Server/Services/ProfileAggregationService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +9 -5
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/SpanService.js +217 -15
- package/build/dist/Server/Services/SpanService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +72 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -0
- package/build/dist/Server/Services/TelemetryEntityService.js +201 -0
- package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -0
- package/build/dist/Server/Services/TelemetryExceptionService.js +18 -18
- package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +27 -21
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +568 -43
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +38 -2
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js +36 -2
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js +25 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js +17 -3
- package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +1 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +31 -0
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/Alert/AlertPrivacyFilter.js +3 -2
- package/build/dist/Server/Utils/Alert/AlertPrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/AlertEpisode/AlertEpisodePrivacyFilter.js +3 -2
- package/build/dist/Server/Utils/AlertEpisode/AlertEpisodePrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js +46 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js.map +1 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +97 -3
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Incident/IncidentPrivacyFilter.js +3 -2
- package/build/dist/Server/Utils/Incident/IncidentPrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/IncidentEpisode/IncidentEpisodePrivacyFilter.js +3 -2
- package/build/dist/Server/Utils/IncidentEpisode/IncidentEpisodePrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js +1 -2
- package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +3 -4
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/PrivacyFilterUtil.js +47 -0
- package/build/dist/Server/Utils/PrivacyFilterUtil.js.map +1 -0
- package/build/dist/Server/Utils/Profile/PprofEncoder.js +132 -4
- package/build/dist/Server/Utils/Profile/PprofEncoder.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +228 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +5 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +569 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +14 -9
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
- package/build/dist/Types/AnalyticsDatabase/TableColumnType.js +1 -0
- package/build/dist/Types/AnalyticsDatabase/TableColumnType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +4 -5
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Log/LogQueryParser.js +2 -2
- package/build/dist/Types/Log/LogQueryParser.js.map +1 -1
- package/build/dist/Types/Log/LogQueryToFilter.js +1 -1
- package/build/dist/Types/Log/LogQueryToFilter.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js +9 -1
- package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepLogMonitor.js +9 -1
- package/build/dist/Types/Monitor/MonitorStepLogMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +13 -0
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepProfileMonitor.js +9 -1
- package/build/dist/Types/Monitor/MonitorStepProfileMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepTraceMonitor.js +9 -1
- package/build/dist/Types/Monitor/MonitorStepTraceMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +8 -1
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/ObjectID.js +9 -0
- package/build/dist/Types/ObjectID.js.map +1 -1
- package/build/dist/Types/Telemetry/EntityRelationshipType.js +32 -0
- package/build/dist/Types/Telemetry/EntityRelationshipType.js.map +1 -0
- package/build/dist/Types/Telemetry/EntityType.js +34 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -0
- package/build/dist/Types/Text.js +32 -1
- package/build/dist/Types/Text.js.map +1 -1
- package/build/dist/Types/Trace/TraceAggregationType.js +1 -0
- package/build/dist/Types/Trace/TraceAggregationType.js.map +1 -1
- package/build/dist/Types/Trace/TraceRecordingRuleDefinition.js +50 -1
- package/build/dist/Types/Trace/TraceRecordingRuleDefinition.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +10 -9
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +8 -8
- package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogSearchBar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogSearchBar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +2 -2
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +4 -4
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +3 -3
- package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +43 -30
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +6 -2
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +14 -3
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +18 -10
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogramTooltip.js +4 -2
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogramTooltip.js.map +1 -1
- package/build/dist/UI/Utils/LogExport.js +2 -2
- package/build/dist/UI/Utils/LogExport.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +16 -16
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardTraceChartComponent.js +110 -0
- package/build/dist/Utils/Dashboard/Components/DashboardTraceChartComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/Telemetry/EntityKey.js +115 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityRelationship.js +71 -0
- package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -0
- package/build/dist/Utils/Traces/CriticalPath.js +5 -5
- package/build/dist/Utils/Traces/CriticalPath.js.map +1 -1
- package/build/dist/Utils/UUID.js +50 -0
- package/build/dist/Utils/UUID.js.map +1 -1
- package/package.json +2 -1
- package/tsconfig.json +10 -1
- package/Server/Services/MetricItemAggMV1mByHostService.ts +0 -30
- package/Types/Profile/ProfileMetricType.ts +0 -16
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByHost.js.map +0 -1
- package/build/dist/Server/Services/MetricItemAggMV1mByHostService.js +0 -28
- package/build/dist/Server/Services/MetricItemAggMV1mByHostService.js.map +0 -1
- package/build/dist/Tests/MockType.js +0 -5
- package/build/dist/Tests/MockType.js.map +0 -1
- package/build/dist/Tests/Models/AnalyticsModels/Log.test.js +0 -12
- package/build/dist/Tests/Models/AnalyticsModels/Log.test.js.map +0 -1
- package/build/dist/Tests/Models/File.test.js +0 -10
- package/build/dist/Tests/Models/File.test.js.map +0 -1
- package/build/dist/Tests/Server/API/BaseAPI.test.js +0 -590
- package/build/dist/Tests/Server/API/BaseAPI.test.js.map +0 -1
- package/build/dist/Tests/Server/API/Helpers.js +0 -27
- package/build/dist/Tests/Server/API/Helpers.js.map +0 -1
- package/build/dist/Tests/Server/API/ProbeAPI.test.js +0 -84
- package/build/dist/Tests/Server/API/ProbeAPI.test.js.map +0 -1
- package/build/dist/Tests/Server/API/ProjectAPI.test.js +0 -170
- package/build/dist/Tests/Server/API/ProjectAPI.test.js.map +0 -1
- package/build/dist/Tests/Server/API/UserSmsApi.test.js +0 -177
- package/build/dist/Tests/Server/API/UserSmsApi.test.js.map +0 -1
- package/build/dist/Tests/Server/Middleware/BearerTokenAuthorization.test.js +0 -63
- package/build/dist/Tests/Server/Middleware/BearerTokenAuthorization.test.js.map +0 -1
- package/build/dist/Tests/Server/Middleware/ClusterKeyAuthorization.test.js +0 -58
- package/build/dist/Tests/Server/Middleware/ClusterKeyAuthorization.test.js.map +0 -1
- package/build/dist/Tests/Server/Middleware/NotificationMiddleware.test.js +0 -101
- package/build/dist/Tests/Server/Middleware/NotificationMiddleware.test.js.map +0 -1
- package/build/dist/Tests/Server/Middleware/ProjectAuthorization.test.js +0 -160
- package/build/dist/Tests/Server/Middleware/ProjectAuthorization.test.js.map +0 -1
- package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js +0 -410
- package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/AlertEpisodeMemberService.test.js +0 -165
- package/build/dist/Tests/Server/Services/AlertEpisodeMemberService.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/AlertEpisodeService.test.js +0 -193
- package/build/dist/Tests/Server/Services/AlertEpisodeService.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/AlertGroupingEngineService.test.js +0 -435
- package/build/dist/Tests/Server/Services/AlertGroupingEngineService.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/AlertGroupingRuleService.test.js +0 -320
- package/build/dist/Tests/Server/Services/AlertGroupingRuleService.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/AnalyticsDatabaseService.test.js +0 -266
- package/build/dist/Tests/Server/Services/AnalyticsDatabaseService.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/BillingService.test.js +0 -910
- package/build/dist/Tests/Server/Services/BillingService.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/LogAggregationService.test.js +0 -75
- package/build/dist/Tests/Server/Services/LogAggregationService.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/ProbeService.test.js +0 -127
- package/build/dist/Tests/Server/Services/ProbeService.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/ScheduledMaintenanceService.test.js +0 -114
- package/build/dist/Tests/Server/Services/ScheduledMaintenanceService.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/TeamMemberService.test.js +0 -106
- package/build/dist/Tests/Server/Services/TeamMemberService.test.js.map +0 -1
- package/build/dist/Tests/Server/Services/TelemetryAttributeService.test.js +0 -50
- package/build/dist/Tests/Server/Services/TelemetryAttributeService.test.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Init.js +0 -4
- package/build/dist/Tests/Server/TestingUtils/Init.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Postgres/TestDataSourceOptions.js +0 -9
- package/build/dist/Tests/Server/TestingUtils/Postgres/TestDataSourceOptions.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Redis/TestRedisOptions.js +0 -16
- package/build/dist/Tests/Server/TestingUtils/Redis/TestRedisOptions.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Services/BillingServiceHelper.js +0 -125
- package/build/dist/Tests/Server/TestingUtils/Services/BillingServiceHelper.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Services/ProjectServiceHelper.js +0 -39
- package/build/dist/Tests/Server/TestingUtils/Services/ProjectServiceHelper.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Services/ScheduledMaintenanceServiceHelper.js +0 -20
- package/build/dist/Tests/Server/TestingUtils/Services/ScheduledMaintenanceServiceHelper.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Services/ScheduledMaintenanceStateServiceHelper.js +0 -31
- package/build/dist/Tests/Server/TestingUtils/Services/ScheduledMaintenanceStateServiceHelper.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Services/TeamMemberServiceHelper.js +0 -14
- package/build/dist/Tests/Server/TestingUtils/Services/TeamMemberServiceHelper.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Services/TeamServiceHelper.js +0 -21
- package/build/dist/Tests/Server/TestingUtils/Services/TeamServiceHelper.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Services/Types.js +0 -2
- package/build/dist/Tests/Server/TestingUtils/Services/Types.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/Services/UserServiceHelper.js +0 -37
- package/build/dist/Tests/Server/TestingUtils/Services/UserServiceHelper.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/__mocks__/Stripe.mock.js +0 -13
- package/build/dist/Tests/Server/TestingUtils/__mocks__/Stripe.mock.js.map +0 -1
- package/build/dist/Tests/Server/TestingUtils/__mocks__/TestDatabase.mock.js +0 -22
- package/build/dist/Tests/Server/TestingUtils/__mocks__/TestDatabase.mock.js.map +0 -1
- package/build/dist/Tests/Server/Types/Domain.test.js +0 -78
- package/build/dist/Tests/Server/Types/Domain.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/AnalyticsDatabase/Statement.test.js +0 -94
- package/build/dist/Tests/Server/Utils/AnalyticsDatabase/Statement.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js +0 -459
- package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/Cookie.test.js +0 -83
- package/build/dist/Tests/Server/Utils/Cookie.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/CronTab.test.js +0 -29
- package/build/dist/Tests/Server/Utils/CronTab.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/JsonToCsv.test.js +0 -114
- package/build/dist/Tests/Server/Utils/JsonToCsv.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.js +0 -606
- package/build/dist/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.js +0 -255
- package/build/dist/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.js +0 -142
- package/build/dist/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/StatusPageResource.test.js +0 -122
- package/build/dist/Tests/Server/Utils/StatusPageResource.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.js +0 -0
- package/build/dist/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.js.map +0 -1
- package/build/dist/Tests/Server/Utils/VM/VMAPI.test.js +0 -205
- package/build/dist/Tests/Server/Utils/VM/VMAPI.test.js.map +0 -1
- package/build/dist/Tests/Spy.js +0 -4
- package/build/dist/Tests/Spy.js.map +0 -1
- package/build/dist/Tests/Types/API/ErrorResponse.test.js +0 -13
- package/build/dist/Tests/Types/API/ErrorResponse.test.js.map +0 -1
- package/build/dist/Tests/Types/API/HTTPErrorResponse.test.js +0 -33
- package/build/dist/Tests/Types/API/HTTPErrorResponse.test.js.map +0 -1
- package/build/dist/Tests/Types/API/HTTPMethod.test.js +0 -16
- package/build/dist/Tests/Types/API/HTTPMethod.test.js.map +0 -1
- package/build/dist/Tests/Types/API/Headers.test.js +0 -14
- package/build/dist/Tests/Types/API/Headers.test.js.map +0 -1
- package/build/dist/Tests/Types/API/Hostname.test.js +0 -22
- package/build/dist/Tests/Types/API/Hostname.test.js.map +0 -1
- package/build/dist/Tests/Types/API/Protocal.test.js +0 -19
- package/build/dist/Tests/Types/API/Protocal.test.js.map +0 -1
- package/build/dist/Tests/Types/API/Response.test.js +0 -14
- package/build/dist/Tests/Types/API/Response.test.js.map +0 -1
- package/build/dist/Tests/Types/API/ResponseType.test.js +0 -13
- package/build/dist/Tests/Types/API/ResponseType.test.js.map +0 -1
- package/build/dist/Tests/Types/API/Route.test.js +0 -30
- package/build/dist/Tests/Types/API/Route.test.js.map +0 -1
- package/build/dist/Tests/Types/API/StatusCode.test.js +0 -26
- package/build/dist/Tests/Types/API/StatusCode.test.js.map +0 -1
- package/build/dist/Tests/Types/API/URL.test.js +0 -33
- package/build/dist/Tests/Types/API/URL.test.js.map +0 -1
- package/build/dist/Tests/Types/Alerts/AlertEventType.test.js +0 -34
- package/build/dist/Tests/Types/Alerts/AlertEventType.test.js.map +0 -1
- package/build/dist/Tests/Types/Alerts/AlertType.test.js +0 -19
- package/build/dist/Tests/Types/Alerts/AlertType.test.js.map +0 -1
- package/build/dist/Tests/Types/AppEnvironment.test.js +0 -13
- package/build/dist/Tests/Types/AppEnvironment.test.js.map +0 -1
- package/build/dist/Tests/Types/ApplicationLog/ApplicationLogType.test.js +0 -13
- package/build/dist/Tests/Types/ApplicationLog/ApplicationLogType.test.js.map +0 -1
- package/build/dist/Tests/Types/ArrayUtil.test.js +0 -71
- package/build/dist/Tests/Types/ArrayUtil.test.js.map +0 -1
- package/build/dist/Tests/Types/Billing/SubscriptionPlan.test.js +0 -181
- package/build/dist/Tests/Types/Billing/SubscriptionPlan.test.js.map +0 -1
- package/build/dist/Tests/Types/BrandColors.test.js +0 -124
- package/build/dist/Tests/Types/BrandColors.test.js.map +0 -1
- package/build/dist/Tests/Types/Char.test.js +0 -82
- package/build/dist/Tests/Types/Char.test.js.map +0 -1
- package/build/dist/Tests/Types/Code/CodeType.test.js +0 -13
- package/build/dist/Tests/Types/Code/CodeType.test.js.map +0 -1
- package/build/dist/Tests/Types/Color.test.js +0 -44
- package/build/dist/Tests/Types/Color.test.js.map +0 -1
- package/build/dist/Tests/Types/Company/CompanySize.test.js +0 -20
- package/build/dist/Tests/Types/Company/CompanySize.test.js.map +0 -1
- package/build/dist/Tests/Types/Company/JobRole.test.js +0 -22
- package/build/dist/Tests/Types/Company/JobRole.test.js.map +0 -1
- package/build/dist/Tests/Types/Countries.test.js +0 -249
- package/build/dist/Tests/Types/Countries.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/ColumnLength.test.js +0 -43
- package/build/dist/Tests/Types/Database/ColumnLength.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/ColumnType.test.js +0 -79
- package/build/dist/Tests/Types/Database/ColumnType.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/Columns.test.js +0 -20
- package/build/dist/Tests/Types/Database/Columns.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/CompareBase.test.js +0 -37
- package/build/dist/Tests/Types/Database/CompareBase.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/Date.test.js +0 -62
- package/build/dist/Tests/Types/Database/Date.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/EqualTo.test.js +0 -65
- package/build/dist/Tests/Types/Database/EqualTo.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/EqualToOrNull.test.js +0 -62
- package/build/dist/Tests/Types/Database/EqualToOrNull.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/InBetween.test.js +0 -72
- package/build/dist/Tests/Types/Database/InBetween.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/LimitMax.test.js +0 -18
- package/build/dist/Tests/Types/Database/LimitMax.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/NotEqual.test.js +0 -19
- package/build/dist/Tests/Types/Database/NotEqual.test.js.map +0 -1
- package/build/dist/Tests/Types/Database/Search.test.js +0 -10
- package/build/dist/Tests/Types/Database/Search.test.js.map +0 -1
- package/build/dist/Tests/Types/DatabaseType.test.js +0 -7
- package/build/dist/Tests/Types/DatabaseType.test.js.map +0 -1
- package/build/dist/Tests/Types/Date.test.js +0 -194
- package/build/dist/Tests/Types/Date.test.js.map +0 -1
- package/build/dist/Tests/Types/Dictionary.test.js +0 -25
- package/build/dist/Tests/Types/Dictionary.test.js.map +0 -1
- package/build/dist/Tests/Types/Domain.test.js +0 -54
- package/build/dist/Tests/Types/Domain.test.js.map +0 -1
- package/build/dist/Tests/Types/Email/Email.test.js +0 -51
- package/build/dist/Tests/Types/Email/Email.test.js.map +0 -1
- package/build/dist/Tests/Types/EmailWithName.test.js +0 -36
- package/build/dist/Tests/Types/EmailWithName.test.js.map +0 -1
- package/build/dist/Tests/Types/EncryptionAlgorithm.test.js +0 -7
- package/build/dist/Tests/Types/EncryptionAlgorithm.test.js.map +0 -1
- package/build/dist/Tests/Types/Exception/ApiException.test.js +0 -10
- package/build/dist/Tests/Types/Exception/ApiException.test.js.map +0 -1
- package/build/dist/Tests/Types/Exception/BadDataException.test.js +0 -12
- package/build/dist/Tests/Types/Exception/BadDataException.test.js.map +0 -1
- package/build/dist/Tests/Types/Exception/BadOperationException.test.js +0 -10
- package/build/dist/Tests/Types/Exception/BadOperationException.test.js.map +0 -1
- package/build/dist/Tests/Types/Exception/BadRequestException.test.js +0 -12
- package/build/dist/Tests/Types/Exception/BadRequestException.test.js.map +0 -1
- package/build/dist/Tests/Types/Exception/DatabaseNotConnectedException.test.js +0 -10
- package/build/dist/Tests/Types/Exception/DatabaseNotConnectedException.test.js.map +0 -1
- package/build/dist/Tests/Types/Exception/Exception.test.js +0 -15
- package/build/dist/Tests/Types/Exception/Exception.test.js.map +0 -1
- package/build/dist/Tests/Types/Exception/NotImplementedException.test.js +0 -12
- package/build/dist/Tests/Types/Exception/NotImplementedException.test.js.map +0 -1
- package/build/dist/Tests/Types/File.test.js +0 -22
- package/build/dist/Tests/Types/File.test.js.map +0 -1
- package/build/dist/Tests/Types/HashedString.test.js +0 -51
- package/build/dist/Tests/Types/HashedString.test.js.map +0 -1
- package/build/dist/Tests/Types/Html.test.js +0 -8
- package/build/dist/Tests/Types/Html.test.js.map +0 -1
- package/build/dist/Tests/Types/IP/IP.test.js +0 -65
- package/build/dist/Tests/Types/IP/IP.test.js.map +0 -1
- package/build/dist/Tests/Types/IP/IPType.test.js +0 -10
- package/build/dist/Tests/Types/IP/IPType.test.js.map +0 -1
- package/build/dist/Tests/Types/IP/IPv4.test.js +0 -17
- package/build/dist/Tests/Types/IP/IPv4.test.js.map +0 -1
- package/build/dist/Tests/Types/IP/IPv6.test.js +0 -17
- package/build/dist/Tests/Types/IP/IPv6.test.js.map +0 -1
- package/build/dist/Tests/Types/JSON.test.js +0 -37
- package/build/dist/Tests/Types/JSON.test.js.map +0 -1
- package/build/dist/Tests/Types/JSONFunctions.test.js +0 -38
- package/build/dist/Tests/Types/JSONFunctions.test.js.map +0 -1
- package/build/dist/Tests/Types/ListData.test.js +0 -34
- package/build/dist/Tests/Types/ListData.test.js.map +0 -1
- package/build/dist/Tests/Types/Monitor/KubernetesAlertTemplates.test.js +0 -121
- package/build/dist/Tests/Types/Monitor/KubernetesAlertTemplates.test.js.map +0 -1
- package/build/dist/Tests/Types/Name.test.js +0 -26
- package/build/dist/Tests/Types/Name.test.js.map +0 -1
- package/build/dist/Tests/Types/ObjectID.test.js +0 -12
- package/build/dist/Tests/Types/ObjectID.test.js.map +0 -1
- package/build/dist/Tests/Types/OnCallDutyPolicy/LayerUtil.test.js +0 -530
- package/build/dist/Tests/Types/OnCallDutyPolicy/LayerUtil.test.js.map +0 -1
- package/build/dist/Tests/Types/Permission.test.js +0 -99
- package/build/dist/Tests/Types/Permission.test.js.map +0 -1
- package/build/dist/Tests/Types/Phone.test.js +0 -37
- package/build/dist/Tests/Types/Phone.test.js.map +0 -1
- package/build/dist/Tests/Types/Port.test.js +0 -35
- package/build/dist/Tests/Types/Port.test.js.map +0 -1
- package/build/dist/Tests/Types/PositiveNumber.test.js +0 -101
- package/build/dist/Tests/Types/PositiveNumber.test.js.map +0 -1
- package/build/dist/Tests/Types/SecuritySeverity.test.js +0 -16
- package/build/dist/Tests/Types/SecuritySeverity.test.js.map +0 -1
- package/build/dist/Tests/Types/SerializableObject.test.js +0 -37
- package/build/dist/Tests/Types/SerializableObject.test.js.map +0 -1
- package/build/dist/Tests/Types/Sleep.test.js +0 -14
- package/build/dist/Tests/Types/Sleep.test.js.map +0 -1
- package/build/dist/Tests/Types/Text.test.js +0 -8
- package/build/dist/Tests/Types/Text.test.js.map +0 -1
- package/build/dist/Tests/Types/Timezone.test.js +0 -596
- package/build/dist/Tests/Types/Timezone.test.js.map +0 -1
- package/build/dist/Tests/Types/Typeof.test.js +0 -16
- package/build/dist/Tests/Types/Typeof.test.js.map +0 -1
- package/build/dist/Tests/Types/UserType.test.js +0 -16
- package/build/dist/Tests/Types/UserType.test.js.map +0 -1
- package/build/dist/Tests/Types/Version.test.js +0 -35
- package/build/dist/Tests/Types/Version.test.js.map +0 -1
- package/build/dist/Tests/Types/XML.test.js +0 -35
- package/build/dist/Tests/Types/XML.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/404.test.js +0 -59
- package/build/dist/Tests/UI/Components/404.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Alert.test.js +0 -83
- package/build/dist/Tests/UI/Components/Alert.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Badge.test.js +0 -59
- package/build/dist/Tests/UI/Components/Badge.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/BasicForm.test.js +0 -92
- package/build/dist/Tests/UI/Components/BasicForm.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Breadcrumbs.test.js +0 -69
- package/build/dist/Tests/UI/Components/Breadcrumbs.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Button.test.js +0 -104
- package/build/dist/Tests/UI/Components/Button.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Card.test.js +0 -81
- package/build/dist/Tests/UI/Components/Card.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/ColorViewer.test.js +0 -42
- package/build/dist/Tests/UI/Components/ColorViewer.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/ComponentsModal.test.js +0 -233
- package/build/dist/Tests/UI/Components/ComponentsModal.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/ConfirmModal.test.js +0 -57
- package/build/dist/Tests/UI/Components/ConfirmModal.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/DictionaryOfStrings.test.js +0 -84
- package/build/dist/Tests/UI/Components/DictionaryOfStrings.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Dropdown.test.js +0 -146
- package/build/dist/Tests/UI/Components/Dropdown.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/DuplicateModel.test.js +0 -229
- package/build/dist/Tests/UI/Components/DuplicateModel.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/EmptyState/EmptyState.test.js +0 -26
- package/build/dist/Tests/UI/Components/EmptyState/EmptyState.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/ErrorBoundary.test.js +0 -32
- package/build/dist/Tests/UI/Components/ErrorBoundary.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/FilePicker.test.js +0 -342
- package/build/dist/Tests/UI/Components/FilePicker.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/HiddenText.test.js +0 -50
- package/build/dist/Tests/UI/Components/HiddenText.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Input.test.js +0 -223
- package/build/dist/Tests/UI/Components/Input.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Item.test.js +0 -58
- package/build/dist/Tests/UI/Components/Item.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/List.test.js +0 -83
- package/build/dist/Tests/UI/Components/List.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Loader.test.js +0 -19
- package/build/dist/Tests/UI/Components/Loader.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/MarkdownEditor.test.js +0 -85
- package/build/dist/Tests/UI/Components/MarkdownEditor.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/MasterPage.test.js +0 -46
- package/build/dist/Tests/UI/Components/MasterPage.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Modal.test.js +0 -127
- package/build/dist/Tests/UI/Components/Modal.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/NavBar.test.js +0 -52
- package/build/dist/Tests/UI/Components/NavBar.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/OrderedStatesList.test.js +0 -86
- package/build/dist/Tests/UI/Components/OrderedStatesList.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Pagination.test.js +0 -137
- package/build/dist/Tests/UI/Components/Pagination.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Pill.test.js +0 -55
- package/build/dist/Tests/UI/Components/Pill.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Probe.test.js +0 -52
- package/build/dist/Tests/UI/Components/Probe.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/ProgressBar.test.js +0 -41
- package/build/dist/Tests/UI/Components/ProgressBar.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/RadioButtons.test.js +0 -66
- package/build/dist/Tests/UI/Components/RadioButtons.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/SideMenuItem.test.js +0 -99
- package/build/dist/Tests/UI/Components/SideMenuItem.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/SideOver.test.js +0 -77
- package/build/dist/Tests/UI/Components/SideOver.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Tabs.test.js +0 -56
- package/build/dist/Tests/UI/Components/Tabs.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Template/Template.test.js +0 -15
- package/build/dist/Tests/UI/Components/Template/Template.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/TextArea.test.js +0 -112
- package/build/dist/Tests/UI/Components/TextArea.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/TimePicker/TimePicker.test.js +0 -352
- package/build/dist/Tests/UI/Components/TimePicker/TimePicker.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Toast.test.js +0 -48
- package/build/dist/Tests/UI/Components/Toast.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/Toggle.test.js +0 -95
- package/build/dist/Tests/UI/Components/Toggle.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/TopSection.test.js +0 -33
- package/build/dist/Tests/UI/Components/TopSection.test.js.map +0 -1
- package/build/dist/Tests/UI/Components/XAxis.test.js +0 -21
- package/build/dist/Tests/UI/Components/XAxis.test.js.map +0 -1
- package/build/dist/Tests/UI/Index.js +0 -2
- package/build/dist/Tests/UI/Index.js.map +0 -1
- package/build/dist/Tests/UI/Mocks/FileMock.js +0 -3
- package/build/dist/Tests/UI/Mocks/FileMock.js.map +0 -1
- package/build/dist/Tests/Utils/API.test.js +0 -399
- package/build/dist/Tests/Utils/API.test.js.map +0 -1
- package/build/dist/Tests/Utils/Analytics.test.js +0 -67
- package/build/dist/Tests/Utils/Analytics.test.js.map +0 -1
- package/build/dist/Tests/Utils/CronTime.test.js +0 -22
- package/build/dist/Tests/Utils/CronTime.test.js.map +0 -1
- package/build/dist/Tests/Utils/Faker.test.js +0 -27
- package/build/dist/Tests/Utils/Faker.test.js.map +0 -1
- package/build/dist/Tests/Utils/MetricUnitUtil.test.js +0 -187
- package/build/dist/Tests/Utils/MetricUnitUtil.test.js.map +0 -1
- package/build/dist/Tests/Utils/Metrics/MetricFormulaEvaluator.test.js +0 -224
- package/build/dist/Tests/Utils/Metrics/MetricFormulaEvaluator.test.js.map +0 -1
- package/build/dist/Tests/Utils/Metrics/MetricResultUnitConverter.test.js +0 -180
- package/build/dist/Tests/Utils/Metrics/MetricResultUnitConverter.test.js.map +0 -1
- package/build/dist/Tests/Utils/RecordingRuleExpression.test.js +0 -142
- package/build/dist/Tests/Utils/RecordingRuleExpression.test.js.map +0 -1
- package/build/dist/Tests/Utils/Slug.test.js +0 -20
- package/build/dist/Tests/Utils/Slug.test.js.map +0 -1
- package/build/dist/Tests/Utils/UUID.test.js +0 -48
- package/build/dist/Tests/Utils/UUID.test.js.map +0 -1
- package/build/dist/Tests/jest.setup.js +0 -30
- package/build/dist/Tests/jest.setup.js.map +0 -1
- package/build/dist/Types/Profile/ProfileMetricType.js +0 -17
- package/build/dist/Types/Profile/ProfileMetricType.js.map +0 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { SQL, Statement } from "../Utils/AnalyticsDatabase/Statement";
|
|
2
|
+
import { getQuerySettings } from "../Utils/AnalyticsDatabase/QuerySettingsHelper";
|
|
2
3
|
import ProfileSampleDatabaseService from "./ProfileSampleService";
|
|
4
|
+
import ProfileDatabaseService from "./ProfileService";
|
|
3
5
|
import TableColumnType from "../../Types/AnalyticsDatabase/TableColumnType";
|
|
4
6
|
import { JSONObject } from "../../Types/JSON";
|
|
5
7
|
import ObjectID from "../../Types/ObjectID";
|
|
@@ -39,6 +41,15 @@ export interface FlamegraphRequest {
|
|
|
39
41
|
profileTypes?: Array<string>;
|
|
40
42
|
}
|
|
41
43
|
|
|
44
|
+
export interface FlamegraphResult {
|
|
45
|
+
flamegraph: ProfileFlamegraphNode;
|
|
46
|
+
/**
|
|
47
|
+
* True when the unique-stack LIMIT was hit, i.e. the smallest stacks in
|
|
48
|
+
* the window were dropped and the tree undercounts the true totals.
|
|
49
|
+
*/
|
|
50
|
+
truncated: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
42
53
|
export interface FunctionListItem {
|
|
43
54
|
functionName: string;
|
|
44
55
|
fileName: string;
|
|
@@ -50,8 +61,19 @@ export interface FunctionListItem {
|
|
|
50
61
|
|
|
51
62
|
export interface FunctionListRequest {
|
|
52
63
|
projectId: ObjectID;
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
/**
|
|
65
|
+
* When present, restricts the list to the samples of a single ingested
|
|
66
|
+
* profile so the per-profile detail view and the windowed view share
|
|
67
|
+
* one code path.
|
|
68
|
+
*/
|
|
69
|
+
profileId?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Optional when profileId is given: a single profile's samples are
|
|
72
|
+
* already bounded, and forcing a window here would silently drop any
|
|
73
|
+
* profile captured before the window started.
|
|
74
|
+
*/
|
|
75
|
+
startTime?: Date;
|
|
76
|
+
endTime?: Date;
|
|
55
77
|
serviceIds?: Array<ObjectID>;
|
|
56
78
|
profileType?: string;
|
|
57
79
|
profileTypes?: Array<string>;
|
|
@@ -59,6 +81,21 @@ export interface FunctionListRequest {
|
|
|
59
81
|
sortBy?: "selfValue" | "totalValue" | "sampleCount";
|
|
60
82
|
}
|
|
61
83
|
|
|
84
|
+
export interface FunctionListResult {
|
|
85
|
+
functions: Array<FunctionListItem>;
|
|
86
|
+
/**
|
|
87
|
+
* Sum of `value` across ALL sample rows matching the filters (computed
|
|
88
|
+
* pre-limit, same unit as the per-function values). Lets the UI render
|
|
89
|
+
* accurate "% of total" figures even when the list is truncated.
|
|
90
|
+
*/
|
|
91
|
+
windowTotal: number;
|
|
92
|
+
/**
|
|
93
|
+
* True when the unique-stack LIMIT was hit, i.e. the smallest stacks in
|
|
94
|
+
* the window were dropped and per-function values undercount.
|
|
95
|
+
*/
|
|
96
|
+
truncated: boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
62
99
|
export interface ServiceActivityRequest {
|
|
63
100
|
projectId: ObjectID;
|
|
64
101
|
startTime: Date;
|
|
@@ -77,7 +114,7 @@ export interface ServiceActivityRequest {
|
|
|
77
114
|
}
|
|
78
115
|
|
|
79
116
|
export interface ServiceActivityItem {
|
|
80
|
-
|
|
117
|
+
primaryEntityId: string;
|
|
81
118
|
sampleCount: number;
|
|
82
119
|
profileCount: number;
|
|
83
120
|
totalValue: number;
|
|
@@ -109,6 +146,100 @@ export interface DiffFlamegraphNode {
|
|
|
109
146
|
frameType: string;
|
|
110
147
|
}
|
|
111
148
|
|
|
149
|
+
export interface DiffFlamegraphResult {
|
|
150
|
+
diffFlamegraph: DiffFlamegraphNode;
|
|
151
|
+
/**
|
|
152
|
+
* True when EITHER window's unique-stack LIMIT was hit. A truncated
|
|
153
|
+
* side undercounts its totals, which would otherwise masquerade as a
|
|
154
|
+
* regression/improvement in the delta — the UI must caveat the diff.
|
|
155
|
+
*/
|
|
156
|
+
truncated: boolean;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface FunctionFocusRequest {
|
|
160
|
+
projectId: ObjectID;
|
|
161
|
+
functionName: string;
|
|
162
|
+
/**
|
|
163
|
+
* May be the empty string: bare frames (folded/collapsed uploads and
|
|
164
|
+
* address-only frames) carry no file information, and the empty
|
|
165
|
+
* fileName is part of the function's identity for matching.
|
|
166
|
+
*/
|
|
167
|
+
fileName: string;
|
|
168
|
+
profileId?: string;
|
|
169
|
+
startTime?: Date;
|
|
170
|
+
endTime?: Date;
|
|
171
|
+
serviceIds?: Array<ObjectID>;
|
|
172
|
+
profileType?: string;
|
|
173
|
+
profileTypes?: Array<string>;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface FunctionFocusResult {
|
|
177
|
+
functionName: string;
|
|
178
|
+
fileName: string;
|
|
179
|
+
/**
|
|
180
|
+
* Sum of `value` over every matching stack, counted once per stack
|
|
181
|
+
* even when the function recurses. Equals callers.totalValue and
|
|
182
|
+
* callees.totalValue (both trees are rooted at the focused function).
|
|
183
|
+
*/
|
|
184
|
+
totalValue: number;
|
|
185
|
+
/** Sum of `value` over stacks where the focused function is the leaf. */
|
|
186
|
+
selfValue: number;
|
|
187
|
+
sampleCount: number;
|
|
188
|
+
/**
|
|
189
|
+
* Sum of `value` over ALL rows matching the non-function filters, so
|
|
190
|
+
* the UI can show "% of window" figures for the focused function.
|
|
191
|
+
*/
|
|
192
|
+
windowTotal: number;
|
|
193
|
+
/**
|
|
194
|
+
* Root = the focused function; children = DIRECT callers, grandchildren
|
|
195
|
+
* = callers-of-callers. Node weights are the value flowing through that
|
|
196
|
+
* caller chain into the function.
|
|
197
|
+
*/
|
|
198
|
+
callers: ProfileFlamegraphNode;
|
|
199
|
+
/**
|
|
200
|
+
* Root = the focused function; children = direct callees (frames toward
|
|
201
|
+
* the leaf), and so on.
|
|
202
|
+
*/
|
|
203
|
+
callees: ProfileFlamegraphNode;
|
|
204
|
+
truncated: boolean;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface BreakdownRequest {
|
|
208
|
+
projectId: ObjectID;
|
|
209
|
+
startTime: Date;
|
|
210
|
+
endTime: Date;
|
|
211
|
+
/**
|
|
212
|
+
* "service" groups by primaryEntityId; any other value is treated as a
|
|
213
|
+
* Profile attribute key and groups by that attribute's value.
|
|
214
|
+
*/
|
|
215
|
+
breakdownBy: string;
|
|
216
|
+
serviceIds?: Array<ObjectID>;
|
|
217
|
+
profileType?: string;
|
|
218
|
+
profileTypes?: Array<string>;
|
|
219
|
+
limit?: number;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface BreakdownItem {
|
|
223
|
+
/**
|
|
224
|
+
* The group value: a primaryEntityId string for breakdownBy="service"
|
|
225
|
+
* (the UI resolves display names), otherwise the raw attribute value.
|
|
226
|
+
*/
|
|
227
|
+
value: string;
|
|
228
|
+
sampleCount: number;
|
|
229
|
+
profileCount: number;
|
|
230
|
+
/** 0-100 percentage of totalSampleCount. */
|
|
231
|
+
share: number;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface BreakdownResult {
|
|
235
|
+
items: Array<BreakdownItem>;
|
|
236
|
+
/**
|
|
237
|
+
* Sum of sampleCount across ALL groups (computed pre-limit), so shares
|
|
238
|
+
* stay accurate even when only the top-N items are returned.
|
|
239
|
+
*/
|
|
240
|
+
totalSampleCount: number;
|
|
241
|
+
}
|
|
242
|
+
|
|
112
243
|
interface ParsedFrame {
|
|
113
244
|
functionName: string;
|
|
114
245
|
fileName: string;
|
|
@@ -119,25 +250,45 @@ interface ParsedFrame {
|
|
|
119
250
|
|
|
120
251
|
export class ProfileAggregationService {
|
|
121
252
|
private static readonly TABLE_NAME: string = AnalyticsTableName.ProfileSample;
|
|
253
|
+
private static readonly PROFILE_TABLE_NAME: string =
|
|
254
|
+
AnalyticsTableName.Profile;
|
|
122
255
|
private static readonly DEFAULT_FUNCTION_LIST_LIMIT: number = 50;
|
|
123
|
-
private static readonly
|
|
256
|
+
private static readonly DEFAULT_BREAKDOWN_LIMIT: number = 10;
|
|
257
|
+
/**
|
|
258
|
+
* Cap on unique groups fetched by a breakdown query. Groups are ordered
|
|
259
|
+
* by summed sampleCount, so hitting the cap drops the quietest groups
|
|
260
|
+
* first — totals over the fetched groups stay representative even for
|
|
261
|
+
* pathological high-cardinality attribute keys.
|
|
262
|
+
*/
|
|
263
|
+
private static readonly MAX_BREAKDOWN_GROUP_FETCH: number = 10000;
|
|
264
|
+
/**
|
|
265
|
+
* Cap on unique (stacktrace, frameTypes) groups fetched per query.
|
|
266
|
+
* Sample reads GROUP BY stack identity and ORDER BY summed value, so
|
|
267
|
+
* hitting this cap drops the *smallest* stacks first — truncation is
|
|
268
|
+
* deterministic and barely visible in a flamegraph, unlike a LIMIT over
|
|
269
|
+
* raw unordered sample rows.
|
|
270
|
+
*/
|
|
271
|
+
private static readonly MAX_STACK_FETCH: number = 10000;
|
|
124
272
|
|
|
125
273
|
/**
|
|
126
274
|
* Build a flamegraph tree from ProfileSample records.
|
|
127
275
|
*
|
|
128
276
|
* Each sample has a `stacktrace` array where each element follows the
|
|
129
277
|
* format "functionName@fileName:lineNumber". The array is ordered
|
|
130
|
-
*
|
|
278
|
+
* LEAF-FIRST (index 0 = leaf, last index = root) — the pprof
|
|
279
|
+
* Sample.location_id and OTLP Stack.location_indices conventions both
|
|
280
|
+
* store the innermost frame first, and ingestion preserves wire order.
|
|
131
281
|
*
|
|
132
|
-
*
|
|
282
|
+
* Samples are pre-aggregated in ClickHouse by stack identity, then
|
|
283
|
+
* stacks sharing common prefixes are merged into a tree of
|
|
133
284
|
* ProfileFlamegraphNode objects.
|
|
134
285
|
*/
|
|
135
286
|
@CaptureSpan()
|
|
136
287
|
public static async getFlamegraph(
|
|
137
288
|
request: FlamegraphRequest,
|
|
138
|
-
): Promise<
|
|
289
|
+
): Promise<FlamegraphResult> {
|
|
139
290
|
const statement: Statement =
|
|
140
|
-
ProfileAggregationService.
|
|
291
|
+
ProfileAggregationService.buildGroupedStackQuery(request);
|
|
141
292
|
|
|
142
293
|
const dbResult: Results =
|
|
143
294
|
await ProfileSampleDatabaseService.executeQuery(statement);
|
|
@@ -146,8 +297,10 @@ export class ProfileAggregationService {
|
|
|
146
297
|
}>();
|
|
147
298
|
|
|
148
299
|
const rows: Array<JSONObject> = response.data || [];
|
|
300
|
+
const truncated: boolean =
|
|
301
|
+
rows.length >= ProfileAggregationService.MAX_STACK_FETCH;
|
|
149
302
|
|
|
150
|
-
// Build the tree from
|
|
303
|
+
// Build the tree from the pre-aggregated stacks
|
|
151
304
|
const root: ProfileFlamegraphNode = {
|
|
152
305
|
functionName: "(root)",
|
|
153
306
|
fileName: "",
|
|
@@ -158,36 +311,52 @@ export class ProfileAggregationService {
|
|
|
158
311
|
frameType: "",
|
|
159
312
|
};
|
|
160
313
|
|
|
314
|
+
/*
|
|
315
|
+
* Per-node child index so frame lookup is O(1) instead of a linear
|
|
316
|
+
* children.find() — wide fan-out (thousands of siblings under root)
|
|
317
|
+
* made the scan quadratic. Kept outside the nodes so the serialized
|
|
318
|
+
* tree shape is unchanged.
|
|
319
|
+
*/
|
|
320
|
+
const childIndex: WeakMap<
|
|
321
|
+
ProfileFlamegraphNode,
|
|
322
|
+
Map<string, ProfileFlamegraphNode>
|
|
323
|
+
> = new WeakMap();
|
|
324
|
+
|
|
161
325
|
for (const row of rows) {
|
|
162
326
|
const stacktrace: Array<string> =
|
|
163
327
|
(row["stacktrace"] as Array<string>) || [];
|
|
164
328
|
const frameTypes: Array<string> =
|
|
165
329
|
(row["frameTypes"] as Array<string>) || [];
|
|
166
|
-
const value: number = Number(row["
|
|
330
|
+
const value: number = Number(row["totalValue"] || 0);
|
|
167
331
|
|
|
168
332
|
if (stacktrace.length === 0) {
|
|
169
333
|
continue;
|
|
170
334
|
}
|
|
171
335
|
|
|
172
|
-
|
|
336
|
+
/*
|
|
337
|
+
* Walk down the tree, creating nodes as needed. Stored stacks are
|
|
338
|
+
* leaf-first, so iterate from the END of the array (root) toward
|
|
339
|
+
* index 0 (leaf) to build the tree root-to-leaf.
|
|
340
|
+
*/
|
|
173
341
|
let currentNode: ProfileFlamegraphNode = root;
|
|
174
342
|
currentNode.totalValue += value;
|
|
175
343
|
|
|
176
|
-
for (let i: number =
|
|
344
|
+
for (let i: number = stacktrace.length - 1; i >= 0; i--) {
|
|
177
345
|
const frame: ParsedFrame = ProfileAggregationService.parseFrame(
|
|
178
346
|
stacktrace[i]!,
|
|
179
347
|
);
|
|
180
348
|
const frameType: string = frameTypes[i] || "";
|
|
349
|
+
const frameKey: string = `${frame.functionName}@${frame.fileName}:${frame.lineNumber}`;
|
|
350
|
+
|
|
351
|
+
let index: Map<string, ProfileFlamegraphNode> | undefined =
|
|
352
|
+
childIndex.get(currentNode);
|
|
181
353
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
child.lineNumber === frame.lineNumber
|
|
189
|
-
);
|
|
190
|
-
});
|
|
354
|
+
if (!index) {
|
|
355
|
+
index = new Map<string, ProfileFlamegraphNode>();
|
|
356
|
+
childIndex.set(currentNode, index);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
let childNode: ProfileFlamegraphNode | undefined = index.get(frameKey);
|
|
191
360
|
|
|
192
361
|
if (!childNode) {
|
|
193
362
|
childNode = {
|
|
@@ -200,12 +369,13 @@ export class ProfileAggregationService {
|
|
|
200
369
|
frameType: frameType,
|
|
201
370
|
};
|
|
202
371
|
currentNode.children.push(childNode);
|
|
372
|
+
index.set(frameKey, childNode);
|
|
203
373
|
}
|
|
204
374
|
|
|
205
375
|
childNode.totalValue += value;
|
|
206
376
|
|
|
207
|
-
//
|
|
208
|
-
if (i ===
|
|
377
|
+
// Index 0 is the leaf frame in leaf-first storage — it gets selfValue
|
|
378
|
+
if (i === 0) {
|
|
209
379
|
childNode.selfValue += value;
|
|
210
380
|
}
|
|
211
381
|
|
|
@@ -213,29 +383,67 @@ export class ProfileAggregationService {
|
|
|
213
383
|
}
|
|
214
384
|
}
|
|
215
385
|
|
|
216
|
-
return root;
|
|
386
|
+
return { flamegraph: root, truncated };
|
|
217
387
|
}
|
|
218
388
|
|
|
219
389
|
/**
|
|
220
390
|
* Return the top functions aggregated across samples, sorted by the
|
|
221
|
-
* requested metric (selfValue, totalValue, or sampleCount)
|
|
391
|
+
* requested metric (selfValue, totalValue, or sampleCount), along with
|
|
392
|
+
* the pre-limit window total so callers can show "% of total" figures.
|
|
222
393
|
*/
|
|
223
394
|
@CaptureSpan()
|
|
224
395
|
public static async getFunctionList(
|
|
225
396
|
request: FunctionListRequest,
|
|
226
|
-
): Promise<
|
|
397
|
+
): Promise<FunctionListResult> {
|
|
398
|
+
const filters: FlamegraphRequest = {
|
|
399
|
+
projectId: request.projectId,
|
|
400
|
+
...(request.startTime !== undefined && { startTime: request.startTime }),
|
|
401
|
+
...(request.endTime !== undefined && { endTime: request.endTime }),
|
|
402
|
+
...(request.profileId !== undefined && { profileId: request.profileId }),
|
|
403
|
+
...(request.serviceIds !== undefined && {
|
|
404
|
+
serviceIds: request.serviceIds,
|
|
405
|
+
}),
|
|
406
|
+
...(request.profileType !== undefined && {
|
|
407
|
+
profileType: request.profileType,
|
|
408
|
+
}),
|
|
409
|
+
...(request.profileTypes !== undefined && {
|
|
410
|
+
profileTypes: request.profileTypes,
|
|
411
|
+
}),
|
|
412
|
+
};
|
|
413
|
+
|
|
227
414
|
const statement: Statement =
|
|
228
|
-
ProfileAggregationService.
|
|
415
|
+
ProfileAggregationService.buildGroupedStackQuery(filters);
|
|
416
|
+
const windowTotalStatement: Statement =
|
|
417
|
+
ProfileAggregationService.buildWindowTotalQuery(filters);
|
|
418
|
+
|
|
419
|
+
/*
|
|
420
|
+
* The window total must be computed over ALL matching rows (pre-limit),
|
|
421
|
+
* so it cannot be derived from the capped grouped result. It is a
|
|
422
|
+
* single cheap aggregate, so run both queries concurrently.
|
|
423
|
+
*/
|
|
424
|
+
const [dbResult, windowTotalDbResult]: [Results, Results] =
|
|
425
|
+
await Promise.all([
|
|
426
|
+
ProfileSampleDatabaseService.executeQuery(statement),
|
|
427
|
+
ProfileSampleDatabaseService.executeQuery(windowTotalStatement),
|
|
428
|
+
]);
|
|
229
429
|
|
|
230
|
-
const dbResult: Results =
|
|
231
|
-
await ProfileSampleDatabaseService.executeQuery(statement);
|
|
232
430
|
const response: DbJSONResponse = await dbResult.json<{
|
|
233
431
|
data?: Array<JSONObject>;
|
|
234
432
|
}>();
|
|
433
|
+
const windowTotalResponse: DbJSONResponse = await windowTotalDbResult.json<{
|
|
434
|
+
data?: Array<JSONObject>;
|
|
435
|
+
}>();
|
|
235
436
|
|
|
236
437
|
const rows: Array<JSONObject> = response.data || [];
|
|
438
|
+
const truncated: boolean =
|
|
439
|
+
rows.length >= ProfileAggregationService.MAX_STACK_FETCH;
|
|
237
440
|
|
|
238
|
-
|
|
441
|
+
const windowTotalRows: Array<JSONObject> = windowTotalResponse.data || [];
|
|
442
|
+
const windowTotal: number = Number(
|
|
443
|
+
windowTotalRows[0]?.["windowTotal"] || 0,
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
// Aggregate per-function stats from the pre-aggregated stacks
|
|
239
447
|
const functionMap: Map<
|
|
240
448
|
string,
|
|
241
449
|
{
|
|
@@ -253,7 +461,12 @@ export class ProfileAggregationService {
|
|
|
253
461
|
(row["stacktrace"] as Array<string>) || [];
|
|
254
462
|
const frameTypes: Array<string> =
|
|
255
463
|
(row["frameTypes"] as Array<string>) || [];
|
|
256
|
-
const value: number = Number(row["
|
|
464
|
+
const value: number = Number(row["totalValue"] || 0);
|
|
465
|
+
/*
|
|
466
|
+
* Each grouped row stands in for `sampleCount` raw samples sharing
|
|
467
|
+
* one stack, so per-function sample counts add the group size, not 1.
|
|
468
|
+
*/
|
|
469
|
+
const groupSampleCount: number = Number(row["sampleCount"] || 0);
|
|
257
470
|
|
|
258
471
|
if (stacktrace.length === 0) {
|
|
259
472
|
continue;
|
|
@@ -267,7 +480,8 @@ export class ProfileAggregationService {
|
|
|
267
480
|
);
|
|
268
481
|
const frameType: string = frameTypes[i] || "";
|
|
269
482
|
const key: string = `${frame.functionName}@${frame.fileName}:${frame.lineNumber}`;
|
|
270
|
-
|
|
483
|
+
// Stacks are stored leaf-first, so index 0 is the leaf frame.
|
|
484
|
+
const isLeaf: boolean = i === 0;
|
|
271
485
|
|
|
272
486
|
let entry: FunctionListItem | undefined = functionMap.get(key);
|
|
273
487
|
|
|
@@ -283,10 +497,10 @@ export class ProfileAggregationService {
|
|
|
283
497
|
functionMap.set(key, entry);
|
|
284
498
|
}
|
|
285
499
|
|
|
286
|
-
// totalValue: count the value once per unique function per
|
|
500
|
+
// totalValue: count the value once per unique function per stack
|
|
287
501
|
if (!seenInThisSample.has(key)) {
|
|
288
502
|
entry.totalValue += value;
|
|
289
|
-
entry.sampleCount +=
|
|
503
|
+
entry.sampleCount += groupSampleCount;
|
|
290
504
|
seenInThisSample.add(key);
|
|
291
505
|
}
|
|
292
506
|
|
|
@@ -316,19 +530,320 @@ export class ProfileAggregationService {
|
|
|
316
530
|
const limit: number =
|
|
317
531
|
request.limit ?? ProfileAggregationService.DEFAULT_FUNCTION_LIST_LIMIT;
|
|
318
532
|
|
|
319
|
-
return
|
|
533
|
+
return {
|
|
534
|
+
functions: items.slice(0, limit),
|
|
535
|
+
windowTotal,
|
|
536
|
+
truncated,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* "Sandwich" aggregation for one function: every matching stack is
|
|
542
|
+
* split at the focused function, the frames toward the root become the
|
|
543
|
+
* callers tree and the frames toward the leaf become the callees tree.
|
|
544
|
+
* Both trees are rooted at the focused function itself so the UI can
|
|
545
|
+
* render them stacked around a single center row.
|
|
546
|
+
*
|
|
547
|
+
* Frames match on functionName + fileName only — line numbers shift on
|
|
548
|
+
* every deploy (and with inlining), so including them would split one
|
|
549
|
+
* logical function into many.
|
|
550
|
+
*/
|
|
551
|
+
@CaptureSpan()
|
|
552
|
+
public static async getFunctionFocus(
|
|
553
|
+
request: FunctionFocusRequest,
|
|
554
|
+
): Promise<FunctionFocusResult> {
|
|
555
|
+
const filters: FlamegraphRequest = {
|
|
556
|
+
projectId: request.projectId,
|
|
557
|
+
...(request.profileId !== undefined && { profileId: request.profileId }),
|
|
558
|
+
...(request.startTime !== undefined && { startTime: request.startTime }),
|
|
559
|
+
...(request.endTime !== undefined && { endTime: request.endTime }),
|
|
560
|
+
...(request.serviceIds !== undefined && {
|
|
561
|
+
serviceIds: request.serviceIds,
|
|
562
|
+
}),
|
|
563
|
+
...(request.profileType !== undefined && {
|
|
564
|
+
profileType: request.profileType,
|
|
565
|
+
}),
|
|
566
|
+
...(request.profileTypes !== undefined && {
|
|
567
|
+
profileTypes: request.profileTypes,
|
|
568
|
+
}),
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
const statement: Statement =
|
|
572
|
+
ProfileAggregationService.buildFunctionStackQuery(
|
|
573
|
+
filters,
|
|
574
|
+
request.functionName,
|
|
575
|
+
request.fileName,
|
|
576
|
+
);
|
|
577
|
+
const windowTotalStatement: Statement =
|
|
578
|
+
ProfileAggregationService.buildWindowTotalQuery(filters);
|
|
579
|
+
|
|
580
|
+
/*
|
|
581
|
+
* windowTotal deliberately ignores the function prefilter — it is the
|
|
582
|
+
* denominator for "% of window" figures, so it must cover every row
|
|
583
|
+
* matching the non-function filters. Both reads are independent, so
|
|
584
|
+
* run them concurrently.
|
|
585
|
+
*/
|
|
586
|
+
const [dbResult, windowTotalDbResult]: [Results, Results] =
|
|
587
|
+
await Promise.all([
|
|
588
|
+
ProfileSampleDatabaseService.executeQuery(statement),
|
|
589
|
+
ProfileSampleDatabaseService.executeQuery(windowTotalStatement),
|
|
590
|
+
]);
|
|
591
|
+
|
|
592
|
+
const response: DbJSONResponse = await dbResult.json<{
|
|
593
|
+
data?: Array<JSONObject>;
|
|
594
|
+
}>();
|
|
595
|
+
const windowTotalResponse: DbJSONResponse = await windowTotalDbResult.json<{
|
|
596
|
+
data?: Array<JSONObject>;
|
|
597
|
+
}>();
|
|
598
|
+
|
|
599
|
+
const rows: Array<JSONObject> = response.data || [];
|
|
600
|
+
const truncated: boolean =
|
|
601
|
+
rows.length >= ProfileAggregationService.MAX_STACK_FETCH;
|
|
602
|
+
|
|
603
|
+
const windowTotalRows: Array<JSONObject> = windowTotalResponse.data || [];
|
|
604
|
+
const windowTotal: number = Number(
|
|
605
|
+
windowTotalRows[0]?.["windowTotal"] || 0,
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
/*
|
|
609
|
+
* Both trees are rooted at the focused function. lineNumber is 0
|
|
610
|
+
* because the view aggregates across line numbers by design.
|
|
611
|
+
*/
|
|
612
|
+
const callers: ProfileFlamegraphNode = {
|
|
613
|
+
functionName: request.functionName,
|
|
614
|
+
fileName: request.fileName,
|
|
615
|
+
lineNumber: 0,
|
|
616
|
+
selfValue: 0,
|
|
617
|
+
totalValue: 0,
|
|
618
|
+
children: [],
|
|
619
|
+
frameType: "",
|
|
620
|
+
};
|
|
621
|
+
const callees: ProfileFlamegraphNode = {
|
|
622
|
+
functionName: request.functionName,
|
|
623
|
+
fileName: request.fileName,
|
|
624
|
+
lineNumber: 0,
|
|
625
|
+
selfValue: 0,
|
|
626
|
+
totalValue: 0,
|
|
627
|
+
children: [],
|
|
628
|
+
frameType: "",
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
/*
|
|
632
|
+
* Per-node child index for O(1) frame lookup, mirroring getFlamegraph.
|
|
633
|
+
* One map serves both trees since it is keyed by parent node identity.
|
|
634
|
+
*/
|
|
635
|
+
const childIndex: WeakMap<
|
|
636
|
+
ProfileFlamegraphNode,
|
|
637
|
+
Map<string, ProfileFlamegraphNode>
|
|
638
|
+
> = new WeakMap();
|
|
639
|
+
|
|
640
|
+
let totalValue: number = 0;
|
|
641
|
+
let selfValue: number = 0;
|
|
642
|
+
let sampleCount: number = 0;
|
|
643
|
+
|
|
644
|
+
for (const row of rows) {
|
|
645
|
+
const stacktrace: Array<string> =
|
|
646
|
+
(row["stacktrace"] as Array<string>) || [];
|
|
647
|
+
const frameTypes: Array<string> =
|
|
648
|
+
(row["frameTypes"] as Array<string>) || [];
|
|
649
|
+
const value: number = Number(row["totalValue"] || 0);
|
|
650
|
+
const groupSampleCount: number = Number(row["sampleCount"] || 0);
|
|
651
|
+
|
|
652
|
+
if (stacktrace.length === 0) {
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/*
|
|
657
|
+
* Stacks are leaf-first, so scanning from the END finds the
|
|
658
|
+
* occurrence CLOSEST TO THE ROOT first. For recursive functions
|
|
659
|
+
* this attributes the whole recursive subtree (including nested
|
|
660
|
+
* occurrences) to one split point, so each stack's value is
|
|
661
|
+
* counted exactly once.
|
|
662
|
+
*/
|
|
663
|
+
let occurrenceIndex: number = -1;
|
|
664
|
+
|
|
665
|
+
for (let i: number = stacktrace.length - 1; i >= 0; i--) {
|
|
666
|
+
const frame: ParsedFrame = ProfileAggregationService.parseFrame(
|
|
667
|
+
stacktrace[i]!,
|
|
668
|
+
);
|
|
669
|
+
if (
|
|
670
|
+
frame.functionName === request.functionName &&
|
|
671
|
+
frame.fileName === request.fileName
|
|
672
|
+
) {
|
|
673
|
+
occurrenceIndex = i;
|
|
674
|
+
break;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/*
|
|
679
|
+
* The ClickHouse prefilter is a prefix match and can overmatch
|
|
680
|
+
* when a fileName containing colons shares a prefix with another
|
|
681
|
+
* (parseFrame splits on the LAST colon) — drop those rows here.
|
|
682
|
+
*/
|
|
683
|
+
if (occurrenceIndex === -1) {
|
|
684
|
+
continue;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
totalValue += value;
|
|
688
|
+
sampleCount += groupSampleCount;
|
|
689
|
+
|
|
690
|
+
/*
|
|
691
|
+
* Self time counts whenever the function is the EXECUTING (leaf)
|
|
692
|
+
* frame — checked against index 0 directly rather than the split
|
|
693
|
+
* point, because a recursive stack splits at the root-most
|
|
694
|
+
* occurrence while the leaf may still be the same function
|
|
695
|
+
* (standard sandwich-view semantics: self = "was on CPU").
|
|
696
|
+
*/
|
|
697
|
+
const leafFrame: ParsedFrame = ProfileAggregationService.parseFrame(
|
|
698
|
+
stacktrace[0]!,
|
|
699
|
+
);
|
|
700
|
+
if (
|
|
701
|
+
leafFrame.functionName === request.functionName &&
|
|
702
|
+
leafFrame.fileName === request.fileName
|
|
703
|
+
) {
|
|
704
|
+
selfValue += value;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
const occurrenceFrameType: string = frameTypes[occurrenceIndex] || "";
|
|
708
|
+
|
|
709
|
+
if (!callers.frameType) {
|
|
710
|
+
callers.frameType = occurrenceFrameType;
|
|
711
|
+
}
|
|
712
|
+
if (!callees.frameType) {
|
|
713
|
+
callees.frameType = occurrenceFrameType;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
callers.totalValue += value;
|
|
717
|
+
callees.totalValue += value;
|
|
718
|
+
|
|
719
|
+
/*
|
|
720
|
+
* Caller chain: frames ABOVE the occurrence (toward the root),
|
|
721
|
+
* direct caller first so depth in the tree equals caller distance.
|
|
722
|
+
*/
|
|
723
|
+
const callerIndices: Array<number> = [];
|
|
724
|
+
for (let i: number = occurrenceIndex + 1; i < stacktrace.length; i++) {
|
|
725
|
+
callerIndices.push(i);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/*
|
|
729
|
+
* Callee chain: frames BELOW the occurrence (toward the leaf),
|
|
730
|
+
* direct callee first.
|
|
731
|
+
*/
|
|
732
|
+
const calleeIndices: Array<number> = [];
|
|
733
|
+
for (let i: number = occurrenceIndex - 1; i >= 0; i--) {
|
|
734
|
+
calleeIndices.push(i);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
ProfileAggregationService.appendFocusChain({
|
|
738
|
+
root: callers,
|
|
739
|
+
stacktrace,
|
|
740
|
+
frameTypes,
|
|
741
|
+
frameIndices: callerIndices,
|
|
742
|
+
value,
|
|
743
|
+
childIndex,
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
ProfileAggregationService.appendFocusChain({
|
|
747
|
+
root: callees,
|
|
748
|
+
stacktrace,
|
|
749
|
+
frameTypes,
|
|
750
|
+
frameIndices: calleeIndices,
|
|
751
|
+
value,
|
|
752
|
+
childIndex,
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
return {
|
|
757
|
+
functionName: request.functionName,
|
|
758
|
+
fileName: request.fileName,
|
|
759
|
+
totalValue,
|
|
760
|
+
selfValue,
|
|
761
|
+
sampleCount,
|
|
762
|
+
windowTotal,
|
|
763
|
+
callers,
|
|
764
|
+
callees,
|
|
765
|
+
truncated,
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Walk one split half of a stack into a focus tree, merging frames on
|
|
771
|
+
* functionName + fileName (line numbers aggregated away — same
|
|
772
|
+
* deploy-stability rationale as the focused-function match itself).
|
|
773
|
+
* The terminal node of the chain absorbs selfValue: in the callers
|
|
774
|
+
* tree that is the stack root ("the chain starts here"), in the
|
|
775
|
+
* callees tree the leaf ("the time bottoms out here"). An empty chain
|
|
776
|
+
* terminates at the focused root itself.
|
|
777
|
+
*/
|
|
778
|
+
private static appendFocusChain(data: {
|
|
779
|
+
root: ProfileFlamegraphNode;
|
|
780
|
+
stacktrace: Array<string>;
|
|
781
|
+
frameTypes: Array<string>;
|
|
782
|
+
frameIndices: Array<number>;
|
|
783
|
+
value: number;
|
|
784
|
+
childIndex: WeakMap<
|
|
785
|
+
ProfileFlamegraphNode,
|
|
786
|
+
Map<string, ProfileFlamegraphNode>
|
|
787
|
+
>;
|
|
788
|
+
}): void {
|
|
789
|
+
let currentNode: ProfileFlamegraphNode = data.root;
|
|
790
|
+
|
|
791
|
+
for (const frameIndex of data.frameIndices) {
|
|
792
|
+
const frame: ParsedFrame = ProfileAggregationService.parseFrame(
|
|
793
|
+
data.stacktrace[frameIndex]!,
|
|
794
|
+
);
|
|
795
|
+
const frameType: string = data.frameTypes[frameIndex] || "";
|
|
796
|
+
const frameKey: string = `${frame.functionName}@${frame.fileName}`;
|
|
797
|
+
|
|
798
|
+
let index: Map<string, ProfileFlamegraphNode> | undefined =
|
|
799
|
+
data.childIndex.get(currentNode);
|
|
800
|
+
|
|
801
|
+
if (!index) {
|
|
802
|
+
index = new Map<string, ProfileFlamegraphNode>();
|
|
803
|
+
data.childIndex.set(currentNode, index);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
let childNode: ProfileFlamegraphNode | undefined = index.get(frameKey);
|
|
807
|
+
|
|
808
|
+
if (!childNode) {
|
|
809
|
+
childNode = {
|
|
810
|
+
functionName: frame.functionName,
|
|
811
|
+
fileName: frame.fileName,
|
|
812
|
+
lineNumber: 0,
|
|
813
|
+
selfValue: 0,
|
|
814
|
+
totalValue: 0,
|
|
815
|
+
children: [],
|
|
816
|
+
frameType: frameType,
|
|
817
|
+
};
|
|
818
|
+
currentNode.children.push(childNode);
|
|
819
|
+
index.set(frameKey, childNode);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
childNode.totalValue += data.value;
|
|
823
|
+
currentNode = childNode;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
currentNode.selfValue += data.value;
|
|
320
827
|
}
|
|
321
828
|
|
|
322
829
|
/**
|
|
323
830
|
* Build a diff flamegraph comparing two time ranges.
|
|
324
|
-
* Returns a tree where each node has baseline/comparison values and
|
|
831
|
+
* Returns a tree where each node has baseline/comparison values and
|
|
832
|
+
* deltas, plus a truncation flag covering both source windows.
|
|
325
833
|
*/
|
|
326
834
|
@CaptureSpan()
|
|
327
835
|
public static async getDiffFlamegraph(
|
|
328
836
|
request: DiffFlamegraphRequest,
|
|
329
|
-
): Promise<
|
|
330
|
-
|
|
331
|
-
|
|
837
|
+
): Promise<DiffFlamegraphResult> {
|
|
838
|
+
/*
|
|
839
|
+
* The two windows are independent reads, so fetch them concurrently —
|
|
840
|
+
* sequential awaits doubled the latency of every diff request.
|
|
841
|
+
*/
|
|
842
|
+
const [baselineResult, comparisonResult]: [
|
|
843
|
+
FlamegraphResult,
|
|
844
|
+
FlamegraphResult,
|
|
845
|
+
] = await Promise.all([
|
|
846
|
+
ProfileAggregationService.getFlamegraph({
|
|
332
847
|
projectId: request.projectId,
|
|
333
848
|
startTime: request.baselineStartTime,
|
|
334
849
|
endTime: request.baselineEndTime,
|
|
@@ -341,10 +856,8 @@ export class ProfileAggregationService {
|
|
|
341
856
|
...(request.profileTypes !== undefined && {
|
|
342
857
|
profileTypes: request.profileTypes,
|
|
343
858
|
}),
|
|
344
|
-
})
|
|
345
|
-
|
|
346
|
-
const comparisonTree: ProfileFlamegraphNode =
|
|
347
|
-
await ProfileAggregationService.getFlamegraph({
|
|
859
|
+
}),
|
|
860
|
+
ProfileAggregationService.getFlamegraph({
|
|
348
861
|
projectId: request.projectId,
|
|
349
862
|
startTime: request.comparisonStartTime,
|
|
350
863
|
endTime: request.comparisonEndTime,
|
|
@@ -357,12 +870,16 @@ export class ProfileAggregationService {
|
|
|
357
870
|
...(request.profileTypes !== undefined && {
|
|
358
871
|
profileTypes: request.profileTypes,
|
|
359
872
|
}),
|
|
360
|
-
})
|
|
873
|
+
}),
|
|
874
|
+
]);
|
|
361
875
|
|
|
362
|
-
return
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
876
|
+
return {
|
|
877
|
+
diffFlamegraph: ProfileAggregationService.mergeDiffTrees(
|
|
878
|
+
baselineResult.flamegraph,
|
|
879
|
+
comparisonResult.flamegraph,
|
|
880
|
+
),
|
|
881
|
+
truncated: baselineResult.truncated || comparisonResult.truncated,
|
|
882
|
+
};
|
|
366
883
|
}
|
|
367
884
|
|
|
368
885
|
private static mergeDiffTrees(
|
|
@@ -442,10 +959,14 @@ export class ProfileAggregationService {
|
|
|
442
959
|
}
|
|
443
960
|
|
|
444
961
|
/**
|
|
445
|
-
* Aggregate sample / profile counts per
|
|
962
|
+
* Aggregate sample / profile counts per primaryEntityId for a time window.
|
|
446
963
|
* Drives the "loudest services first" sort on the Profiles dashboard
|
|
447
964
|
* so a developer opening the page lands on the workloads that are
|
|
448
965
|
* actually doing work rather than scrolling past kernel-thread noise.
|
|
966
|
+
*
|
|
967
|
+
* Reads the small Profile table (one row per ingested profile, with a
|
|
968
|
+
* denormalized sampleCount) instead of scanning every row of the huge
|
|
969
|
+
* ProfileSample table for what is just a per-service ranking.
|
|
449
970
|
*/
|
|
450
971
|
@CaptureSpan()
|
|
451
972
|
public static async getServiceActivity(
|
|
@@ -455,7 +976,7 @@ export class ProfileAggregationService {
|
|
|
455
976
|
ProfileAggregationService.buildServiceActivityQuery(request);
|
|
456
977
|
|
|
457
978
|
const dbResult: Results =
|
|
458
|
-
await
|
|
979
|
+
await ProfileDatabaseService.executeQuery(statement);
|
|
459
980
|
const response: DbJSONResponse = await dbResult.json<{
|
|
460
981
|
data?: Array<JSONObject>;
|
|
461
982
|
}>();
|
|
@@ -463,28 +984,105 @@ export class ProfileAggregationService {
|
|
|
463
984
|
const rows: Array<JSONObject> = response.data || [];
|
|
464
985
|
const out: Array<ServiceActivityItem> = [];
|
|
465
986
|
for (const row of rows) {
|
|
466
|
-
const
|
|
467
|
-
if (!
|
|
987
|
+
const primaryEntityId: string = String(row["primaryEntityId"] || "");
|
|
988
|
+
if (!primaryEntityId) {
|
|
468
989
|
continue;
|
|
469
990
|
}
|
|
470
991
|
out.push({
|
|
471
|
-
|
|
472
|
-
sampleCount: Number(row["
|
|
992
|
+
primaryEntityId,
|
|
993
|
+
sampleCount: Number(row["totalSampleCount"] || 0),
|
|
473
994
|
profileCount: Number(row["profileCount"] || 0),
|
|
474
|
-
|
|
995
|
+
/*
|
|
996
|
+
* Profile rows do not carry a summed sample value, and no client
|
|
997
|
+
* reads this field — it is kept at 0 purely so the response shape
|
|
998
|
+
* stays stable for existing consumers.
|
|
999
|
+
*/
|
|
1000
|
+
totalValue: 0,
|
|
475
1001
|
});
|
|
476
1002
|
}
|
|
477
1003
|
return out;
|
|
478
1004
|
}
|
|
479
1005
|
|
|
1006
|
+
/**
|
|
1007
|
+
* Group profiling volume by a dimension ("service" = primaryEntityId,
|
|
1008
|
+
* anything else = a Profile attribute key) over a time window.
|
|
1009
|
+
*
|
|
1010
|
+
* Reads the small Profile table (one row per ingested profile with a
|
|
1011
|
+
* denormalized sampleCount) — same reasoning as getServiceActivity: a
|
|
1012
|
+
* share-of-volume ranking never needs the huge ProfileSample table.
|
|
1013
|
+
*
|
|
1014
|
+
* totalSampleCount sums over ALL fetched groups before the limit is
|
|
1015
|
+
* applied, so item shares stay percentages of the real total rather
|
|
1016
|
+
* than of the visible top-N.
|
|
1017
|
+
*/
|
|
1018
|
+
@CaptureSpan()
|
|
1019
|
+
public static async getBreakdown(
|
|
1020
|
+
request: BreakdownRequest,
|
|
1021
|
+
): Promise<BreakdownResult> {
|
|
1022
|
+
const statement: Statement =
|
|
1023
|
+
ProfileAggregationService.buildBreakdownQuery(request);
|
|
1024
|
+
|
|
1025
|
+
const dbResult: Results =
|
|
1026
|
+
await ProfileDatabaseService.executeQuery(statement);
|
|
1027
|
+
const response: DbJSONResponse = await dbResult.json<{
|
|
1028
|
+
data?: Array<JSONObject>;
|
|
1029
|
+
}>();
|
|
1030
|
+
|
|
1031
|
+
const rows: Array<JSONObject> = response.data || [];
|
|
1032
|
+
|
|
1033
|
+
// Rows arrive sorted by summed sampleCount descending (query ORDER BY).
|
|
1034
|
+
const allItems: Array<BreakdownItem> = [];
|
|
1035
|
+
let totalSampleCount: number = 0;
|
|
1036
|
+
|
|
1037
|
+
for (const row of rows) {
|
|
1038
|
+
const value: string = String(row["breakdownValue"] || "");
|
|
1039
|
+
if (!value) {
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
const groupSampleCount: number = Number(row["totalSampleCount"] || 0);
|
|
1044
|
+
totalSampleCount += groupSampleCount;
|
|
1045
|
+
|
|
1046
|
+
allItems.push({
|
|
1047
|
+
value,
|
|
1048
|
+
sampleCount: groupSampleCount,
|
|
1049
|
+
profileCount: Number(row["profileCount"] || 0),
|
|
1050
|
+
share: 0,
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
const limit: number =
|
|
1055
|
+
request.limit ?? ProfileAggregationService.DEFAULT_BREAKDOWN_LIMIT;
|
|
1056
|
+
const items: Array<BreakdownItem> = allItems.slice(0, limit);
|
|
1057
|
+
|
|
1058
|
+
for (const item of items) {
|
|
1059
|
+
item.share =
|
|
1060
|
+
totalSampleCount > 0 ? (item.sampleCount / totalSampleCount) * 100 : 0;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
return { items, totalSampleCount };
|
|
1064
|
+
}
|
|
1065
|
+
|
|
480
1066
|
// --- Query builders ---
|
|
481
1067
|
|
|
482
|
-
|
|
1068
|
+
/**
|
|
1069
|
+
* Fetch samples pre-aggregated by stack identity. Collapsing identical
|
|
1070
|
+
* (stacktrace, frameTypes) pairs in ClickHouse shrinks tens of thousands
|
|
1071
|
+
* of raw sample rows to a few hundred unique stacks before they cross
|
|
1072
|
+
* the wire, and the ORDER BY makes the LIMIT drop the smallest stacks
|
|
1073
|
+
* first instead of an arbitrary subset.
|
|
1074
|
+
*
|
|
1075
|
+
* `value` is stored as Int128 in ClickHouse, so the sum is wrapped in
|
|
1076
|
+
* toFloat64 to keep the JSON output numeric (toFloat64OrZero would fail
|
|
1077
|
+
* with "Illegal type Int128").
|
|
1078
|
+
*/
|
|
1079
|
+
private static buildGroupedStackQuery(request: FlamegraphRequest): Statement {
|
|
483
1080
|
const statement: Statement = SQL`
|
|
484
1081
|
SELECT
|
|
485
1082
|
stacktrace,
|
|
486
1083
|
frameTypes,
|
|
487
|
-
value
|
|
1084
|
+
toFloat64(sum(value)) AS totalValue,
|
|
1085
|
+
count() AS sampleCount
|
|
488
1086
|
FROM ${ProfileAggregationService.TABLE_NAME}
|
|
489
1087
|
WHERE projectId = ${{
|
|
490
1088
|
type: TableColumnType.ObjectID,
|
|
@@ -492,92 +1090,136 @@ export class ProfileAggregationService {
|
|
|
492
1090
|
}}
|
|
493
1091
|
`;
|
|
494
1092
|
|
|
495
|
-
|
|
496
|
-
statement.append(
|
|
497
|
-
SQL` AND profileId = ${{
|
|
498
|
-
type: TableColumnType.Text,
|
|
499
|
-
value: request.profileId,
|
|
500
|
-
}}`,
|
|
501
|
-
);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
if (request.startTime) {
|
|
505
|
-
statement.append(
|
|
506
|
-
SQL` AND time >= ${{
|
|
507
|
-
type: TableColumnType.Date,
|
|
508
|
-
value: request.startTime,
|
|
509
|
-
}}`,
|
|
510
|
-
);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
if (request.endTime) {
|
|
514
|
-
statement.append(
|
|
515
|
-
SQL` AND time <= ${{
|
|
516
|
-
type: TableColumnType.Date,
|
|
517
|
-
value: request.endTime,
|
|
518
|
-
}}`,
|
|
519
|
-
);
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
ProfileAggregationService.appendCommonFilters(statement, request);
|
|
1093
|
+
ProfileAggregationService.appendSampleFilters(statement, request);
|
|
523
1094
|
|
|
524
1095
|
statement.append(
|
|
525
|
-
SQL`
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
1096
|
+
SQL` GROUP BY stacktrace, frameTypes
|
|
1097
|
+
ORDER BY totalValue DESC
|
|
1098
|
+
LIMIT ${{
|
|
1099
|
+
type: TableColumnType.Number,
|
|
1100
|
+
value: ProfileAggregationService.MAX_STACK_FETCH,
|
|
1101
|
+
}}`,
|
|
529
1102
|
);
|
|
530
1103
|
|
|
531
1104
|
/*
|
|
532
|
-
* Cap runtime below the client's 58s request_timeout;
|
|
533
|
-
*
|
|
534
|
-
* yields a partial flamegraph rather than holding a pool connection.
|
|
1105
|
+
* Cap runtime below the client's 58s request_timeout; 'break' yields
|
|
1106
|
+
* a partial (top stacks) result rather than holding a pool connection.
|
|
535
1107
|
*/
|
|
536
1108
|
statement.append(
|
|
537
|
-
|
|
1109
|
+
getQuerySettings({
|
|
1110
|
+
maxExecutionTimeInSeconds: 45,
|
|
1111
|
+
timeoutOverflowMode: "break",
|
|
1112
|
+
}),
|
|
538
1113
|
);
|
|
539
1114
|
|
|
540
1115
|
return statement;
|
|
541
1116
|
}
|
|
542
1117
|
|
|
543
|
-
|
|
544
|
-
|
|
1118
|
+
/**
|
|
1119
|
+
* Grouped-stack query restricted to stacks containing one function, so
|
|
1120
|
+
* a sandwich aggregation never pulls the full window's stacks over the
|
|
1121
|
+
* wire just to discard most of them.
|
|
1122
|
+
*
|
|
1123
|
+
* Stored frame strings are "functionName" + ("@fileName" when fileName
|
|
1124
|
+
* is non-empty) + (":lineNumber" when lineNumber > 0) — see
|
|
1125
|
+
* OtelProfilesIngestService.resolveStackFrames. Line numbers shift
|
|
1126
|
+
* across deploys, so the predicate matches the functionName+fileName
|
|
1127
|
+
* identity only:
|
|
1128
|
+
* - non-empty fileName: exact "fn@file" (no line recorded) OR prefix
|
|
1129
|
+
* "fn@file:" (line recorded);
|
|
1130
|
+
* - empty fileName: the exact bare frame (folded uploads and
|
|
1131
|
+
* address-only frames store just the name — parseFrame treats any
|
|
1132
|
+
* '@'-less frame as all functionName, so equality is the full
|
|
1133
|
+
* match).
|
|
1134
|
+
* The prefix form can overmatch when one colon-bearing fileName is a
|
|
1135
|
+
* prefix of another (parseFrame splits on the LAST colon), so callers
|
|
1136
|
+
* must re-check each frame in memory via parseFrame.
|
|
1137
|
+
*/
|
|
1138
|
+
private static buildFunctionStackQuery(
|
|
1139
|
+
request: FlamegraphRequest,
|
|
1140
|
+
functionName: string,
|
|
1141
|
+
fileName: string,
|
|
545
1142
|
): Statement {
|
|
546
1143
|
const statement: Statement = SQL`
|
|
547
1144
|
SELECT
|
|
548
1145
|
stacktrace,
|
|
549
1146
|
frameTypes,
|
|
550
|
-
value
|
|
1147
|
+
toFloat64(sum(value)) AS totalValue,
|
|
1148
|
+
count() AS sampleCount
|
|
551
1149
|
FROM ${ProfileAggregationService.TABLE_NAME}
|
|
552
1150
|
WHERE projectId = ${{
|
|
553
1151
|
type: TableColumnType.ObjectID,
|
|
554
1152
|
value: request.projectId,
|
|
555
1153
|
}}
|
|
556
|
-
AND time >= ${{
|
|
557
|
-
type: TableColumnType.Date,
|
|
558
|
-
value: request.startTime,
|
|
559
|
-
}}
|
|
560
|
-
AND time <= ${{
|
|
561
|
-
type: TableColumnType.Date,
|
|
562
|
-
value: request.endTime,
|
|
563
|
-
}}
|
|
564
1154
|
`;
|
|
565
1155
|
|
|
566
|
-
ProfileAggregationService.
|
|
1156
|
+
ProfileAggregationService.appendSampleFilters(statement, request);
|
|
1157
|
+
|
|
1158
|
+
if (fileName) {
|
|
1159
|
+
statement.append(
|
|
1160
|
+
SQL` AND arrayExists(x -> (x = ${{
|
|
1161
|
+
type: TableColumnType.Text,
|
|
1162
|
+
value: `${functionName}@${fileName}`,
|
|
1163
|
+
}} OR startsWith(x, ${{
|
|
1164
|
+
type: TableColumnType.Text,
|
|
1165
|
+
value: `${functionName}@${fileName}:`,
|
|
1166
|
+
}})), stacktrace)`,
|
|
1167
|
+
);
|
|
1168
|
+
} else {
|
|
1169
|
+
statement.append(
|
|
1170
|
+
SQL` AND has(stacktrace, ${{
|
|
1171
|
+
type: TableColumnType.Text,
|
|
1172
|
+
value: functionName,
|
|
1173
|
+
}})`,
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
567
1176
|
|
|
568
1177
|
statement.append(
|
|
569
|
-
SQL`
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
1178
|
+
SQL` GROUP BY stacktrace, frameTypes
|
|
1179
|
+
ORDER BY totalValue DESC
|
|
1180
|
+
LIMIT ${{
|
|
1181
|
+
type: TableColumnType.Number,
|
|
1182
|
+
value: ProfileAggregationService.MAX_STACK_FETCH,
|
|
1183
|
+
}}`,
|
|
573
1184
|
);
|
|
574
1185
|
|
|
575
1186
|
/*
|
|
576
1187
|
* Cap runtime below the client's 58s request_timeout; 'break' yields
|
|
577
|
-
* a partial
|
|
1188
|
+
* a partial (top stacks) result rather than holding a pool connection.
|
|
578
1189
|
*/
|
|
579
1190
|
statement.append(
|
|
580
|
-
|
|
1191
|
+
getQuerySettings({
|
|
1192
|
+
maxExecutionTimeInSeconds: 45,
|
|
1193
|
+
timeoutOverflowMode: "break",
|
|
1194
|
+
}),
|
|
1195
|
+
);
|
|
1196
|
+
|
|
1197
|
+
return statement;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
/**
|
|
1201
|
+
* Total of `value` across every sample row matching the filters — no
|
|
1202
|
+
* GROUP BY and no LIMIT, so it stays correct even when the grouped
|
|
1203
|
+
* stack query truncates.
|
|
1204
|
+
*/
|
|
1205
|
+
private static buildWindowTotalQuery(request: FlamegraphRequest): Statement {
|
|
1206
|
+
const statement: Statement = SQL`
|
|
1207
|
+
SELECT
|
|
1208
|
+
toFloat64(sum(value)) AS windowTotal
|
|
1209
|
+
FROM ${ProfileAggregationService.TABLE_NAME}
|
|
1210
|
+
WHERE projectId = ${{
|
|
1211
|
+
type: TableColumnType.ObjectID,
|
|
1212
|
+
value: request.projectId,
|
|
1213
|
+
}}
|
|
1214
|
+
`;
|
|
1215
|
+
|
|
1216
|
+
ProfileAggregationService.appendSampleFilters(statement, request);
|
|
1217
|
+
|
|
1218
|
+
statement.append(
|
|
1219
|
+
getQuerySettings({
|
|
1220
|
+
maxExecutionTimeInSeconds: 45,
|
|
1221
|
+
timeoutOverflowMode: "break",
|
|
1222
|
+
}),
|
|
581
1223
|
);
|
|
582
1224
|
|
|
583
1225
|
return statement;
|
|
@@ -587,32 +1229,33 @@ export class ProfileAggregationService {
|
|
|
587
1229
|
request: ServiceActivityRequest,
|
|
588
1230
|
): Statement {
|
|
589
1231
|
/*
|
|
590
|
-
*
|
|
591
|
-
*
|
|
592
|
-
*
|
|
593
|
-
*
|
|
1232
|
+
* One Profile row per ingested profile with a denormalized sampleCount,
|
|
1233
|
+
* so the per-service ranking never has to touch the (orders of
|
|
1234
|
+
* magnitude larger) ProfileSample table. uniqExact tolerates duplicate
|
|
1235
|
+
* rows for the same profileId from re-ingestion.
|
|
594
1236
|
*/
|
|
595
1237
|
const statement: Statement = SQL`
|
|
596
1238
|
SELECT
|
|
597
|
-
toString(
|
|
598
|
-
|
|
599
|
-
uniqExact(profileId) AS profileCount
|
|
600
|
-
|
|
601
|
-
FROM ${ProfileAggregationService.TABLE_NAME}
|
|
1239
|
+
toString(primaryEntityId) AS primaryEntityId,
|
|
1240
|
+
toFloat64(sum(sampleCount)) AS totalSampleCount,
|
|
1241
|
+
uniqExact(profileId) AS profileCount
|
|
1242
|
+
FROM ${ProfileAggregationService.PROFILE_TABLE_NAME}
|
|
602
1243
|
WHERE projectId = ${{
|
|
603
1244
|
type: TableColumnType.ObjectID,
|
|
604
1245
|
value: request.projectId,
|
|
605
1246
|
}}
|
|
606
|
-
AND
|
|
1247
|
+
AND startTime >= ${{
|
|
607
1248
|
type: TableColumnType.Date,
|
|
608
1249
|
value: request.startTime,
|
|
609
1250
|
}}
|
|
610
|
-
AND
|
|
1251
|
+
AND startTime <= ${{
|
|
611
1252
|
type: TableColumnType.Date,
|
|
612
1253
|
value: request.endTime,
|
|
613
1254
|
}}
|
|
614
1255
|
`;
|
|
615
1256
|
|
|
1257
|
+
statement.append(" AND retentionDate >= now()");
|
|
1258
|
+
|
|
616
1259
|
/*
|
|
617
1260
|
* profileTypes (array) wins over profileType (single) so the UI
|
|
618
1261
|
* can OR together every raw type string in a category.
|
|
@@ -634,8 +1277,8 @@ export class ProfileAggregationService {
|
|
|
634
1277
|
}
|
|
635
1278
|
|
|
636
1279
|
statement.append(
|
|
637
|
-
SQL` GROUP BY
|
|
638
|
-
ORDER BY
|
|
1280
|
+
SQL` GROUP BY primaryEntityId
|
|
1281
|
+
ORDER BY totalSampleCount DESC
|
|
639
1282
|
LIMIT 10000`,
|
|
640
1283
|
);
|
|
641
1284
|
|
|
@@ -644,12 +1287,147 @@ export class ProfileAggregationService {
|
|
|
644
1287
|
* partial service activity rather than holding a pool connection.
|
|
645
1288
|
*/
|
|
646
1289
|
statement.append(
|
|
647
|
-
|
|
1290
|
+
getQuerySettings({
|
|
1291
|
+
maxExecutionTimeInSeconds: 45,
|
|
1292
|
+
timeoutOverflowMode: "break",
|
|
1293
|
+
}),
|
|
648
1294
|
);
|
|
649
1295
|
|
|
650
1296
|
return statement;
|
|
651
1297
|
}
|
|
652
1298
|
|
|
1299
|
+
/**
|
|
1300
|
+
* Per-group volume aggregate over the Profile table for getBreakdown.
|
|
1301
|
+
*
|
|
1302
|
+
* The "service" dimension groups by primaryEntityId (mirroring
|
|
1303
|
+
* buildServiceActivityQuery); any other dimension is a Profile
|
|
1304
|
+
* attribute key, read via the parameter-bound Map subscript
|
|
1305
|
+
* `attributes[key]` — the same O(1) fast path the analytics query
|
|
1306
|
+
* generator uses for map equality. The subscript yields '' for missing
|
|
1307
|
+
* keys, so the != '' guard drops profiles without the attribute.
|
|
1308
|
+
*/
|
|
1309
|
+
private static buildBreakdownQuery(request: BreakdownRequest): Statement {
|
|
1310
|
+
let statement: Statement;
|
|
1311
|
+
|
|
1312
|
+
if (request.breakdownBy === "service") {
|
|
1313
|
+
statement = SQL`
|
|
1314
|
+
SELECT
|
|
1315
|
+
toString(primaryEntityId) AS breakdownValue,
|
|
1316
|
+
toFloat64(sum(sampleCount)) AS totalSampleCount,
|
|
1317
|
+
uniqExact(profileId) AS profileCount
|
|
1318
|
+
FROM ${ProfileAggregationService.PROFILE_TABLE_NAME}
|
|
1319
|
+
WHERE projectId = ${{
|
|
1320
|
+
type: TableColumnType.ObjectID,
|
|
1321
|
+
value: request.projectId,
|
|
1322
|
+
}}
|
|
1323
|
+
`;
|
|
1324
|
+
} else {
|
|
1325
|
+
statement = SQL`
|
|
1326
|
+
SELECT
|
|
1327
|
+
attributes[${{
|
|
1328
|
+
type: TableColumnType.Text,
|
|
1329
|
+
value: request.breakdownBy,
|
|
1330
|
+
}}] AS breakdownValue,
|
|
1331
|
+
toFloat64(sum(sampleCount)) AS totalSampleCount,
|
|
1332
|
+
uniqExact(profileId) AS profileCount
|
|
1333
|
+
FROM ${ProfileAggregationService.PROFILE_TABLE_NAME}
|
|
1334
|
+
WHERE projectId = ${{
|
|
1335
|
+
type: TableColumnType.ObjectID,
|
|
1336
|
+
value: request.projectId,
|
|
1337
|
+
}}
|
|
1338
|
+
AND attributes[${{
|
|
1339
|
+
type: TableColumnType.Text,
|
|
1340
|
+
value: request.breakdownBy,
|
|
1341
|
+
}}] != ''
|
|
1342
|
+
`;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
statement.append(
|
|
1346
|
+
SQL` AND startTime >= ${{
|
|
1347
|
+
type: TableColumnType.Date,
|
|
1348
|
+
value: request.startTime,
|
|
1349
|
+
}} AND startTime <= ${{
|
|
1350
|
+
type: TableColumnType.Date,
|
|
1351
|
+
value: request.endTime,
|
|
1352
|
+
}}`,
|
|
1353
|
+
);
|
|
1354
|
+
|
|
1355
|
+
/*
|
|
1356
|
+
* Read-side retention filter: rows past their per-service retention
|
|
1357
|
+
* stay in their part until the whole part drops (ttl_only_drop_parts).
|
|
1358
|
+
*/
|
|
1359
|
+
statement.append(" AND retentionDate >= now()");
|
|
1360
|
+
|
|
1361
|
+
ProfileAggregationService.appendCommonFilters(statement, request);
|
|
1362
|
+
|
|
1363
|
+
statement.append(
|
|
1364
|
+
SQL` GROUP BY breakdownValue
|
|
1365
|
+
ORDER BY totalSampleCount DESC
|
|
1366
|
+
LIMIT ${{
|
|
1367
|
+
type: TableColumnType.Number,
|
|
1368
|
+
value: ProfileAggregationService.MAX_BREAKDOWN_GROUP_FETCH,
|
|
1369
|
+
}}`,
|
|
1370
|
+
);
|
|
1371
|
+
|
|
1372
|
+
/*
|
|
1373
|
+
* Cap runtime below the client's 58s request_timeout; 'break' yields
|
|
1374
|
+
* a partial (top groups) result rather than holding a pool connection.
|
|
1375
|
+
*/
|
|
1376
|
+
statement.append(
|
|
1377
|
+
getQuerySettings({
|
|
1378
|
+
maxExecutionTimeInSeconds: 45,
|
|
1379
|
+
timeoutOverflowMode: "break",
|
|
1380
|
+
}),
|
|
1381
|
+
);
|
|
1382
|
+
|
|
1383
|
+
return statement;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
/**
|
|
1387
|
+
* Shared WHERE-clause tail for ProfileSample reads: optional profileId /
|
|
1388
|
+
* time-window filters, the read-side retention filter, and the common
|
|
1389
|
+
* service / profile-type filters.
|
|
1390
|
+
*/
|
|
1391
|
+
private static appendSampleFilters(
|
|
1392
|
+
statement: Statement,
|
|
1393
|
+
request: FlamegraphRequest,
|
|
1394
|
+
): void {
|
|
1395
|
+
if (request.profileId) {
|
|
1396
|
+
statement.append(
|
|
1397
|
+
SQL` AND profileId = ${{
|
|
1398
|
+
type: TableColumnType.Text,
|
|
1399
|
+
value: request.profileId,
|
|
1400
|
+
}}`,
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
if (request.startTime) {
|
|
1405
|
+
statement.append(
|
|
1406
|
+
SQL` AND time >= ${{
|
|
1407
|
+
type: TableColumnType.Date,
|
|
1408
|
+
value: request.startTime,
|
|
1409
|
+
}}`,
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
if (request.endTime) {
|
|
1414
|
+
statement.append(
|
|
1415
|
+
SQL` AND time <= ${{
|
|
1416
|
+
type: TableColumnType.Date,
|
|
1417
|
+
value: request.endTime,
|
|
1418
|
+
}}`,
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
/*
|
|
1423
|
+
* Read-side retention filter: rows past their per-service retention
|
|
1424
|
+
* stay in their part until the whole part drops (ttl_only_drop_parts).
|
|
1425
|
+
*/
|
|
1426
|
+
statement.append(" AND retentionDate >= now()");
|
|
1427
|
+
|
|
1428
|
+
ProfileAggregationService.appendCommonFilters(statement, request);
|
|
1429
|
+
}
|
|
1430
|
+
|
|
653
1431
|
private static appendCommonFilters(
|
|
654
1432
|
statement: Statement,
|
|
655
1433
|
request: Pick<
|
|
@@ -659,7 +1437,7 @@ export class ProfileAggregationService {
|
|
|
659
1437
|
): void {
|
|
660
1438
|
if (request.serviceIds && request.serviceIds.length > 0) {
|
|
661
1439
|
statement.append(
|
|
662
|
-
SQL` AND
|
|
1440
|
+
SQL` AND primaryEntityId IN (${{
|
|
663
1441
|
type: TableColumnType.ObjectID,
|
|
664
1442
|
value: new Includes(
|
|
665
1443
|
request.serviceIds.map((id: ObjectID) => {
|