@oneuptime/common 12.0.15 → 12.0.17

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.
Files changed (718) hide show
  1. package/Models/AnalyticsModels/Index.ts +10 -0
  2. package/Models/AnalyticsModels/LogCountBaseline.ts +174 -0
  3. package/Models/AnalyticsModels/SecurityEvent.ts +794 -0
  4. package/Models/AnalyticsModels/Span.ts +29 -1
  5. package/Models/AnalyticsModels/SpanCountBaseline.ts +198 -0
  6. package/Models/DatabaseModels/Alert.ts +42 -0
  7. package/Models/DatabaseModels/AlertMeasurement.ts +1114 -0
  8. package/Models/DatabaseModels/AlertMeasurementValue.ts +501 -0
  9. package/Models/DatabaseModels/AlertStateTimeline.ts +10 -2
  10. package/Models/DatabaseModels/BillingPaymentMethod.ts +8 -10
  11. package/Models/DatabaseModels/DetectionRule.ts +568 -0
  12. package/Models/DatabaseModels/GoogleSecOpsConnection.ts +382 -0
  13. package/Models/DatabaseModels/Incident.ts +42 -0
  14. package/Models/DatabaseModels/IncidentMeasurement.ts +1114 -0
  15. package/Models/DatabaseModels/IncidentMeasurementValue.ts +501 -0
  16. package/Models/DatabaseModels/IncidentStateTimeline.ts +10 -2
  17. package/Models/DatabaseModels/IncomingCallPolicyLabelRule.ts +36 -0
  18. package/Models/DatabaseModels/IncomingCallPolicyOwnerRule.ts +42 -0
  19. package/Models/DatabaseModels/Index.ts +20 -0
  20. package/Models/DatabaseModels/Label.ts +11 -0
  21. package/Models/DatabaseModels/LlmCostBudget.ts +655 -0
  22. package/Models/DatabaseModels/LlmModelPrice.ts +481 -0
  23. package/Models/DatabaseModels/LogSavedView.ts +87 -0
  24. package/Models/DatabaseModels/MarketingConversion.ts +210 -8
  25. package/Models/DatabaseModels/MetricSavedView.ts +59 -0
  26. package/Models/DatabaseModels/OnCallDutyPolicyLabelRule.ts +36 -0
  27. package/Models/DatabaseModels/OnCallDutyPolicyOwnerRule.ts +42 -0
  28. package/Models/DatabaseModels/OnCallDutyPolicyScheduleLabelRule.ts +36 -0
  29. package/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerRule.ts +42 -0
  30. package/Models/DatabaseModels/Probe.ts +21 -0
  31. package/Models/DatabaseModels/RunbookLabelRule.ts +36 -0
  32. package/Models/DatabaseModels/RunbookOwnerRule.ts +42 -0
  33. package/Models/DatabaseModels/ScheduledMaintenanceMeasurement.ts +1104 -0
  34. package/Models/DatabaseModels/ScheduledMaintenanceMeasurementValue.ts +491 -0
  35. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +10 -2
  36. package/Models/DatabaseModels/StatusPageLabelRule.ts +36 -0
  37. package/Models/DatabaseModels/StatusPageOwnerRule.ts +42 -0
  38. package/Models/DatabaseModels/TableView.ts +15 -0
  39. package/Models/DatabaseModels/Team.ts +13 -0
  40. package/Models/DatabaseModels/TeamMember.ts +8 -0
  41. package/Models/DatabaseModels/TraceSavedView.ts +52 -0
  42. package/Models/DatabaseModels/WorkflowLabelRule.ts +36 -0
  43. package/Models/DatabaseModels/WorkflowOwnerRule.ts +42 -0
  44. package/Server/API/TelemetryAPI.ts +252 -6
  45. package/Server/API/UserAPI.ts +88 -0
  46. package/Server/EnvironmentConfig.ts +36 -1
  47. package/Server/Infrastructure/Postgres/SchemaMigrations/1788000000000-AddDetectionRuleAndGoogleSecOpsConnection.ts +88 -0
  48. package/Server/Infrastructure/Postgres/SchemaMigrations/1788100000000-AddMeasurements.ts +457 -0
  49. package/Server/Infrastructure/Postgres/SchemaMigrations/1788200000000-AddLlmCostBudget.ts +97 -0
  50. package/Server/Infrastructure/Postgres/SchemaMigrations/1788300000000-AddLlmModelPrice.ts +45 -0
  51. package/Server/Infrastructure/Postgres/SchemaMigrations/1788400000000-AddMarketingConversionAttribution.ts +105 -0
  52. package/Server/Infrastructure/Postgres/SchemaMigrations/1788500000000-RemoveLlmCostBudgetAlertColumns.ts +77 -0
  53. package/Server/Infrastructure/Postgres/SchemaMigrations/1788600000000-AddDetectionRuleIncidentColumns.ts +39 -0
  54. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
  55. package/Server/Middleware/IdentityRateLimit.ts +672 -0
  56. package/Server/Services/AccessTokenService.ts +15 -2
  57. package/Server/Services/AlertMeasurementService.ts +302 -0
  58. package/Server/Services/AlertMeasurementValueService.ts +508 -0
  59. package/Server/Services/AlertService.ts +50 -0
  60. package/Server/Services/AlertStateTimelineService.ts +54 -0
  61. package/Server/Services/DetectionRuleService.ts +74 -0
  62. package/Server/Services/GoogleSecOpsConnectionService.ts +89 -0
  63. package/Server/Services/IncidentMeasurementService.ts +304 -0
  64. package/Server/Services/IncidentMeasurementValueService.ts +523 -0
  65. package/Server/Services/IncidentService.ts +51 -0
  66. package/Server/Services/IncidentStateTimelineService.ts +54 -0
  67. package/Server/Services/Index.ts +30 -0
  68. package/Server/Services/LlmCostBudgetService.ts +93 -0
  69. package/Server/Services/LlmModelPriceService.ts +202 -0
  70. package/Server/Services/LogAggregationService.ts +1106 -2
  71. package/Server/Services/LogCountBaselineService.ts +163 -0
  72. package/Server/Services/MutableMetricService.ts +30 -9
  73. package/Server/Services/ScheduledMaintenanceMeasurementService.ts +311 -0
  74. package/Server/Services/ScheduledMaintenanceMeasurementValueService.ts +546 -0
  75. package/Server/Services/ScheduledMaintenanceService.ts +53 -0
  76. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +188 -1
  77. package/Server/Services/SecurityEventService.ts +104 -0
  78. package/Server/Services/SpanCountBaselineService.ts +173 -0
  79. package/Server/Services/StatusPageService.ts +4 -3
  80. package/Server/Services/TelemetryUsageBillingService.ts +17 -2
  81. package/Server/Services/UserService.ts +284 -51
  82. package/Server/Services/UserTotpAuthService.ts +27 -86
  83. package/Server/Services/UserWebAuthnService.ts +26 -86
  84. package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +14 -0
  85. package/Server/Types/Database/Permissions/TenantPermission.ts +10 -0
  86. package/Server/Types/Database/QueryHelper.ts +1 -1
  87. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
  88. package/Server/Utils/AI/Toolbox/Index.ts +6 -0
  89. package/Server/Utils/AI/Toolbox/SecurityEventTools.ts +349 -0
  90. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +13 -4
  91. package/Server/Utils/Attribution.ts +130 -34
  92. package/Server/Utils/Marketing/ConversionUploadProvider.ts +98 -16
  93. package/Server/Utils/Marketing/Providers/GoogleAds.ts +70 -7
  94. package/Server/Utils/Marketing/Providers/LinkedIn.ts +54 -16
  95. package/Server/Utils/Marketing/Providers/Meta.ts +52 -18
  96. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +37 -10
  97. package/Server/Utils/Marketing/Providers/Reddit.ts +45 -15
  98. package/Server/Utils/Measurement/MeasurementDefinitionValidator.ts +209 -0
  99. package/Server/Utils/Measurement/MeasurementMetricWriter.ts +189 -0
  100. package/Server/Utils/Monitor/Criteria/CountAnomaly.ts +182 -0
  101. package/Server/Utils/Monitor/Criteria/LogMonitorCriteria.ts +132 -0
  102. package/Server/Utils/Monitor/Criteria/SecurityEventsMonitorCriteria.ts +35 -0
  103. package/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.ts +132 -0
  104. package/Server/Utils/Monitor/DataToProcess.ts +2 -0
  105. package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
  106. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +15 -0
  107. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +20 -0
  108. package/Server/Utils/Monitor/MonitorResource.ts +16 -0
  109. package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +1 -0
  110. package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +1 -0
  111. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +805 -0
  112. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.ts +262 -0
  113. package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +212 -0
  114. package/Server/Utils/SecurityEvent/SecurityEventRow.ts +101 -0
  115. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +635 -0
  116. package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +379 -0
  117. package/Server/Utils/Telemetry/LlmSpan.ts +83 -4
  118. package/Server/Utils/Telemetry/LogErrorPatternSql.ts +136 -0
  119. package/Server/Utils/UserPermission/UserPermission.ts +57 -1
  120. package/Tests/App/Dashboard/AlertsSideMenu.test.tsx +4 -0
  121. package/Tests/App/Dashboard/CreatePageEntryPointPermissions.test.tsx +306 -0
  122. package/Tests/App/Dashboard/DangerZone.test.tsx +11 -0
  123. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +4 -0
  124. package/Tests/App/Dashboard/LogMonitorAttributeOperatorPreview.test.tsx +459 -0
  125. package/Tests/App/Dashboard/OverviewCustomFields.test.tsx +24 -0
  126. package/Tests/App/Dashboard/ScheduledMaintenanceSideMenu.test.tsx +6 -0
  127. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +250 -0
  128. package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +106 -0
  129. package/Tests/App/Dashboard/SecurityEventsMonitorsPage.test.tsx +185 -0
  130. package/Tests/App/Dashboard/SecurityEventsSetupGuide.test.tsx +200 -0
  131. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +323 -0
  132. package/Tests/Models/DatabaseModels/ProjectSharedResources.test.ts +386 -0
  133. package/Tests/Models/DetectionRuleCreateContract.test.ts +35 -0
  134. package/Tests/Server/API/LogErrorPatternAPI.test.ts +811 -0
  135. package/Tests/Server/API/UserAuthenticationAPI.test.ts +11 -0
  136. package/Tests/Server/API/UserProjectsAPI.test.ts +11 -2
  137. package/Tests/Server/API/UserTwoFactorAuthAdminAPI.test.ts +918 -0
  138. package/Tests/Server/Infrastructure/LocalCache.test.ts +149 -0
  139. package/Tests/Server/Services/AccessTokenProjectUserGrant.test.ts +249 -0
  140. package/Tests/Server/Services/AlertMeasurementService.test.ts +665 -0
  141. package/Tests/Server/Services/AlertMeasurementValueService.test.ts +389 -0
  142. package/Tests/Server/Services/DetectionRuleService.test.ts +254 -0
  143. package/Tests/Server/Services/IncidentMeasurementService.test.ts +394 -0
  144. package/Tests/Server/Services/IncidentMeasurementValueService.test.ts +816 -0
  145. package/Tests/Server/Services/LlmCostBudgetService.test.ts +104 -0
  146. package/Tests/Server/Services/LogAggregationAttributeOperators.test.ts +405 -0
  147. package/Tests/Server/Services/LogErrorPatternAggregation.test.ts +804 -0
  148. package/Tests/Server/Services/MutableMetricNameRouting.test.ts +83 -0
  149. package/Tests/Server/Services/ScheduledMaintenanceMeasurementService.test.ts +750 -0
  150. package/Tests/Server/Services/ScheduledMaintenanceMeasurementValueService.test.ts +478 -0
  151. package/Tests/Server/Services/UserAuthenticationService.test.ts +216 -4
  152. package/Tests/Server/Services/UserTwoFactorAuthAdmin.test.ts +1190 -0
  153. package/Tests/Server/Types/Database/Permissions/ScopedRoleSharedResourceAccess.test.ts +466 -0
  154. package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +265 -0
  155. package/Tests/Server/Types/Database/QueryHelperTextAndStructuralOperators.test.ts +206 -0
  156. package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +6 -0
  157. package/Tests/Server/Utils/AnalyticsDatabase/FractionalAttributeThreshold.test.ts +224 -0
  158. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +172 -2
  159. package/Tests/Server/Utils/Attribution.test.ts +228 -1
  160. package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +153 -92
  161. package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +123 -6
  162. package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +253 -1
  163. package/Tests/Server/Utils/Marketing/LinkedIn.test.ts +282 -0
  164. package/Tests/Server/Utils/Marketing/Meta.test.ts +304 -0
  165. package/Tests/Server/Utils/Marketing/MicrosoftAds.test.ts +263 -0
  166. package/Tests/Server/Utils/Marketing/Reddit.test.ts +259 -0
  167. package/Tests/Server/Utils/Measurement/MeasurementDefinitionValidator.test.ts +322 -0
  168. package/Tests/Server/Utils/Measurement/MeasurementMetricWriter.test.ts +373 -0
  169. package/Tests/Server/Utils/Monitor/Criteria/CountAnomaly.test.ts +221 -0
  170. package/Tests/Server/Utils/Monitor/Criteria/LogMonitorCriteria.test.ts +236 -0
  171. package/Tests/Server/Utils/Monitor/Criteria/SecurityEventsMonitorCriteria.test.ts +147 -0
  172. package/Tests/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.test.ts +274 -0
  173. package/Tests/Server/Utils/Monitor/SecurityEventsMonitorDataExtractor.test.ts +93 -0
  174. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +1098 -0
  175. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +308 -0
  176. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +271 -0
  177. package/Tests/Server/Utils/SecurityEvent/SecurityEventRow.test.ts +272 -0
  178. package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +511 -0
  179. package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +497 -0
  180. package/Tests/Server/Utils/Telemetry/LlmSpan.test.ts +380 -0
  181. package/Tests/Server/Utils/Telemetry/LogErrorPatternSql.test.ts +207 -0
  182. package/Tests/Server/Utils/UserPermission/ProjectUserGrant.test.ts +293 -0
  183. package/Tests/Types/Monitor/MonitorStepInfraMonitorUtils.test.ts +194 -0
  184. package/Tests/Types/Monitor/MonitorStepSecurityEventsMonitor.test.ts +201 -0
  185. package/Tests/Types/SecurityEvent/OcsfEventClass.test.ts +105 -0
  186. package/Tests/Types/SecurityEvent/OcsfSeverity.test.ts +111 -0
  187. package/Tests/Types/Telemetry/LlmCostCatalog.test.ts +516 -0
  188. package/Tests/UI/Components/ActiveFilterChipsOperatorValues.test.tsx +222 -0
  189. package/Tests/UI/Components/BulkActionPermissionGating.test.tsx +296 -0
  190. package/Tests/UI/Components/CardModelDetailPermissionGating.test.tsx +305 -0
  191. package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +23 -0
  192. package/Tests/UI/Components/DictionaryFilterOperatorDisplay.test.ts +239 -0
  193. package/Tests/UI/Components/DisabledButtonTooltip.test.tsx +267 -0
  194. package/Tests/UI/Components/DuplicateModel.test.tsx +37 -0
  195. package/Tests/UI/Components/ModelCardPermissionGating.test.tsx +348 -0
  196. package/Tests/UI/Components/ModelDelete.test.tsx +25 -1
  197. package/Tests/UI/Components/ModelFormCreatePermission.test.tsx +342 -0
  198. package/Tests/UI/Components/ModelTable/BaseModelTablePermissionGating.test.tsx +680 -0
  199. package/Tests/UI/Components/OrderedStatesListCreateGate.test.tsx +174 -0
  200. package/Tests/UI/Components/SavedViewsDropdownSearch.test.tsx +1127 -0
  201. package/Tests/UI/Components/SavedViewsFacetSection.test.tsx +958 -0
  202. package/Tests/UI/Components/SavedViewsList.test.ts +699 -0
  203. package/Tests/UI/Components/SavedViewsSidebarIntegration.test.tsx +640 -0
  204. package/Tests/UI/Components/SavedViewsSurfaceParity.test.tsx +679 -0
  205. package/Tests/UI/Components/TableViewLoadFailure.test.tsx +248 -0
  206. package/Tests/UI/Types/UseComponentOutsideClick.test.tsx +226 -0
  207. package/Tests/UI/Utils/PermissionGate.test.ts +467 -0
  208. package/Tests/Utils/Measurement/MeasurementEvaluator.test.ts +639 -0
  209. package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
  210. package/Tests/Utils/Monitor/NetworkDeviceLinkRuleUtil.test.ts +285 -0
  211. package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +433 -0
  212. package/Tests/Utils/SecurityEvent/GenericNormalizer.test.ts +204 -0
  213. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.test.ts +252 -0
  214. package/Tests/Utils/SecurityEvent/NormalizerHelpers.test.ts +274 -0
  215. package/Tests/Utils/SecurityEvent/OcsfNormalizer.test.ts +208 -0
  216. package/Tests/Utils/SecurityEvent/SecurityEventNormalizer.test.ts +172 -0
  217. package/Tests/Utils/SecurityEvent/SigmaRuleParser.test.ts +471 -0
  218. package/Tests/Utils/SecurityEvent/UdmNormalizer.test.ts +361 -0
  219. package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +82 -0
  220. package/Tests/Utils/Telemetry/LogErrorPattern.test.ts +463 -0
  221. package/Types/AI/AIChatTypes.ts +1 -0
  222. package/Types/Alerts/AlertMeasurementAnchorType.ts +14 -0
  223. package/Types/Alerts/AlertStateRole.ts +11 -0
  224. package/Types/AnalyticsDatabase/AnalyticsTableName.ts +16 -0
  225. package/Types/Dashboard/Chart/ChartType.ts +1 -0
  226. package/Types/Dashboard/DashboardComponentType.ts +2 -0
  227. package/Types/Dashboard/DashboardComponents/DashboardSecurityEventsFlowComponent.ts +18 -0
  228. package/Types/Dashboard/DashboardComponents/DashboardSecurityEventsListComponent.ts +16 -0
  229. package/Types/Incident/IncidentMeasurementAnchorType.ts +34 -0
  230. package/Types/Incident/IncidentStateRole.ts +14 -0
  231. package/Types/Marketing/Attribution.ts +75 -0
  232. package/Types/Marketing/MarketingConversion.ts +37 -7
  233. package/Types/Measurement/MeasurementAggregationType.ts +43 -0
  234. package/Types/Measurement/MeasurementAnchorKind.ts +23 -0
  235. package/Types/Measurement/MeasurementOccurrence.ts +14 -0
  236. package/Types/Measurement/MeasurementStatus.ts +34 -0
  237. package/Types/MeteredPlan/ProductType.ts +1 -0
  238. package/Types/Monitor/CriteriaFilter.ts +3 -0
  239. package/Types/Monitor/MonitorCriteriaInstance.ts +64 -0
  240. package/Types/Monitor/MonitorStep.ts +28 -0
  241. package/Types/Monitor/MonitorStepSecurityEventsMonitor.ts +100 -0
  242. package/Types/Monitor/MonitorType.ts +20 -0
  243. package/Types/Monitor/SecurityEventsMonitor/SecurityEventsMonitorResponse.ts +17 -0
  244. package/Types/Permission.ts +399 -2
  245. package/Types/ScheduledMaintenance/ScheduledMaintenanceMeasurementAnchorType.ts +20 -0
  246. package/Types/ScheduledMaintenance/ScheduledMaintenanceStateRole.ts +16 -0
  247. package/Types/SecurityEvent/DetectionFindingConstants.ts +24 -0
  248. package/Types/SecurityEvent/NormalizedSecurityEvent.ts +92 -0
  249. package/Types/SecurityEvent/OcsfEventClass.ts +205 -0
  250. package/Types/SecurityEvent/OcsfSeverity.ts +88 -0
  251. package/Types/SecurityEvent/SecurityEventFormat.ts +23 -0
  252. package/Types/SecurityEvent/SigmaRule.ts +70 -0
  253. package/Types/Telemetry/LlmConventions.ts +20 -1
  254. package/Types/Telemetry/LlmCostCatalog.ts +557 -0
  255. package/Types/Telemetry/ServiceType.ts +1 -0
  256. package/Types/Telemetry/TelemetryRetentionConfig.ts +5 -1
  257. package/Types/Telemetry/TelemetryType.ts +1 -0
  258. package/Types/TwoFactorAuthStatus.ts +42 -0
  259. package/Types/UserAuthenticationStatus.ts +18 -0
  260. package/UI/Components/ActionButton/ActionButtonSchema.ts +7 -0
  261. package/UI/Components/BulkUpdate/BulkArchiveActions.tsx +35 -2
  262. package/UI/Components/BulkUpdate/BulkLabelActions.tsx +34 -1
  263. package/UI/Components/BulkUpdate/BulkOwnerActions.tsx +45 -1
  264. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +3 -0
  265. package/UI/Components/Button/Button.tsx +37 -2
  266. package/UI/Components/Card/Card.tsx +6 -0
  267. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +24 -1
  268. package/UI/Components/Dictionary/DictionaryFilterOperator.ts +57 -0
  269. package/UI/Components/DuplicateModel/DuplicateModel.tsx +16 -0
  270. package/UI/Components/Forms/ModelForm.tsx +54 -2
  271. package/UI/Components/List/ListRow.tsx +6 -0
  272. package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +34 -7
  273. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +7 -40
  274. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +155 -3
  275. package/UI/Components/ModelDelete/ModelDelete.tsx +20 -0
  276. package/UI/Components/ModelDetail/CardModelDetail.tsx +36 -23
  277. package/UI/Components/ModelList/ModelList.tsx +21 -2
  278. package/UI/Components/ModelList/StaticModelList.tsx +11 -0
  279. package/UI/Components/ModelTable/BaseModelTable.tsx +168 -62
  280. package/UI/Components/ModelTable/ModelTable.tsx +16 -10
  281. package/UI/Components/ModelTable/TableView.tsx +36 -4
  282. package/UI/Components/MoreMenu/MoreMenuItem.tsx +36 -4
  283. package/UI/Components/OrderedStatesList/Item.tsx +6 -0
  284. package/UI/Components/OrderedStatesList/OrderedStatesList.tsx +81 -47
  285. package/UI/Components/ResetObjectID/ResetObjectID.tsx +16 -0
  286. package/UI/Components/SavedViews/SavedViewsFacetSection.tsx +242 -0
  287. package/UI/Components/SavedViews/SavedViewsList.ts +168 -0
  288. package/UI/Components/SavedViews/SavedViewsSearchInput.tsx +46 -0
  289. package/UI/Components/SavedViews/SavedViewsShowMoreButton.tsx +44 -0
  290. package/UI/Components/Table/TableRow.tsx +12 -0
  291. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +152 -2
  292. package/UI/Types/UseComponentOutsideClick.ts +47 -0
  293. package/UI/Utils/PermissionGate.ts +277 -0
  294. package/Utils/Dashboard/Components/DashboardSecurityEventsFlowComponent.ts +84 -0
  295. package/Utils/Dashboard/Components/DashboardSecurityEventsListComponent.ts +110 -0
  296. package/Utils/Dashboard/Components/Index.ts +14 -0
  297. package/Utils/Measurement/MeasurementEvaluator.ts +359 -0
  298. package/Utils/Monitor/MonitorSummarySnapshotUtil.ts +1 -0
  299. package/Utils/Monitor/NetworkDeviceLinkRuleUtil.ts +93 -11
  300. package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +231 -0
  301. package/Utils/SecurityEvent/GenericNormalizer.ts +208 -0
  302. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +206 -0
  303. package/Utils/SecurityEvent/NormalizerHelpers.ts +263 -0
  304. package/Utils/SecurityEvent/OcsfNormalizer.ts +194 -0
  305. package/Utils/SecurityEvent/SecurityEventNormalizer.ts +82 -0
  306. package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +579 -0
  307. package/Utils/SecurityEvent/UdmNormalizer.ts +442 -0
  308. package/Utils/Telemetry/CrossSignalScope.ts +46 -9
  309. package/Utils/Telemetry/LogErrorPattern.ts +350 -0
  310. package/build/dist/Models/AnalyticsModels/Index.js +10 -0
  311. package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
  312. package/build/dist/Models/AnalyticsModels/LogCountBaseline.js +159 -0
  313. package/build/dist/Models/AnalyticsModels/LogCountBaseline.js.map +1 -0
  314. package/build/dist/Models/AnalyticsModels/SecurityEvent.js +596 -0
  315. package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -0
  316. package/build/dist/Models/AnalyticsModels/Span.js +24 -1
  317. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  318. package/build/dist/Models/AnalyticsModels/SpanCountBaseline.js +181 -0
  319. package/build/dist/Models/AnalyticsModels/SpanCountBaseline.js.map +1 -0
  320. package/build/dist/Models/DatabaseModels/Alert.js +43 -0
  321. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  322. package/build/dist/Models/DatabaseModels/AlertMeasurement.js +1143 -0
  323. package/build/dist/Models/DatabaseModels/AlertMeasurement.js.map +1 -0
  324. package/build/dist/Models/DatabaseModels/AlertMeasurementValue.js +523 -0
  325. package/build/dist/Models/DatabaseModels/AlertMeasurementValue.js.map +1 -0
  326. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +9 -2
  327. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
  328. package/build/dist/Models/DatabaseModels/BillingPaymentMethod.js +10 -11
  329. package/build/dist/Models/DatabaseModels/BillingPaymentMethod.js.map +1 -1
  330. package/build/dist/Models/DatabaseModels/DetectionRule.js +598 -0
  331. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -0
  332. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +410 -0
  333. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -0
  334. package/build/dist/Models/DatabaseModels/Incident.js +43 -0
  335. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  336. package/build/dist/Models/DatabaseModels/IncidentMeasurement.js +1143 -0
  337. package/build/dist/Models/DatabaseModels/IncidentMeasurement.js.map +1 -0
  338. package/build/dist/Models/DatabaseModels/IncidentMeasurementValue.js +523 -0
  339. package/build/dist/Models/DatabaseModels/IncidentMeasurementValue.js.map +1 -0
  340. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +9 -2
  341. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  342. package/build/dist/Models/DatabaseModels/IncomingCallPolicyLabelRule.js +36 -0
  343. package/build/dist/Models/DatabaseModels/IncomingCallPolicyLabelRule.js.map +1 -1
  344. package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerRule.js +42 -0
  345. package/build/dist/Models/DatabaseModels/IncomingCallPolicyOwnerRule.js.map +1 -1
  346. package/build/dist/Models/DatabaseModels/Index.js +20 -0
  347. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  348. package/build/dist/Models/DatabaseModels/Label.js +11 -0
  349. package/build/dist/Models/DatabaseModels/Label.js.map +1 -1
  350. package/build/dist/Models/DatabaseModels/LlmCostBudget.js +681 -0
  351. package/build/dist/Models/DatabaseModels/LlmCostBudget.js.map +1 -0
  352. package/build/dist/Models/DatabaseModels/LlmModelPrice.js +503 -0
  353. package/build/dist/Models/DatabaseModels/LlmModelPrice.js.map +1 -0
  354. package/build/dist/Models/DatabaseModels/LogSavedView.js +87 -0
  355. package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -1
  356. package/build/dist/Models/DatabaseModels/MarketingConversion.js +224 -8
  357. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +1 -1
  358. package/build/dist/Models/DatabaseModels/MetricSavedView.js +59 -0
  359. package/build/dist/Models/DatabaseModels/MetricSavedView.js.map +1 -1
  360. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyLabelRule.js +36 -0
  361. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyLabelRule.js.map +1 -1
  362. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerRule.js +42 -0
  363. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerRule.js.map +1 -1
  364. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLabelRule.js +36 -0
  365. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLabelRule.js.map +1 -1
  366. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerRule.js +42 -0
  367. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleOwnerRule.js.map +1 -1
  368. package/build/dist/Models/DatabaseModels/Probe.js +21 -0
  369. package/build/dist/Models/DatabaseModels/Probe.js.map +1 -1
  370. package/build/dist/Models/DatabaseModels/RunbookLabelRule.js +36 -0
  371. package/build/dist/Models/DatabaseModels/RunbookLabelRule.js.map +1 -1
  372. package/build/dist/Models/DatabaseModels/RunbookOwnerRule.js +42 -0
  373. package/build/dist/Models/DatabaseModels/RunbookOwnerRule.js.map +1 -1
  374. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceMeasurement.js +1133 -0
  375. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceMeasurement.js.map +1 -0
  376. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceMeasurementValue.js +515 -0
  377. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceMeasurementValue.js.map +1 -0
  378. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +9 -2
  379. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  380. package/build/dist/Models/DatabaseModels/StatusPageLabelRule.js +36 -0
  381. package/build/dist/Models/DatabaseModels/StatusPageLabelRule.js.map +1 -1
  382. package/build/dist/Models/DatabaseModels/StatusPageOwnerRule.js +42 -0
  383. package/build/dist/Models/DatabaseModels/StatusPageOwnerRule.js.map +1 -1
  384. package/build/dist/Models/DatabaseModels/TableView.js +15 -0
  385. package/build/dist/Models/DatabaseModels/TableView.js.map +1 -1
  386. package/build/dist/Models/DatabaseModels/Team.js +13 -0
  387. package/build/dist/Models/DatabaseModels/Team.js.map +1 -1
  388. package/build/dist/Models/DatabaseModels/TeamMember.js +8 -0
  389. package/build/dist/Models/DatabaseModels/TeamMember.js.map +1 -1
  390. package/build/dist/Models/DatabaseModels/TraceSavedView.js +52 -0
  391. package/build/dist/Models/DatabaseModels/TraceSavedView.js.map +1 -1
  392. package/build/dist/Models/DatabaseModels/WorkflowLabelRule.js +36 -0
  393. package/build/dist/Models/DatabaseModels/WorkflowLabelRule.js.map +1 -1
  394. package/build/dist/Models/DatabaseModels/WorkflowOwnerRule.js +42 -0
  395. package/build/dist/Models/DatabaseModels/WorkflowOwnerRule.js.map +1 -1
  396. package/build/dist/Server/API/TelemetryAPI.js +136 -0
  397. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  398. package/build/dist/Server/API/UserAPI.js +75 -2
  399. package/build/dist/Server/API/UserAPI.js.map +1 -1
  400. package/build/dist/Server/EnvironmentConfig.js +29 -1
  401. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  402. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788000000000-AddDetectionRuleAndGoogleSecOpsConnection.js +36 -0
  403. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788000000000-AddDetectionRuleAndGoogleSecOpsConnection.js.map +1 -0
  404. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788100000000-AddMeasurements.js +162 -0
  405. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788100000000-AddMeasurements.js.map +1 -0
  406. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788200000000-AddLlmCostBudget.js +40 -0
  407. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788200000000-AddLlmCostBudget.js.map +1 -0
  408. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788300000000-AddLlmModelPrice.js +22 -0
  409. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788300000000-AddLlmModelPrice.js.map +1 -0
  410. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788400000000-AddMarketingConversionAttribution.js +52 -0
  411. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788400000000-AddMarketingConversionAttribution.js.map +1 -0
  412. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788500000000-RemoveLlmCostBudgetAlertColumns.js +38 -0
  413. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788500000000-RemoveLlmCostBudgetAlertColumns.js.map +1 -0
  414. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788600000000-AddDetectionRuleIncidentColumns.js +24 -0
  415. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788600000000-AddDetectionRuleIncidentColumns.js.map +1 -0
  416. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
  417. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  418. package/build/dist/Server/Middleware/IdentityRateLimit.js +491 -0
  419. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -0
  420. package/build/dist/Server/Services/AccessTokenService.js +13 -2
  421. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  422. package/build/dist/Server/Services/AlertMeasurementService.js +250 -0
  423. package/build/dist/Server/Services/AlertMeasurementService.js.map +1 -0
  424. package/build/dist/Server/Services/AlertMeasurementValueService.js +400 -0
  425. package/build/dist/Server/Services/AlertMeasurementValueService.js.map +1 -0
  426. package/build/dist/Server/Services/AlertService.js +37 -0
  427. package/build/dist/Server/Services/AlertService.js.map +1 -1
  428. package/build/dist/Server/Services/AlertStateTimelineService.js +48 -0
  429. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  430. package/build/dist/Server/Services/DetectionRuleService.js +50 -0
  431. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -0
  432. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +55 -0
  433. package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -0
  434. package/build/dist/Server/Services/IncidentMeasurementService.js +252 -0
  435. package/build/dist/Server/Services/IncidentMeasurementService.js.map +1 -0
  436. package/build/dist/Server/Services/IncidentMeasurementValueService.js +413 -0
  437. package/build/dist/Server/Services/IncidentMeasurementValueService.js.map +1 -0
  438. package/build/dist/Server/Services/IncidentService.js +41 -0
  439. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  440. package/build/dist/Server/Services/IncidentStateTimelineService.js +50 -0
  441. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  442. package/build/dist/Server/Services/Index.js +30 -0
  443. package/build/dist/Server/Services/Index.js.map +1 -1
  444. package/build/dist/Server/Services/LlmCostBudgetService.js +89 -0
  445. package/build/dist/Server/Services/LlmCostBudgetService.js.map +1 -0
  446. package/build/dist/Server/Services/LlmModelPriceService.js +163 -0
  447. package/build/dist/Server/Services/LlmModelPriceService.js.map +1 -0
  448. package/build/dist/Server/Services/LogAggregationService.js +709 -0
  449. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  450. package/build/dist/Server/Services/LogCountBaselineService.js +112 -0
  451. package/build/dist/Server/Services/LogCountBaselineService.js.map +1 -0
  452. package/build/dist/Server/Services/MutableMetricService.js +28 -9
  453. package/build/dist/Server/Services/MutableMetricService.js.map +1 -1
  454. package/build/dist/Server/Services/ScheduledMaintenanceMeasurementService.js +254 -0
  455. package/build/dist/Server/Services/ScheduledMaintenanceMeasurementService.js.map +1 -0
  456. package/build/dist/Server/Services/ScheduledMaintenanceMeasurementValueService.js +434 -0
  457. package/build/dist/Server/Services/ScheduledMaintenanceMeasurementValueService.js.map +1 -0
  458. package/build/dist/Server/Services/ScheduledMaintenanceService.js +37 -0
  459. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  460. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +134 -0
  461. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  462. package/build/dist/Server/Services/SecurityEventService.js +64 -0
  463. package/build/dist/Server/Services/SecurityEventService.js.map +1 -0
  464. package/build/dist/Server/Services/SpanCountBaselineService.js +122 -0
  465. package/build/dist/Server/Services/SpanCountBaselineService.js.map +1 -0
  466. package/build/dist/Server/Services/StatusPageService.js +4 -3
  467. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  468. package/build/dist/Server/Services/TelemetryUsageBillingService.js +15 -3
  469. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  470. package/build/dist/Server/Services/UserService.js +262 -42
  471. package/build/dist/Server/Services/UserService.js.map +1 -1
  472. package/build/dist/Server/Services/UserTotpAuthService.js +0 -73
  473. package/build/dist/Server/Services/UserTotpAuthService.js.map +1 -1
  474. package/build/dist/Server/Services/UserWebAuthnService.js +1 -73
  475. package/build/dist/Server/Services/UserWebAuthnService.js.map +1 -1
  476. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +13 -0
  477. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
  478. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +10 -0
  479. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
  480. package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
  481. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  482. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
  483. package/build/dist/Server/Utils/AI/Toolbox/Index.js +3 -0
  484. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  485. package/build/dist/Server/Utils/AI/Toolbox/SecurityEventTools.js +257 -0
  486. package/build/dist/Server/Utils/AI/Toolbox/SecurityEventTools.js.map +1 -0
  487. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +13 -4
  488. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  489. package/build/dist/Server/Utils/Attribution.js +77 -33
  490. package/build/dist/Server/Utils/Attribution.js.map +1 -1
  491. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +46 -9
  492. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +1 -1
  493. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +52 -8
  494. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +1 -1
  495. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +41 -17
  496. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +1 -1
  497. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +42 -18
  498. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +1 -1
  499. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +24 -11
  500. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +1 -1
  501. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +34 -15
  502. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +1 -1
  503. package/build/dist/Server/Utils/Measurement/MeasurementDefinitionValidator.js +109 -0
  504. package/build/dist/Server/Utils/Measurement/MeasurementDefinitionValidator.js.map +1 -0
  505. package/build/dist/Server/Utils/Measurement/MeasurementMetricWriter.js +131 -0
  506. package/build/dist/Server/Utils/Measurement/MeasurementMetricWriter.js.map +1 -0
  507. package/build/dist/Server/Utils/Monitor/Criteria/CountAnomaly.js +111 -0
  508. package/build/dist/Server/Utils/Monitor/Criteria/CountAnomaly.js.map +1 -0
  509. package/build/dist/Server/Utils/Monitor/Criteria/LogMonitorCriteria.js +84 -1
  510. package/build/dist/Server/Utils/Monitor/Criteria/LogMonitorCriteria.js.map +1 -1
  511. package/build/dist/Server/Utils/Monitor/Criteria/SecurityEventsMonitorCriteria.js +35 -0
  512. package/build/dist/Server/Utils/Monitor/Criteria/SecurityEventsMonitorCriteria.js.map +1 -0
  513. package/build/dist/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.js +84 -1
  514. package/build/dist/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.js.map +1 -1
  515. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
  516. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
  517. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +12 -0
  518. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  519. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
  520. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  521. package/build/dist/Server/Utils/Monitor/MonitorResource.js +10 -0
  522. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  523. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +6 -5
  524. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
  525. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +1 -0
  526. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -1
  527. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +600 -0
  528. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -0
  529. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +145 -0
  530. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -0
  531. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +176 -0
  532. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -0
  533. package/build/dist/Server/Utils/SecurityEvent/SecurityEventRow.js +69 -0
  534. package/build/dist/Server/Utils/SecurityEvent/SecurityEventRow.js.map +1 -0
  535. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +493 -0
  536. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -0
  537. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +317 -0
  538. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -0
  539. package/build/dist/Server/Utils/Telemetry/LlmSpan.js +56 -4
  540. package/build/dist/Server/Utils/Telemetry/LlmSpan.js.map +1 -1
  541. package/build/dist/Server/Utils/Telemetry/LogErrorPatternSql.js +112 -0
  542. package/build/dist/Server/Utils/Telemetry/LogErrorPatternSql.js.map +1 -0
  543. package/build/dist/Server/Utils/UserPermission/UserPermission.js +46 -1
  544. package/build/dist/Server/Utils/UserPermission/UserPermission.js.map +1 -1
  545. package/build/dist/Types/AI/AIChatTypes.js +1 -0
  546. package/build/dist/Types/AI/AIChatTypes.js.map +1 -1
  547. package/build/dist/Types/Alerts/AlertMeasurementAnchorType.js +15 -0
  548. package/build/dist/Types/Alerts/AlertMeasurementAnchorType.js.map +1 -0
  549. package/build/dist/Types/Alerts/AlertStateRole.js +12 -0
  550. package/build/dist/Types/Alerts/AlertStateRole.js.map +1 -0
  551. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +16 -0
  552. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
  553. package/build/dist/Types/Dashboard/Chart/ChartType.js +1 -0
  554. package/build/dist/Types/Dashboard/Chart/ChartType.js.map +1 -1
  555. package/build/dist/Types/Dashboard/DashboardComponentType.js +2 -0
  556. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  557. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSecurityEventsFlowComponent.js +2 -0
  558. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSecurityEventsFlowComponent.js.map +1 -0
  559. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSecurityEventsListComponent.js +2 -0
  560. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSecurityEventsListComponent.js.map +1 -0
  561. package/build/dist/Types/Incident/IncidentMeasurementAnchorType.js +29 -0
  562. package/build/dist/Types/Incident/IncidentMeasurementAnchorType.js.map +1 -0
  563. package/build/dist/Types/Incident/IncidentStateRole.js +15 -0
  564. package/build/dist/Types/Incident/IncidentStateRole.js.map +1 -0
  565. package/build/dist/Types/Marketing/Attribution.js +68 -0
  566. package/build/dist/Types/Marketing/Attribution.js.map +1 -0
  567. package/build/dist/Types/Marketing/MarketingConversion.js +36 -7
  568. package/build/dist/Types/Marketing/MarketingConversion.js.map +1 -1
  569. package/build/dist/Types/Measurement/MeasurementAggregationType.js +40 -0
  570. package/build/dist/Types/Measurement/MeasurementAggregationType.js.map +1 -0
  571. package/build/dist/Types/Measurement/MeasurementAnchorKind.js +22 -0
  572. package/build/dist/Types/Measurement/MeasurementAnchorKind.js.map +1 -0
  573. package/build/dist/Types/Measurement/MeasurementOccurrence.js +15 -0
  574. package/build/dist/Types/Measurement/MeasurementOccurrence.js.map +1 -0
  575. package/build/dist/Types/Measurement/MeasurementStatus.js +32 -0
  576. package/build/dist/Types/Measurement/MeasurementStatus.js.map +1 -0
  577. package/build/dist/Types/MeteredPlan/ProductType.js +1 -0
  578. package/build/dist/Types/MeteredPlan/ProductType.js.map +1 -1
  579. package/build/dist/Types/Monitor/CriteriaFilter.js +2 -0
  580. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  581. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +59 -0
  582. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  583. package/build/dist/Types/Monitor/MonitorStep.js +17 -0
  584. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  585. package/build/dist/Types/Monitor/MonitorStepSecurityEventsMonitor.js +64 -0
  586. package/build/dist/Types/Monitor/MonitorStepSecurityEventsMonitor.js.map +1 -0
  587. package/build/dist/Types/Monitor/MonitorType.js +19 -0
  588. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  589. package/build/dist/Types/Monitor/SecurityEventsMonitor/SecurityEventsMonitorResponse.js +2 -0
  590. package/build/dist/Types/Monitor/SecurityEventsMonitor/SecurityEventsMonitorResponse.js.map +1 -0
  591. package/build/dist/Types/Permission.js +347 -2
  592. package/build/dist/Types/Permission.js.map +1 -1
  593. package/build/dist/Types/ScheduledMaintenance/ScheduledMaintenanceMeasurementAnchorType.js +19 -0
  594. package/build/dist/Types/ScheduledMaintenance/ScheduledMaintenanceMeasurementAnchorType.js.map +1 -0
  595. package/build/dist/Types/ScheduledMaintenance/ScheduledMaintenanceStateRole.js +17 -0
  596. package/build/dist/Types/ScheduledMaintenance/ScheduledMaintenanceStateRole.js.map +1 -0
  597. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +18 -0
  598. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -0
  599. package/build/dist/Types/SecurityEvent/NormalizedSecurityEvent.js +2 -0
  600. package/build/dist/Types/SecurityEvent/NormalizedSecurityEvent.js.map +1 -0
  601. package/build/dist/Types/SecurityEvent/OcsfEventClass.js +181 -0
  602. package/build/dist/Types/SecurityEvent/OcsfEventClass.js.map +1 -0
  603. package/build/dist/Types/SecurityEvent/OcsfSeverity.js +81 -0
  604. package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -0
  605. package/build/dist/Types/SecurityEvent/SecurityEventFormat.js +21 -0
  606. package/build/dist/Types/SecurityEvent/SecurityEventFormat.js.map +1 -0
  607. package/build/dist/Types/SecurityEvent/SigmaRule.js +16 -0
  608. package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -0
  609. package/build/dist/Types/Telemetry/LlmConventions.js +19 -1
  610. package/build/dist/Types/Telemetry/LlmConventions.js.map +1 -1
  611. package/build/dist/Types/Telemetry/LlmCostCatalog.js +484 -0
  612. package/build/dist/Types/Telemetry/LlmCostCatalog.js.map +1 -0
  613. package/build/dist/Types/Telemetry/ServiceType.js +1 -0
  614. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  615. package/build/dist/Types/Telemetry/TelemetryRetentionConfig.js.map +1 -1
  616. package/build/dist/Types/Telemetry/TelemetryType.js +1 -0
  617. package/build/dist/Types/Telemetry/TelemetryType.js.map +1 -1
  618. package/build/dist/Types/TwoFactorAuthStatus.js +41 -0
  619. package/build/dist/Types/TwoFactorAuthStatus.js.map +1 -0
  620. package/build/dist/UI/Components/BulkUpdate/BulkArchiveActions.js +16 -2
  621. package/build/dist/UI/Components/BulkUpdate/BulkArchiveActions.js.map +1 -1
  622. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +15 -1
  623. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
  624. package/build/dist/UI/Components/BulkUpdate/BulkOwnerActions.js +20 -1
  625. package/build/dist/UI/Components/BulkUpdate/BulkOwnerActions.js.map +1 -1
  626. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +1 -1
  627. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  628. package/build/dist/UI/Components/Button/Button.js +22 -1
  629. package/build/dist/UI/Components/Button/Button.js.map +1 -1
  630. package/build/dist/UI/Components/Card/Card.js +1 -1
  631. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  632. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +14 -1
  633. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  634. package/build/dist/UI/Components/Dictionary/DictionaryFilterOperator.js +47 -0
  635. package/build/dist/UI/Components/Dictionary/DictionaryFilterOperator.js.map +1 -1
  636. package/build/dist/UI/Components/DuplicateModel/DuplicateModel.js +8 -0
  637. package/build/dist/UI/Components/DuplicateModel/DuplicateModel.js.map +1 -1
  638. package/build/dist/UI/Components/Forms/ModelForm.js +40 -1
  639. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  640. package/build/dist/UI/Components/List/ListRow.js +4 -1
  641. package/build/dist/UI/Components/List/ListRow.js.map +1 -1
  642. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +32 -7
  643. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
  644. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +2 -17
  645. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  646. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +93 -4
  647. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  648. package/build/dist/UI/Components/ModelDelete/ModelDelete.js +13 -0
  649. package/build/dist/UI/Components/ModelDelete/ModelDelete.js.map +1 -1
  650. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +27 -11
  651. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  652. package/build/dist/UI/Components/ModelList/ModelList.js +13 -2
  653. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  654. package/build/dist/UI/Components/ModelList/StaticModelList.js +4 -1
  655. package/build/dist/UI/Components/ModelList/StaticModelList.js.map +1 -1
  656. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +101 -40
  657. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  658. package/build/dist/UI/Components/ModelTable/ModelTable.js +9 -7
  659. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  660. package/build/dist/UI/Components/ModelTable/TableView.js +32 -4
  661. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  662. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +19 -2
  663. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  664. package/build/dist/UI/Components/OrderedStatesList/Item.js +4 -1
  665. package/build/dist/UI/Components/OrderedStatesList/Item.js.map +1 -1
  666. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js +33 -32
  667. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js.map +1 -1
  668. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js +8 -0
  669. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js.map +1 -1
  670. package/build/dist/UI/Components/SavedViews/SavedViewsFacetSection.js +98 -0
  671. package/build/dist/UI/Components/SavedViews/SavedViewsFacetSection.js.map +1 -0
  672. package/build/dist/UI/Components/SavedViews/SavedViewsList.js +99 -0
  673. package/build/dist/UI/Components/SavedViews/SavedViewsList.js.map +1 -0
  674. package/build/dist/UI/Components/SavedViews/SavedViewsSearchInput.js +17 -0
  675. package/build/dist/UI/Components/SavedViews/SavedViewsSearchInput.js.map +1 -0
  676. package/build/dist/UI/Components/SavedViews/SavedViewsShowMoreButton.js +15 -0
  677. package/build/dist/UI/Components/SavedViews/SavedViewsShowMoreButton.js.map +1 -0
  678. package/build/dist/UI/Components/Table/TableRow.js +8 -2
  679. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  680. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +93 -4
  681. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
  682. package/build/dist/UI/Types/UseComponentOutsideClick.js +39 -0
  683. package/build/dist/UI/Types/UseComponentOutsideClick.js.map +1 -1
  684. package/build/dist/UI/Utils/PermissionGate.js +164 -0
  685. package/build/dist/UI/Utils/PermissionGate.js.map +1 -0
  686. package/build/dist/Utils/Dashboard/Components/DashboardSecurityEventsFlowComponent.js +70 -0
  687. package/build/dist/Utils/Dashboard/Components/DashboardSecurityEventsFlowComponent.js.map +1 -0
  688. package/build/dist/Utils/Dashboard/Components/DashboardSecurityEventsListComponent.js +92 -0
  689. package/build/dist/Utils/Dashboard/Components/DashboardSecurityEventsListComponent.js.map +1 -0
  690. package/build/dist/Utils/Dashboard/Components/Index.js +8 -0
  691. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  692. package/build/dist/Utils/Measurement/MeasurementEvaluator.js +210 -0
  693. package/build/dist/Utils/Measurement/MeasurementEvaluator.js.map +1 -0
  694. package/build/dist/Utils/Monitor/MonitorSummarySnapshotUtil.js +1 -0
  695. package/build/dist/Utils/Monitor/MonitorSummarySnapshotUtil.js.map +1 -1
  696. package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js +51 -10
  697. package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js.map +1 -1
  698. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +108 -0
  699. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -0
  700. package/build/dist/Utils/SecurityEvent/GenericNormalizer.js +176 -0
  701. package/build/dist/Utils/SecurityEvent/GenericNormalizer.js.map +1 -0
  702. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +146 -0
  703. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -0
  704. package/build/dist/Utils/SecurityEvent/NormalizerHelpers.js +196 -0
  705. package/build/dist/Utils/SecurityEvent/NormalizerHelpers.js.map +1 -0
  706. package/build/dist/Utils/SecurityEvent/OcsfNormalizer.js +136 -0
  707. package/build/dist/Utils/SecurityEvent/OcsfNormalizer.js.map +1 -0
  708. package/build/dist/Utils/SecurityEvent/SecurityEventNormalizer.js +64 -0
  709. package/build/dist/Utils/SecurityEvent/SecurityEventNormalizer.js.map +1 -0
  710. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +388 -0
  711. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -0
  712. package/build/dist/Utils/SecurityEvent/UdmNormalizer.js +328 -0
  713. package/build/dist/Utils/SecurityEvent/UdmNormalizer.js.map +1 -0
  714. package/build/dist/Utils/Telemetry/CrossSignalScope.js +29 -7
  715. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
  716. package/build/dist/Utils/Telemetry/LogErrorPattern.js +284 -0
  717. package/build/dist/Utils/Telemetry/LogErrorPattern.js.map +1 -0
  718. package/package.json +3 -1
@@ -2,7 +2,7 @@ import { SQL, Statement } from "../Utils/AnalyticsDatabase/Statement";
2
2
  import { getQuerySettings } from "../Utils/AnalyticsDatabase/QuerySettingsHelper";
3
3
  import LogDatabaseService from "./LogService";
4
4
  import TableColumnType from "../../Types/AnalyticsDatabase/TableColumnType";
5
- import { JSONObject } from "../../Types/JSON";
5
+ import { JSONObject, ObjectType } from "../../Types/JSON";
6
6
  import ObjectID from "../../Types/ObjectID";
7
7
  import BadDataException from "../../Types/Exception/BadDataException";
8
8
  import Includes from "../../Types/BaseDatabase/Includes";
@@ -14,6 +14,10 @@ import {
14
14
  appendResourceScopeFilters,
15
15
  ResourceEntityScope,
16
16
  } from "../Utils/Telemetry/ResourceEntityFilter";
17
+ import {
18
+ buildLogErrorPatternExpression,
19
+ clampLogErrorPattern,
20
+ } from "../Utils/Telemetry/LogErrorPatternSql";
17
21
 
18
22
  export interface HistogramBucket {
19
23
  time: string;
@@ -21,7 +25,21 @@ export interface HistogramBucket {
21
25
  count: number;
22
26
  }
23
27
 
24
- export type LogAttributeFilterValue = string | Array<string>;
28
+ /*
29
+ * A serialized QueryOperator (`{_type: "Search", value: "web"}` and friends)
30
+ * — how an attribute filter row that uses any operator other than the
31
+ * implicit `=` arrives over the wire, since every QueryOperator's toJSON()
32
+ * emits this shape. See appendAttributeOperatorFilter.
33
+ */
34
+ export interface SerializedAttributeOperator {
35
+ _type: string;
36
+ value?: unknown;
37
+ }
38
+
39
+ export type LogAttributeFilterValue =
40
+ | string
41
+ | Array<string>
42
+ | SerializedAttributeOperator;
25
43
  export type LogAttributeFilters = Record<string, LogAttributeFilterValue>;
26
44
 
27
45
  export interface HistogramRequest {
@@ -125,6 +143,111 @@ export interface AnalyticsTableRow {
125
143
  count: number;
126
144
  }
127
145
 
146
+ /*
147
+ * ---------------------------------------------------------------------
148
+ * Error-pattern insights
149
+ * ---------------------------------------------------------------------
150
+ *
151
+ * The Logs Insights page answers "what is actually going wrong, and where"
152
+ * by clustering error bodies into patterns (see
153
+ * Common/Utils/Telemetry/LogErrorPattern) and counting the clusters in the
154
+ * database. Everything below shares one filter shape so the top-list and
155
+ * every drill-down run against exactly the same slice of logs — a
156
+ * correlation panel that silently widened its own scope would be worse
157
+ * than no panel at all.
158
+ */
159
+
160
+ /** Severities treated as "an error" when the caller does not say. */
161
+ export const DEFAULT_ERROR_LOG_SEVERITIES: Array<string> = ["Error", "Fatal"];
162
+
163
+ export interface ErrorPatternFilters {
164
+ projectId: ObjectID;
165
+ startTime: Date;
166
+ endTime: Date;
167
+ serviceIds?: Array<ObjectID> | undefined;
168
+ entityKeys?: Array<string> | undefined;
169
+ resourceScopes?: Array<ResourceEntityScope> | undefined;
170
+ /** Defaults to DEFAULT_ERROR_LOG_SEVERITIES when absent or empty. */
171
+ severityTexts?: Array<string> | undefined;
172
+ bodySearchText?: string | undefined;
173
+ traceIds?: Array<string> | undefined;
174
+ spanIds?: Array<string> | undefined;
175
+ sessionIds?: Array<string> | undefined;
176
+ attributes?: LogAttributeFilters | undefined;
177
+ }
178
+
179
+ export interface TopErrorPatternsRequest extends ErrorPatternFilters {
180
+ limit?: number | undefined;
181
+ }
182
+
183
+ export interface TopErrorPattern {
184
+ /** The normalized message every occurrence in this group shares. */
185
+ pattern: string;
186
+ /** The most recent raw body in the group, for display. */
187
+ sampleBody: string;
188
+ count: number;
189
+ /** ClickHouse datetime strings — parse with OneUptimeDate.fromString. */
190
+ firstSeenAt: string;
191
+ lastSeenAt: string;
192
+ /** Distinct services / hosts / clusters this pattern was seen on. */
193
+ resourceCount: number;
194
+ resourceIds: Array<string>;
195
+ severities: Array<string>;
196
+ /** Distinct traces carrying at least one occurrence. */
197
+ traceCount: number;
198
+ sampleTraceIds: Array<string>;
199
+ }
200
+
201
+ export interface ErrorPatternDetailRequest extends ErrorPatternFilters {
202
+ pattern: string;
203
+ limit?: number | undefined;
204
+ }
205
+
206
+ export interface ErrorPatternTimelineRequest extends ErrorPatternDetailRequest {
207
+ bucketSizeInMinutes: number;
208
+ }
209
+
210
+ export interface ErrorPatternTimelinePoint {
211
+ time: string;
212
+ count: number;
213
+ }
214
+
215
+ export interface ErrorPatternCoOccurrence {
216
+ pattern: string;
217
+ sampleBody: string;
218
+ count: number;
219
+ }
220
+
221
+ export interface ErrorPatternAttribute {
222
+ key: string;
223
+ value: string;
224
+ count: number;
225
+ }
226
+
227
+ export interface ErrorPatternResource {
228
+ resourceId: string;
229
+ resourceType: string;
230
+ count: number;
231
+ lastSeenAt: string;
232
+ }
233
+
234
+ export interface ErrorPatternTrace {
235
+ traceId: string;
236
+ count: number;
237
+ lastSeenAt: string;
238
+ resourceId: string;
239
+ }
240
+
241
+ export interface ErrorPatternSample {
242
+ logId: string;
243
+ time: string;
244
+ body: string;
245
+ severityText: string;
246
+ resourceId: string;
247
+ traceId: string;
248
+ spanId: string;
249
+ }
250
+
128
251
  export class LogAggregationService {
129
252
  private static readonly DEFAULT_FACET_LIMIT: number = 500;
130
253
  private static readonly TABLE_NAME: string = AnalyticsTableName.Log;
@@ -902,6 +1025,26 @@ export class LogAggregationService {
902
1025
  value: new Includes(attrValue),
903
1026
  }}), mapKeys(attributes), mapValues(attributes))`,
904
1027
  );
1028
+ } else if (typeof attrValue === "object" && attrValue !== null) {
1029
+ LogAggregationService.appendAttributeOperatorFilter(
1030
+ statement,
1031
+ attrKey,
1032
+ attrValue as unknown as Record<string, unknown>,
1033
+ );
1034
+ } else if (attrValue === "") {
1035
+ /*
1036
+ * A blank equality value is "missing or empty", not "present and
1037
+ * empty": the list query compares `attributes['k'] = ''`, and a Map
1038
+ * subscript returns the type default for a key the row does not
1039
+ * carry, so rows without the attribute match too. Routed through the
1040
+ * operator builder so a bare "" and an explicit EqualTo("") — the
1041
+ * same filter written two ways — cannot disagree.
1042
+ */
1043
+ LogAggregationService.appendAttributeOperatorFilter(
1044
+ statement,
1045
+ attrKey,
1046
+ { _type: ObjectType.IsNull },
1047
+ );
905
1048
  } else {
906
1049
  statement.append(
907
1050
  SQL` AND arrayExists((k, v) -> lowerUTF8(k) = lowerUTF8(${{
@@ -917,6 +1060,299 @@ export class LogAggregationService {
917
1060
  }
918
1061
  }
919
1062
 
1063
+ /*
1064
+ * Attribute filter rows carry an operator (`contains`, `is any of`,
1065
+ * `is empty`, ...) as well as a value, and the operator travels over the
1066
+ * wire as the serialized `{_type, value}` shape every QueryOperator's
1067
+ * toJSON() produces. The list query compiles those through
1068
+ * StatementGenerator; these aggregation endpoints (histogram, facets,
1069
+ * export) used to treat anything non-array as a plain string, so an
1070
+ * operator object bound as "[object Object]", matched nothing, and left the
1071
+ * log monitor preview showing an empty chart beside a populated list.
1072
+ *
1073
+ * Predicates mirror StatementGenerator's map-attribute branches, in the
1074
+ * case-insensitive arrayExists form the rest of this builder uses — these
1075
+ * keys are typed by a user, not canonical column names.
1076
+ */
1077
+ private static appendAttributeOperatorFilter(
1078
+ statement: Statement,
1079
+ attrKey: string,
1080
+ attrValue: Record<string, unknown>,
1081
+ ): void {
1082
+ const operatorType: unknown = attrValue["_type"];
1083
+ const rawValue: unknown = attrValue["value"];
1084
+
1085
+ type MatchesFunction = (predicate: Statement) => Statement;
1086
+
1087
+ // `<key> matches case-insensitively AND <predicate>` over the map pairs.
1088
+ const matches: MatchesFunction = (predicate: Statement): Statement => {
1089
+ return SQL`arrayExists((k, v) -> lowerUTF8(k) = lowerUTF8(${{
1090
+ type: TableColumnType.Text,
1091
+ value: attrKey,
1092
+ }}) AND `
1093
+ .append(predicate)
1094
+ .append(SQL`, mapKeys(attributes), mapValues(attributes))`);
1095
+ };
1096
+
1097
+ type RequirePrimitiveFunction = (
1098
+ value: unknown,
1099
+ ) => string | number | boolean | null;
1100
+
1101
+ /*
1102
+ * `value` is unvalidated JSON off the wire. `String()` and `Number()` do
1103
+ * not merely produce a bad result on an object — ToPrimitive THROWS a
1104
+ * TypeError when the object shadows toString/valueOf with non-callables
1105
+ * (`{"toString": 1}`), and that escapes the BadDataException the default
1106
+ * branch raises, answering with a 500 instead of a 400. Narrow to
1107
+ * primitives first so every rejection goes out the same door.
1108
+ */
1109
+ const requirePrimitive: RequirePrimitiveFunction = (
1110
+ value: unknown,
1111
+ ): string | number | boolean | null => {
1112
+ if (value === undefined || value === null) {
1113
+ return null;
1114
+ }
1115
+
1116
+ if (
1117
+ typeof value === "string" ||
1118
+ typeof value === "number" ||
1119
+ typeof value === "boolean"
1120
+ ) {
1121
+ return value;
1122
+ }
1123
+
1124
+ throw new BadDataException(
1125
+ `Invalid value in the attribute filter for "${attrKey}"`,
1126
+ );
1127
+ };
1128
+
1129
+ type TextValueFunction = () => string;
1130
+
1131
+ const textValue: TextValueFunction = (): string => {
1132
+ const primitive: string | number | boolean | null =
1133
+ requirePrimitive(rawValue);
1134
+
1135
+ return primitive === null ? "" : String(primitive);
1136
+ };
1137
+
1138
+ type LikeFunction = (pattern: string) => Statement;
1139
+
1140
+ const like: LikeFunction = (pattern: string): Statement => {
1141
+ return SQL`v ILIKE ${{
1142
+ type: TableColumnType.Text,
1143
+ value: pattern,
1144
+ }}`;
1145
+ };
1146
+
1147
+ type NumericFunction = (comparison: string) => Statement;
1148
+
1149
+ /*
1150
+ * Map values are stored as text; toFloat64OrNull yields NULL for
1151
+ * non-numeric values (including the empty default for a missing key),
1152
+ * which compares false against any threshold and drops those rows.
1153
+ */
1154
+ const numeric: NumericFunction = (comparison: string): Statement => {
1155
+ const primitive: string | number | boolean | null =
1156
+ requirePrimitive(rawValue);
1157
+ const threshold: number = Number(primitive);
1158
+
1159
+ /*
1160
+ * Reject rather than bind. `Number(null)` is 0, so a filter with no
1161
+ * value would silently become "> 0", and a non-numeric one binds as the
1162
+ * literal `nan`, which ClickHouse cannot parse — a 500 where the user
1163
+ * should get a 400 naming the filter.
1164
+ */
1165
+ if (
1166
+ primitive === null ||
1167
+ primitive === "" ||
1168
+ !Number.isFinite(threshold)
1169
+ ) {
1170
+ throw new BadDataException(
1171
+ `The attribute filter for "${attrKey}" needs a numeric value`,
1172
+ );
1173
+ }
1174
+
1175
+ /*
1176
+ * Decimal (ClickHouse Double), not Number (Int32): the left-hand side is
1177
+ * a Float64 and thresholds are free text, so `> 1.5` bound as Int32 is a
1178
+ * parse error at the database rather than a comparison.
1179
+ *
1180
+ * The comparison itself is appended as raw SQL — an interpolation in the
1181
+ * SQL tag becomes a bound Identifier, which is not what `>` is. Every
1182
+ * caller passes a literal from the switch below, never user input.
1183
+ */
1184
+ return SQL`toFloat64OrNull(v) `.append(comparison).append(
1185
+ SQL` ${{
1186
+ type: TableColumnType.Decimal,
1187
+ value: threshold,
1188
+ }}`,
1189
+ );
1190
+ };
1191
+
1192
+ type MembershipValuesFunction = () => Array<string>;
1193
+
1194
+ const membershipValues: MembershipValuesFunction = (): Array<string> => {
1195
+ return Array.isArray(rawValue)
1196
+ ? rawValue.map((entry: unknown) => {
1197
+ const primitive: string | number | boolean | null =
1198
+ requirePrimitive(entry);
1199
+
1200
+ return primitive === null ? "" : String(primitive);
1201
+ })
1202
+ : [];
1203
+ };
1204
+
1205
+ type HasNonEmptyValueFunction = () => Statement;
1206
+
1207
+ /*
1208
+ * "the key is present with a non-empty value".
1209
+ *
1210
+ * A ClickHouse Map subscript returns the value type's default for a
1211
+ * missing key, so the list query's `attributes['k']` reads as '' for a row
1212
+ * that has no such attribute at all. That makes an EMPTY comparison value
1213
+ * mean something different from every other value, in both directions:
1214
+ * `attributes['k'] = ''` matches rows that lack the key, and
1215
+ * `attributes['k'] != ''` drops them. Naively negating the existence test
1216
+ * gets both backwards — an "is not equal to <blank>" filter counted every
1217
+ * row in the project while the list beside it counted only the handful
1218
+ * that carried the attribute.
1219
+ */
1220
+ const hasNonEmptyValue: HasNonEmptyValueFunction = (): Statement => {
1221
+ return matches(SQL`v != ''`);
1222
+ };
1223
+
1224
+ switch (operatorType) {
1225
+ case ObjectType.EqualTo:
1226
+ if (textValue() === "") {
1227
+ // `attributes['k'] = ''` — missing or empty. Same set as "is empty".
1228
+ statement.append(SQL` AND NOT `.append(hasNonEmptyValue()));
1229
+ return;
1230
+ }
1231
+
1232
+ statement.append(
1233
+ SQL` AND `.append(
1234
+ matches(
1235
+ SQL`v = ${{
1236
+ type: TableColumnType.Text,
1237
+ value: textValue(),
1238
+ }}`,
1239
+ ),
1240
+ ),
1241
+ );
1242
+ return;
1243
+
1244
+ case ObjectType.NotEqual:
1245
+ if (textValue() === "") {
1246
+ /*
1247
+ * `attributes['k'] != ''` — present AND non-empty. Same set as
1248
+ * "is not empty"; see hasNonEmptyValue above for why blank is
1249
+ * special.
1250
+ */
1251
+ statement.append(SQL` AND `.append(hasNonEmptyValue()));
1252
+ return;
1253
+ }
1254
+
1255
+ /*
1256
+ * Negating the whole existence test is what makes rows that lack the
1257
+ * attribute pass, matching the map-subscript form's semantics (a
1258
+ * missing key reads as '' and so is != a non-empty value).
1259
+ */
1260
+ statement.append(
1261
+ SQL` AND NOT `.append(
1262
+ matches(
1263
+ SQL`v = ${{
1264
+ type: TableColumnType.Text,
1265
+ value: textValue(),
1266
+ }}`,
1267
+ ),
1268
+ ),
1269
+ );
1270
+ return;
1271
+
1272
+ case ObjectType.Search:
1273
+ statement.append(SQL` AND `.append(matches(like(`%${textValue()}%`))));
1274
+ return;
1275
+
1276
+ case ObjectType.NotContains:
1277
+ statement.append(
1278
+ SQL` AND NOT `.append(matches(like(`%${textValue()}%`))),
1279
+ );
1280
+ return;
1281
+
1282
+ case ObjectType.StartsWith:
1283
+ statement.append(SQL` AND `.append(matches(like(`${textValue()}%`))));
1284
+ return;
1285
+
1286
+ case ObjectType.EndsWith:
1287
+ statement.append(SQL` AND `.append(matches(like(`%${textValue()}`))));
1288
+ return;
1289
+
1290
+ case ObjectType.GreaterThan:
1291
+ statement.append(SQL` AND `.append(matches(numeric(">"))));
1292
+ return;
1293
+
1294
+ case ObjectType.GreaterThanOrEqual:
1295
+ statement.append(SQL` AND `.append(matches(numeric(">="))));
1296
+ return;
1297
+
1298
+ case ObjectType.LessThan:
1299
+ statement.append(SQL` AND `.append(matches(numeric("<"))));
1300
+ return;
1301
+
1302
+ case ObjectType.LessThanOrEqual:
1303
+ statement.append(SQL` AND `.append(matches(numeric("<="))));
1304
+ return;
1305
+
1306
+ case ObjectType.IsNull:
1307
+ // "is empty" — no non-empty value stored under that key.
1308
+ statement.append(SQL` AND NOT `.append(hasNonEmptyValue()));
1309
+ return;
1310
+
1311
+ case ObjectType.NotNull:
1312
+ statement.append(SQL` AND `.append(hasNonEmptyValue()));
1313
+ return;
1314
+
1315
+ case ObjectType.Includes:
1316
+ case ObjectType.IncludesNone: {
1317
+ const values: Array<string> = membershipValues();
1318
+
1319
+ /*
1320
+ * An empty membership list means "All", not "nothing" — skipping the
1321
+ * predicate matches how StatementGenerator and the form treat it, and
1322
+ * avoids emitting `IN ()`.
1323
+ */
1324
+ if (values.length === 0) {
1325
+ return;
1326
+ }
1327
+
1328
+ const membership: Statement = matches(
1329
+ SQL`v IN (${{
1330
+ type: TableColumnType.Text,
1331
+ value: new Includes(values),
1332
+ }})`,
1333
+ );
1334
+
1335
+ statement.append(
1336
+ (operatorType === ObjectType.Includes
1337
+ ? SQL` AND `
1338
+ : SQL` AND NOT `
1339
+ ).append(membership),
1340
+ );
1341
+ return;
1342
+ }
1343
+
1344
+ default:
1345
+ /*
1346
+ * An unrecognized shape is a filter this builder cannot honour.
1347
+ * Refuse it rather than binding an object as text and quietly
1348
+ * returning counts that disagree with the logs list.
1349
+ */
1350
+ throw new BadDataException(
1351
+ `Unsupported attribute filter for "${attrKey}"`,
1352
+ );
1353
+ }
1354
+ }
1355
+
920
1356
  @CaptureSpan()
921
1357
  public static async getExportLogs(request: {
922
1358
  projectId: ObjectID;
@@ -1219,6 +1655,674 @@ export class LogAggregationService {
1219
1655
  return { totalLogs, matchingLogs, estimatedReductionPercent };
1220
1656
  }
1221
1657
 
1658
+ // --- Error pattern insights ---
1659
+
1660
+ private static readonly DEFAULT_ERROR_PATTERN_LIMIT: number = 10;
1661
+ private static readonly MAX_ERROR_PATTERN_LIMIT: number = 50;
1662
+ private static readonly ERROR_PATTERN_SAMPLE_ARRAY_LIMIT: number = 5;
1663
+ /* Every severity a pattern can carry fits comfortably in eight slots. */
1664
+ private static readonly ERROR_PATTERN_SEVERITY_ARRAY_LIMIT: number = 8;
1665
+ /*
1666
+ * Cheap pre-filter for bodies that carry no message: they normalize to the
1667
+ * empty pattern, which would otherwise become a meaningless "" group.
1668
+ *
1669
+ * Deliberately only a pre-filter, not the guarantee. ClickHouse's trimBoth
1670
+ * strips SPACES only, so a body of tabs or newlines survives this predicate
1671
+ * and still normalizes to "" once the whitespace rule collapses it. The
1672
+ * grouped reads therefore also carry `HAVING pattern != ''`; this stays
1673
+ * because skipping those rows before aggregation is strictly cheaper than
1674
+ * grouping them and throwing the group away.
1675
+ */
1676
+ private static readonly NON_EMPTY_BODY_FILTER: string =
1677
+ " AND notEmpty(trimBoth(ifNull(body, '')))";
1678
+
1679
+ /*
1680
+ * The actual guarantee that no empty-pattern group is returned. Applied to
1681
+ * every read that GROUPs BY the pattern; the row-returning reads instead
1682
+ * scope to one caller-supplied pattern, which is never "".
1683
+ */
1684
+ private static readonly NON_EMPTY_PATTERN_HAVING: string =
1685
+ " HAVING pattern != ''";
1686
+
1687
+ /**
1688
+ * The distinct error messages in the window, most frequent first.
1689
+ *
1690
+ * This is the "Top Errors" list: one row per pattern with its occurrence
1691
+ * count, when it started and last happened, how many resources it spans,
1692
+ * and enough sample material (a real body, some trace ids) for the UI to
1693
+ * render the row without a second round trip.
1694
+ */
1695
+ @CaptureSpan()
1696
+ public static async getTopErrorPatterns(
1697
+ request: TopErrorPatternsRequest,
1698
+ ): Promise<Array<TopErrorPattern>> {
1699
+ const statement: Statement =
1700
+ LogAggregationService.buildTopErrorPatternsStatement(request);
1701
+
1702
+ const rows: Array<JSONObject> =
1703
+ await LogAggregationService.runQuery(statement);
1704
+
1705
+ return rows
1706
+ .map((row: JSONObject): TopErrorPattern => {
1707
+ return {
1708
+ pattern: String(row["pattern"] || ""),
1709
+ sampleBody: String(row["sampleBody"] || ""),
1710
+ count: Number(row["cnt"] || 0),
1711
+ firstSeenAt: String(row["firstSeen"] || ""),
1712
+ lastSeenAt: String(row["lastSeen"] || ""),
1713
+ resourceCount: Number(row["resourceCount"] || 0),
1714
+ resourceIds: LogAggregationService.toStringArray(row["resourceIds"]),
1715
+ severities: LogAggregationService.toStringArray(row["severities"]),
1716
+ traceCount: Number(row["traceCount"] || 0),
1717
+ sampleTraceIds: LogAggregationService.toStringArray(
1718
+ row["sampleTraceIds"],
1719
+ ),
1720
+ };
1721
+ })
1722
+ .filter((item: TopErrorPattern): boolean => {
1723
+ return item.pattern.length > 0;
1724
+ });
1725
+ }
1726
+
1727
+ /**
1728
+ * When one pattern happened, bucketed over the window — the "is this a
1729
+ * steady drip or a spike at 14:05" question.
1730
+ */
1731
+ @CaptureSpan()
1732
+ public static async getErrorPatternTimeline(
1733
+ request: ErrorPatternTimelineRequest,
1734
+ ): Promise<Array<ErrorPatternTimelinePoint>> {
1735
+ const statement: Statement =
1736
+ LogAggregationService.buildErrorPatternTimelineStatement(request);
1737
+
1738
+ const rows: Array<JSONObject> =
1739
+ await LogAggregationService.runQuery(statement);
1740
+
1741
+ return rows.map((row: JSONObject): ErrorPatternTimelinePoint => {
1742
+ return {
1743
+ time: String(row["bucket"] || ""),
1744
+ count: Number(row["cnt"] || 0),
1745
+ };
1746
+ });
1747
+ }
1748
+
1749
+ /**
1750
+ * Other error patterns that fired in the same time buckets as this one.
1751
+ *
1752
+ * This is the correlation the Insights page exists for: rather than
1753
+ * eyeballing two log lists side by side, the panel names the errors that
1754
+ * keep company with the one under investigation. "Same bucket" is a
1755
+ * deliberately coarse notion of simultaneity — it inherits whatever
1756
+ * bucket size the timeline is drawn at, so a wide window correlates
1757
+ * loosely and a narrow one tightly.
1758
+ */
1759
+ @CaptureSpan()
1760
+ public static async getErrorPatternCoOccurrences(
1761
+ request: ErrorPatternTimelineRequest,
1762
+ ): Promise<Array<ErrorPatternCoOccurrence>> {
1763
+ const statement: Statement =
1764
+ LogAggregationService.buildErrorPatternCoOccurrenceStatement(request);
1765
+
1766
+ const rows: Array<JSONObject> =
1767
+ await LogAggregationService.runQuery(statement);
1768
+
1769
+ return rows
1770
+ .map((row: JSONObject): ErrorPatternCoOccurrence => {
1771
+ return {
1772
+ pattern: String(row["pattern"] || ""),
1773
+ sampleBody: String(row["sampleBody"] || ""),
1774
+ count: Number(row["cnt"] || 0),
1775
+ };
1776
+ })
1777
+ .filter((item: ErrorPatternCoOccurrence): boolean => {
1778
+ return item.pattern.length > 0;
1779
+ });
1780
+ }
1781
+
1782
+ /**
1783
+ * The attribute key/value pairs carried by this pattern's occurrences,
1784
+ * most common first — how the page answers "which host is this?" without
1785
+ * the user having to open a log line and read its attributes.
1786
+ */
1787
+ @CaptureSpan()
1788
+ public static async getErrorPatternAttributes(
1789
+ request: ErrorPatternDetailRequest,
1790
+ ): Promise<Array<ErrorPatternAttribute>> {
1791
+ const statement: Statement =
1792
+ LogAggregationService.buildErrorPatternAttributesStatement(request);
1793
+
1794
+ const rows: Array<JSONObject> =
1795
+ await LogAggregationService.runQuery(statement);
1796
+
1797
+ return rows
1798
+ .map((row: JSONObject): ErrorPatternAttribute => {
1799
+ return {
1800
+ key: String(row["attrKey"] || ""),
1801
+ value: String(row["attrValue"] || ""),
1802
+ count: Number(row["cnt"] || 0),
1803
+ };
1804
+ })
1805
+ .filter((item: ErrorPatternAttribute): boolean => {
1806
+ return item.key.length > 0;
1807
+ });
1808
+ }
1809
+
1810
+ /** Which services / hosts / clusters this pattern is happening on. */
1811
+ @CaptureSpan()
1812
+ public static async getErrorPatternResources(
1813
+ request: ErrorPatternDetailRequest,
1814
+ ): Promise<Array<ErrorPatternResource>> {
1815
+ const statement: Statement =
1816
+ LogAggregationService.buildErrorPatternResourcesStatement(request);
1817
+
1818
+ const rows: Array<JSONObject> =
1819
+ await LogAggregationService.runQuery(statement);
1820
+
1821
+ return rows
1822
+ .map((row: JSONObject): ErrorPatternResource => {
1823
+ return {
1824
+ resourceId: String(row["resourceId"] || ""),
1825
+ resourceType: String(row["resourceType"] || ""),
1826
+ count: Number(row["cnt"] || 0),
1827
+ lastSeenAt: String(row["lastSeen"] || ""),
1828
+ };
1829
+ })
1830
+ .filter((item: ErrorPatternResource): boolean => {
1831
+ return item.resourceId.length > 0;
1832
+ });
1833
+ }
1834
+
1835
+ /**
1836
+ * Traces that carry at least one occurrence — the jump from "this error
1837
+ * happened" to the request it happened inside.
1838
+ */
1839
+ @CaptureSpan()
1840
+ public static async getErrorPatternTraces(
1841
+ request: ErrorPatternDetailRequest,
1842
+ ): Promise<Array<ErrorPatternTrace>> {
1843
+ const statement: Statement =
1844
+ LogAggregationService.buildErrorPatternTracesStatement(request);
1845
+
1846
+ const rows: Array<JSONObject> =
1847
+ await LogAggregationService.runQuery(statement);
1848
+
1849
+ return rows
1850
+ .map((row: JSONObject): ErrorPatternTrace => {
1851
+ return {
1852
+ traceId: String(row["traceId"] || ""),
1853
+ count: Number(row["cnt"] || 0),
1854
+ lastSeenAt: String(row["lastSeen"] || ""),
1855
+ resourceId: String(row["resourceId"] || ""),
1856
+ };
1857
+ })
1858
+ .filter((item: ErrorPatternTrace): boolean => {
1859
+ return item.traceId.length > 0;
1860
+ });
1861
+ }
1862
+
1863
+ /** The most recent raw log lines behind the pattern. */
1864
+ @CaptureSpan()
1865
+ public static async getErrorPatternSamples(
1866
+ request: ErrorPatternDetailRequest,
1867
+ ): Promise<Array<ErrorPatternSample>> {
1868
+ const statement: Statement =
1869
+ LogAggregationService.buildErrorPatternSamplesStatement(request);
1870
+
1871
+ const rows: Array<JSONObject> =
1872
+ await LogAggregationService.runQuery(statement);
1873
+
1874
+ return rows.map((row: JSONObject): ErrorPatternSample => {
1875
+ return {
1876
+ logId: String(row["_id"] || ""),
1877
+ time: String(row["time"] || ""),
1878
+ body: String(row["body"] || ""),
1879
+ severityText: String(row["severityText"] || ""),
1880
+ resourceId: String(row["resourceId"] || ""),
1881
+ traceId: String(row["traceId"] || ""),
1882
+ spanId: String(row["spanId"] || ""),
1883
+ };
1884
+ });
1885
+ }
1886
+
1887
+ private static async runQuery(
1888
+ statement: Statement,
1889
+ ): Promise<Array<JSONObject>> {
1890
+ const dbResult: Results = await LogDatabaseService.executeQuery(statement);
1891
+ const response: DbJSONResponse = await dbResult.json<{
1892
+ data?: Array<JSONObject>;
1893
+ }>();
1894
+
1895
+ return response.data || [];
1896
+ }
1897
+
1898
+ /*
1899
+ * ClickHouse returns array-valued aggregates (groupUniqArray) as JSON
1900
+ * arrays, but a row that reached us through a different serializer could
1901
+ * carry anything — coerce defensively rather than trusting the shape.
1902
+ */
1903
+ private static toStringArray(value: unknown): Array<string> {
1904
+ if (!Array.isArray(value)) {
1905
+ return [];
1906
+ }
1907
+
1908
+ return value
1909
+ .map((item: unknown): string => {
1910
+ return String(item ?? "");
1911
+ })
1912
+ .filter((item: string): boolean => {
1913
+ return item.length > 0;
1914
+ });
1915
+ }
1916
+
1917
+ private static clampErrorPatternLimit(limit: number | undefined): number {
1918
+ if (typeof limit !== "number" || !Number.isFinite(limit)) {
1919
+ return LogAggregationService.DEFAULT_ERROR_PATTERN_LIMIT;
1920
+ }
1921
+
1922
+ return Math.min(
1923
+ Math.max(1, Math.floor(limit)),
1924
+ LogAggregationService.MAX_ERROR_PATTERN_LIMIT,
1925
+ );
1926
+ }
1927
+
1928
+ /*
1929
+ * Error-pattern reads share one WHERE clause so a drill-down can never
1930
+ * see rows the top-list did not. The only thing this adds over
1931
+ * appendCommonFilters is the severity default: a request that names no
1932
+ * severities means "errors", not "every log in the project".
1933
+ */
1934
+ private static appendErrorPatternScope(
1935
+ statement: Statement,
1936
+ request: ErrorPatternFilters,
1937
+ ): void {
1938
+ statement.append(
1939
+ SQL` WHERE projectId = ${{
1940
+ type: TableColumnType.ObjectID,
1941
+ value: request.projectId,
1942
+ }} AND time >= ${{
1943
+ type: TableColumnType.Date,
1944
+ value: request.startTime,
1945
+ }} AND time <= ${{
1946
+ type: TableColumnType.Date,
1947
+ value: request.endTime,
1948
+ }}`,
1949
+ );
1950
+
1951
+ statement.append(LogAggregationService.RETENTION_FILTER);
1952
+ statement.append(LogAggregationService.NON_EMPTY_BODY_FILTER);
1953
+
1954
+ LogAggregationService.appendCommonFilters(statement, {
1955
+ ...request,
1956
+ severityTexts:
1957
+ request.severityTexts && request.severityTexts.length > 0
1958
+ ? request.severityTexts
1959
+ : DEFAULT_ERROR_LOG_SEVERITIES,
1960
+ });
1961
+ }
1962
+
1963
+ /*
1964
+ * ` AND <pattern expression> = '<the pattern>'` — the predicate every
1965
+ * drill-down uses to reduce the window to one cluster. The pattern value
1966
+ * is clamped to the same maximum length the expression truncates to, so
1967
+ * an oversized parameter cannot be used to push a huge constant into the
1968
+ * query (it could only ever match nothing anyway).
1969
+ */
1970
+ private static appendErrorPatternEquality(
1971
+ statement: Statement,
1972
+ pattern: string,
1973
+ ): void {
1974
+ statement.append(" AND ");
1975
+ statement.append(buildLogErrorPatternExpression());
1976
+ statement.append(
1977
+ SQL` = ${{
1978
+ type: TableColumnType.Text,
1979
+ value: clampLogErrorPattern(pattern),
1980
+ }}`,
1981
+ );
1982
+ }
1983
+
1984
+ private static errorPatternQuerySettings(): string {
1985
+ /*
1986
+ * Same ceiling as every other aggregation here: below the client's 58s
1987
+ * request timeout, 'break' so a wide window degrades to partial counts
1988
+ * instead of an error page, and the scan-memory bound because these
1989
+ * queries read the fat `attributes` map alongside `body`.
1990
+ */
1991
+ return getQuerySettings({
1992
+ maxExecutionTimeInSeconds: 45,
1993
+ timeoutOverflowMode: "break",
1994
+ boundScanMemory: true,
1995
+ });
1996
+ }
1997
+
1998
+ private static buildTopErrorPatternsStatement(
1999
+ request: TopErrorPatternsRequest,
2000
+ ): Statement {
2001
+ const limit: number = LogAggregationService.clampErrorPatternLimit(
2002
+ request.limit,
2003
+ );
2004
+ /*
2005
+ * Inlined rather than bound as a parameter: these are the parameters of
2006
+ * a PARAMETRIC aggregate function, which ClickHouse requires to be
2007
+ * constants, and they are trusted class constants rather than anything
2008
+ * a caller supplies.
2009
+ */
2010
+ const sampleLimit: number =
2011
+ LogAggregationService.ERROR_PATTERN_SAMPLE_ARRAY_LIMIT;
2012
+ const severityLimit: number =
2013
+ LogAggregationService.ERROR_PATTERN_SEVERITY_ARRAY_LIMIT;
2014
+
2015
+ const statement: Statement = new Statement();
2016
+
2017
+ statement.append("SELECT ");
2018
+ statement.append(buildLogErrorPatternExpression());
2019
+ statement.append(" AS pattern");
2020
+ statement.append(", count() AS cnt");
2021
+ /*
2022
+ * The newest real body in the group. Showing a raw example alongside
2023
+ * the normalized pattern is what makes a row readable — `<num>` reads
2024
+ * very differently next to the line it came from.
2025
+ */
2026
+ statement.append(", argMax(ifNull(body, ''), time) AS sampleBody");
2027
+ statement.append(", min(time) AS firstSeen");
2028
+ statement.append(", max(time) AS lastSeen");
2029
+ statement.append(", uniqExact(primaryEntityId) AS resourceCount");
2030
+ statement.append(
2031
+ `, groupUniqArray(${sampleLimit})(toString(primaryEntityId)) AS resourceIds`,
2032
+ );
2033
+ statement.append(
2034
+ `, groupUniqArray(${severityLimit})(toString(severityText)) AS severities`,
2035
+ );
2036
+ statement.append(
2037
+ ", uniqExactIf(traceId, ifNull(traceId, '') != '') AS traceCount",
2038
+ );
2039
+ statement.append(
2040
+ `, groupUniqArrayIf(${sampleLimit})(ifNull(traceId, ''), ifNull(traceId, '') != '') AS sampleTraceIds`,
2041
+ );
2042
+ statement.append(` FROM ${LogAggregationService.TABLE_NAME}`);
2043
+
2044
+ LogAggregationService.appendErrorPatternScope(statement, request);
2045
+
2046
+ statement.append(" GROUP BY pattern");
2047
+ statement.append(LogAggregationService.NON_EMPTY_PATTERN_HAVING);
2048
+ statement.append(
2049
+ SQL` ORDER BY cnt DESC LIMIT ${{
2050
+ type: TableColumnType.Number,
2051
+ value: limit,
2052
+ }}`,
2053
+ );
2054
+
2055
+ statement.append(LogAggregationService.errorPatternQuerySettings());
2056
+
2057
+ return statement;
2058
+ }
2059
+
2060
+ private static buildErrorPatternTimelineStatement(
2061
+ request: ErrorPatternTimelineRequest,
2062
+ ): Statement {
2063
+ const intervalSeconds: number =
2064
+ LogAggregationService.resolveBucketSeconds(request);
2065
+
2066
+ const statement: Statement = SQL`SELECT toStartOfInterval(time, INTERVAL ${{
2067
+ type: TableColumnType.Number,
2068
+ value: intervalSeconds,
2069
+ }} SECOND) AS bucket, count() AS cnt`;
2070
+
2071
+ statement.append(` FROM ${LogAggregationService.TABLE_NAME}`);
2072
+
2073
+ LogAggregationService.appendErrorPatternScope(statement, request);
2074
+ LogAggregationService.appendErrorPatternEquality(
2075
+ statement,
2076
+ request.pattern,
2077
+ );
2078
+
2079
+ statement.append(" GROUP BY bucket ORDER BY bucket ASC");
2080
+ statement.append(LogAggregationService.errorPatternQuerySettings());
2081
+
2082
+ return statement;
2083
+ }
2084
+
2085
+ private static buildErrorPatternCoOccurrenceStatement(
2086
+ request: ErrorPatternTimelineRequest,
2087
+ ): Statement {
2088
+ const intervalSeconds: number =
2089
+ LogAggregationService.resolveBucketSeconds(request);
2090
+ const limit: number = LogAggregationService.clampErrorPatternLimit(
2091
+ request.limit,
2092
+ );
2093
+
2094
+ const statement: Statement = new Statement();
2095
+
2096
+ statement.append("SELECT ");
2097
+ statement.append(buildLogErrorPatternExpression());
2098
+ statement.append(" AS pattern");
2099
+ statement.append(", count() AS cnt");
2100
+ statement.append(", argMax(ifNull(body, ''), time) AS sampleBody");
2101
+ statement.append(` FROM ${LogAggregationService.TABLE_NAME}`);
2102
+
2103
+ LogAggregationService.appendErrorPatternScope(statement, request);
2104
+
2105
+ /*
2106
+ * Everything EXCEPT the pattern under investigation. Written as the
2107
+ * full expression rather than the `pattern` alias: ClickHouse
2108
+ * substitutes same-level SELECT aliases into WHERE, and an alias that
2109
+ * shadows nothing today can start shadowing a real column tomorrow.
2110
+ */
2111
+ statement.append(" AND ");
2112
+ statement.append(buildLogErrorPatternExpression());
2113
+ statement.append(
2114
+ SQL` != ${{
2115
+ type: TableColumnType.Text,
2116
+ value: clampLogErrorPattern(request.pattern),
2117
+ }}`,
2118
+ );
2119
+
2120
+ /*
2121
+ * ...restricted to the buckets the investigated pattern itself landed
2122
+ * in.
2123
+ *
2124
+ * GLOBAL IN, not plain IN, and it is load-bearing. This predicate sits
2125
+ * in a query on the Distributed LogItemV3 table whose subquery reads
2126
+ * that SAME Distributed table, which multi-shard ClickHouse rejects
2127
+ * outright as a double-distributed subquery (Code 288,
2128
+ * distributed_product_mode = 'deny' by default) — the panel would throw
2129
+ * on any 2+-shard cluster, and because the endpoint wraps each
2130
+ * correlation read in a degrade-to-empty catch it would fail SILENTLY,
2131
+ * rendering "nothing else was failing" forever.
2132
+ *
2133
+ * A shard-local evaluation would be wrong even where it is allowed: the
2134
+ * sharding key is cityHash64(projectId, primaryEntityId, time), so one
2135
+ * project's rows span every shard and the bucket set has to be computed
2136
+ * once globally. On a single shard GLOBAL is a semantic no-op. Same
2137
+ * reasoning, same shape as MetricService's Top-K group restriction.
2138
+ */
2139
+ statement.append(
2140
+ SQL` AND toStartOfInterval(time, INTERVAL ${{
2141
+ type: TableColumnType.Number,
2142
+ value: intervalSeconds,
2143
+ }} SECOND) GLOBAL IN (SELECT DISTINCT toStartOfInterval(time, INTERVAL ${{
2144
+ type: TableColumnType.Number,
2145
+ value: intervalSeconds,
2146
+ }} SECOND)`,
2147
+ );
2148
+
2149
+ statement.append(` FROM ${LogAggregationService.TABLE_NAME}`);
2150
+
2151
+ LogAggregationService.appendErrorPatternScope(statement, request);
2152
+ LogAggregationService.appendErrorPatternEquality(
2153
+ statement,
2154
+ request.pattern,
2155
+ );
2156
+
2157
+ statement.append(")");
2158
+
2159
+ statement.append(" GROUP BY pattern");
2160
+ statement.append(LogAggregationService.NON_EMPTY_PATTERN_HAVING);
2161
+ statement.append(
2162
+ SQL` ORDER BY cnt DESC LIMIT ${{
2163
+ type: TableColumnType.Number,
2164
+ value: limit,
2165
+ }}`,
2166
+ );
2167
+
2168
+ statement.append(LogAggregationService.errorPatternQuerySettings());
2169
+
2170
+ return statement;
2171
+ }
2172
+
2173
+ private static buildErrorPatternAttributesStatement(
2174
+ request: ErrorPatternDetailRequest,
2175
+ ): Statement {
2176
+ const limit: number = LogAggregationService.clampErrorPatternLimit(
2177
+ request.limit,
2178
+ );
2179
+
2180
+ /*
2181
+ * The ARRAY JOIN runs over a pre-filtered subquery on purpose. Written
2182
+ * flat, the join explodes every row in the window into one row per
2183
+ * attribute BEFORE the WHERE narrows to a single pattern — on a service
2184
+ * carrying twenty resource attributes that is a twentyfold scan for a
2185
+ * result the size of a tooltip.
2186
+ */
2187
+ const statement: Statement = new Statement();
2188
+
2189
+ statement.append(
2190
+ `SELECT attrKey, attrValue, count() AS cnt FROM (SELECT attributes FROM ${LogAggregationService.TABLE_NAME}`,
2191
+ );
2192
+
2193
+ LogAggregationService.appendErrorPatternScope(statement, request);
2194
+ LogAggregationService.appendErrorPatternEquality(
2195
+ statement,
2196
+ request.pattern,
2197
+ );
2198
+
2199
+ statement.append(
2200
+ ") ARRAY JOIN mapKeys(attributes) AS attrKey, mapValues(attributes) AS attrValue",
2201
+ );
2202
+ statement.append(
2203
+ SQL` GROUP BY attrKey, attrValue ORDER BY cnt DESC LIMIT ${{
2204
+ type: TableColumnType.Number,
2205
+ value: limit,
2206
+ }}`,
2207
+ );
2208
+
2209
+ statement.append(LogAggregationService.errorPatternQuerySettings());
2210
+
2211
+ return statement;
2212
+ }
2213
+
2214
+ private static buildErrorPatternResourcesStatement(
2215
+ request: ErrorPatternDetailRequest,
2216
+ ): Statement {
2217
+ const limit: number = LogAggregationService.clampErrorPatternLimit(
2218
+ request.limit,
2219
+ );
2220
+
2221
+ const statement: Statement = new Statement();
2222
+
2223
+ statement.append(
2224
+ `SELECT toString(primaryEntityId) AS resourceId, any(ifNull(primaryEntityType, '')) AS resourceType, count() AS cnt, max(time) AS lastSeen FROM ${LogAggregationService.TABLE_NAME}`,
2225
+ );
2226
+
2227
+ LogAggregationService.appendErrorPatternScope(statement, request);
2228
+ LogAggregationService.appendErrorPatternEquality(
2229
+ statement,
2230
+ request.pattern,
2231
+ );
2232
+
2233
+ statement.append(
2234
+ SQL` GROUP BY resourceId ORDER BY cnt DESC LIMIT ${{
2235
+ type: TableColumnType.Number,
2236
+ value: limit,
2237
+ }}`,
2238
+ );
2239
+
2240
+ statement.append(LogAggregationService.errorPatternQuerySettings());
2241
+
2242
+ return statement;
2243
+ }
2244
+
2245
+ private static buildErrorPatternTracesStatement(
2246
+ request: ErrorPatternDetailRequest,
2247
+ ): Statement {
2248
+ const limit: number = LogAggregationService.clampErrorPatternLimit(
2249
+ request.limit,
2250
+ );
2251
+
2252
+ const statement: Statement = new Statement();
2253
+
2254
+ statement.append(
2255
+ `SELECT ifNull(traceId, '') AS traceId, count() AS cnt, max(time) AS lastSeen, any(toString(primaryEntityId)) AS resourceId FROM ${LogAggregationService.TABLE_NAME}`,
2256
+ );
2257
+
2258
+ LogAggregationService.appendErrorPatternScope(statement, request);
2259
+ LogAggregationService.appendErrorPatternEquality(
2260
+ statement,
2261
+ request.pattern,
2262
+ );
2263
+
2264
+ statement.append(" AND ifNull(traceId, '') != ''");
2265
+
2266
+ statement.append(
2267
+ SQL` GROUP BY traceId ORDER BY cnt DESC LIMIT ${{
2268
+ type: TableColumnType.Number,
2269
+ value: limit,
2270
+ }}`,
2271
+ );
2272
+
2273
+ statement.append(LogAggregationService.errorPatternQuerySettings());
2274
+
2275
+ return statement;
2276
+ }
2277
+
2278
+ private static buildErrorPatternSamplesStatement(
2279
+ request: ErrorPatternDetailRequest,
2280
+ ): Statement {
2281
+ const limit: number = LogAggregationService.clampErrorPatternLimit(
2282
+ request.limit,
2283
+ );
2284
+
2285
+ const statement: Statement = new Statement();
2286
+
2287
+ statement.append(
2288
+ `SELECT _id, time, ifNull(body, '') AS body, toString(severityText) AS severityText, toString(primaryEntityId) AS resourceId, ifNull(traceId, '') AS traceId, ifNull(spanId, '') AS spanId FROM ${LogAggregationService.TABLE_NAME}`,
2289
+ );
2290
+
2291
+ LogAggregationService.appendErrorPatternScope(statement, request);
2292
+ LogAggregationService.appendErrorPatternEquality(
2293
+ statement,
2294
+ request.pattern,
2295
+ );
2296
+
2297
+ statement.append(
2298
+ SQL` ORDER BY time DESC LIMIT ${{
2299
+ type: TableColumnType.Number,
2300
+ value: limit,
2301
+ }}`,
2302
+ );
2303
+
2304
+ statement.append(LogAggregationService.errorPatternQuerySettings());
2305
+
2306
+ return statement;
2307
+ }
2308
+
2309
+ /*
2310
+ * Bucket size in seconds, clamped to a minute floor. A zero or negative
2311
+ * bucket would compile to `INTERVAL 0 SECOND`, which ClickHouse rejects —
2312
+ * and the correlation query's "same bucket" join would lose all meaning.
2313
+ */
2314
+ private static resolveBucketSeconds(
2315
+ request: ErrorPatternTimelineRequest,
2316
+ ): number {
2317
+ const minutes: number = request.bucketSizeInMinutes;
2318
+
2319
+ if (typeof minutes !== "number" || !Number.isFinite(minutes)) {
2320
+ return 60;
2321
+ }
2322
+
2323
+ return Math.max(1, Math.floor(minutes)) * 60;
2324
+ }
2325
+
1222
2326
  private static isTopLevelColumn(key: string): boolean {
1223
2327
  return LogAggregationService.TOP_LEVEL_COLUMNS.has(key);
1224
2328
  }