@oneuptime/common 10.8.0 → 10.8.2

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 (67) hide show
  1. package/Models/DatabaseModels/CloudResourceInstance.ts +1 -2
  2. package/Models/DatabaseModels/CloudResourceOwnerTeam.ts +1 -2
  3. package/Models/DatabaseModels/CloudResourceOwnerUser.ts +1 -2
  4. package/Models/DatabaseModels/TelemetryException.ts +3 -2
  5. package/Server/API/TelemetryAPI.ts +78 -25
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/1780931863719-AddTelemetryResourceMetadataColumns.ts +1 -3
  7. package/Server/Infrastructure/Postgres/SchemaMigrations/1780933132562-AddServerlessFunctionTables.ts +6 -2
  8. package/Server/Infrastructure/Postgres/SchemaMigrations/1780935387827-AddCloudResourceTables.ts +18 -6
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1781011482945-MigrationName.ts +2317 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  11. package/Server/Services/CloudResourceLabelRuleEngineService.ts +4 -1
  12. package/Server/Services/CloudResourceOwnerRuleEngineService.ts +4 -1
  13. package/Server/Services/LogAggregationService.ts +41 -16
  14. package/Server/Services/OpenTelemetryIngestService.ts +3 -1
  15. package/Server/Services/RumApplicationLabelRuleEngineService.ts +4 -1
  16. package/Server/Services/RumApplicationOwnerRuleEngineService.ts +4 -1
  17. package/Server/Services/ServerlessFunctionInstanceService.ts +4 -2
  18. package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +7 -2
  19. package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +7 -2
  20. package/Server/Services/TraceAggregationService.ts +128 -4
  21. package/Server/Utils/Telemetry/ResourceFacetResolver.ts +4 -3
  22. package/Types/Permission.ts +4 -2
  23. package/UI/Components/BulkUpdate/BulkLabelActions.tsx +14 -14
  24. package/UI/Components/Forms/Fields/FormField.tsx +18 -12
  25. package/UI/Components/Input/Input.tsx +3 -1
  26. package/UI/Components/TextArea/TextArea.tsx +3 -1
  27. package/UI/Components/Toast/Toast.tsx +4 -2
  28. package/build/dist/Models/DatabaseModels/CloudResourceInstance.js.map +1 -1
  29. package/build/dist/Models/DatabaseModels/CloudResourceOwnerTeam.js.map +1 -1
  30. package/build/dist/Models/DatabaseModels/CloudResourceOwnerUser.js.map +1 -1
  31. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  32. package/build/dist/Server/API/TelemetryAPI.js +61 -23
  33. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  34. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780931863719-AddTelemetryResourceMetadataColumns.js.map +1 -1
  35. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780933132562-AddServerlessFunctionTables.js.map +1 -1
  36. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780935387827-AddCloudResourceTables.js.map +1 -1
  37. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781011482945-MigrationName.js +798 -0
  38. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781011482945-MigrationName.js.map +1 -0
  39. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  40. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  41. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
  42. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
  43. package/build/dist/Server/Services/LogAggregationService.js +33 -10
  44. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  45. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  46. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
  47. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
  48. package/build/dist/Server/Services/ServerlessFunctionInstanceService.js +4 -2
  49. package/build/dist/Server/Services/ServerlessFunctionInstanceService.js.map +1 -1
  50. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +2 -1
  51. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
  52. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +2 -1
  53. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
  54. package/build/dist/Server/Services/TraceAggregationService.js +105 -4
  55. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  56. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
  57. package/build/dist/Types/Permission.js.map +1 -1
  58. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
  59. package/build/dist/UI/Components/Forms/Fields/FormField.js +15 -12
  60. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  61. package/build/dist/UI/Components/Input/Input.js +3 -1
  62. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  63. package/build/dist/UI/Components/TextArea/TextArea.js +3 -1
  64. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  65. package/build/dist/UI/Components/Toast/Toast.js +4 -2
  66. package/build/dist/UI/Components/Toast/Toast.js.map +1 -1
  67. package/package.json +1 -1
@@ -140,8 +140,7 @@ export default class CloudResourceInstance extends BaseModel {
140
140
  type: TableColumnType.ShortText,
141
141
  canReadOnRelationQuery: true,
142
142
  title: "Instance Name",
143
- description:
144
- "service.instance.id value identifying this instance / task.",
143
+ description: "service.instance.id value identifying this instance / task.",
145
144
  })
146
145
  @Column({
147
146
  nullable: false,
@@ -258,8 +258,7 @@ export default class CloudResourceOwnerTeam extends BaseModel {
258
258
  type: TableColumnType.Entity,
259
259
  modelType: CloudResource,
260
260
  title: "Cloud Resource",
261
- description:
262
- "Relation to Cloud Resource in which this object belongs",
261
+ description: "Relation to Cloud Resource in which this object belongs",
263
262
  })
264
263
  @ManyToOne(
265
264
  () => {
@@ -221,8 +221,7 @@ export default class CloudResourceOwnerUser extends BaseModel {
221
221
  type: TableColumnType.Entity,
222
222
  modelType: CloudResource,
223
223
  title: "Cloud Resource",
224
- description:
225
- "Relation to Cloud Resource in which this object belongs",
224
+ description: "Relation to Cloud Resource in which this object belongs",
226
225
  })
227
226
  @ManyToOne(
228
227
  () => {
@@ -86,8 +86,9 @@ import RumApplication from "./RumApplication";
86
86
  RumApplication,
87
87
  ],
88
88
  {
89
- includeProjectScope: true,
90
- })
89
+ includeProjectScope: true,
90
+ },
91
+ )
91
92
  @Entity({
92
93
  name: "TelemetryException",
93
94
  })
@@ -688,11 +688,10 @@ router.post(
688
688
  : undefined;
689
689
 
690
690
  /*
691
- * Compute all facets from a single sort-key-aligned sample query
692
- * (ORDER BY startTime DESC LIMIT N) and count top-K in Node. This
693
- * avoids ClickHouse GROUP BY aggregations that can't return partial
694
- * results under max_execution_time 'break' mode, and returns in
695
- * <1s even over 14-day windows.
691
+ * Shared window + active filters for both facet-counting paths below:
692
+ * the exact projection-backed GROUP BY (resource facets + statusCode)
693
+ * and the recent-N sample (kind + attribute facets, which have no cheap
694
+ * exact path).
696
695
  */
697
696
  const multiRequest: TraceMultiFacetRequest = {
698
697
  projectId: databaseProps.tenantId,
@@ -710,38 +709,92 @@ router.post(
710
709
  attributes,
711
710
  };
712
711
 
713
- let facets: Record<string, Array<TraceFacetValue>>;
714
- try {
715
- facets =
716
- await TraceAggregationService.getFacetValuesFromSample(multiRequest);
717
- } catch {
718
- facets = Object.fromEntries(
719
- facetKeys.map((key: string): [string, Array<TraceFacetValue>] => {
720
- return [key, []];
721
- }),
722
- );
712
+ /*
713
+ * Resource facets (serviceId / hostId / dockerHostId / k8s cluster ...)
714
+ * and statusCode are counted with an exact, projection-backed GROUP BY
715
+ * in getResourceFacetCounts(). The recent-N sample below saturates with
716
+ * whichever service is chattiest right now and reports 0 for every other
717
+ * service regardless of its true volume over the window — the "top 1000"
718
+ * symptom. Facets with no projection (kind, attribute keys) have no cheap
719
+ * exact path and stay on the sample.
720
+ */
721
+ const sampledKeys: Array<string> = facetKeys.filter(
722
+ (key: string): boolean => {
723
+ return (
724
+ !ResourceFacetResolver.isResourceFacet(key) && key !== "statusCode"
725
+ );
726
+ },
727
+ );
728
+
729
+ let facets: Record<string, Array<TraceFacetValue>> = {};
730
+ if (sampledKeys.length > 0) {
731
+ try {
732
+ facets = await TraceAggregationService.getFacetValuesFromSample({
733
+ ...multiRequest,
734
+ facetKeys: sampledKeys,
735
+ });
736
+ } catch {
737
+ facets = Object.fromEntries(
738
+ sampledKeys.map((key: string): [string, Array<TraceFacetValue>] => {
739
+ return [key, []];
740
+ }),
741
+ );
742
+ }
743
+ }
744
+
745
+ const needsAccurateCounts: boolean =
746
+ facetKeys.includes("statusCode") ||
747
+ facetKeys.some((key: string): boolean => {
748
+ return ResourceFacetResolver.isResourceFacet(key);
749
+ });
750
+
751
+ let serviceCounts: Map<string, number> = new Map<string, number>();
752
+ let statusCounts: Map<string, number> = new Map<string, number>();
753
+ if (needsAccurateCounts) {
754
+ try {
755
+ const accurate: {
756
+ serviceCounts: Map<string, number>;
757
+ statusCounts: Map<string, number>;
758
+ } =
759
+ await TraceAggregationService.getResourceFacetCounts(multiRequest);
760
+ serviceCounts = accurate.serviceCounts;
761
+ statusCounts = accurate.statusCounts;
762
+ } catch {
763
+ /*
764
+ * Degrade gracefully: resource facets still enumerate via Postgres
765
+ * (count 0), statusCode falls back to empty.
766
+ */
767
+ }
768
+ }
769
+
770
+ if (facetKeys.includes("statusCode")) {
771
+ facets["statusCode"] = Array.from(statusCounts.entries())
772
+ .map(([value, count]: [string, number]): TraceFacetValue => {
773
+ return { value, count };
774
+ })
775
+ .sort((a: TraceFacetValue, b: TraceFacetValue): number => {
776
+ return b.count - a.count;
777
+ })
778
+ .slice(0, limit);
723
779
  }
724
780
 
725
781
  /*
726
782
  * Replace resource-facet results with the Postgres source-of-truth list
727
- * (filtered by facetSearchText and enriched with displayName). Counts
728
- * come from the ClickHouse sample above entities with no recent
729
- * telemetry surface with count 0 instead of being hidden entirely. This
730
- * means low-volume services / hosts still appear in the sidebar and the
731
- * search box can find resources beyond the loaded subset.
783
+ * (filtered by facetSearchText and enriched with displayName). Every
784
+ * resource facet shares the same exact serviceId -> count map; resource
785
+ * ids are globally unique, so each facet only ever resolves its own
786
+ * entities. Entities with no telemetry in the window surface with count
787
+ * 0 instead of being hidden, and the search box can find resources
788
+ * beyond the loaded subset.
732
789
  */
733
790
  const resourceSpecs: Array<ResourceFacetSpec> = facetKeys
734
791
  .filter((key: string): boolean => {
735
792
  return ResourceFacetResolver.isResourceFacet(key);
736
793
  })
737
794
  .map((key: string): ResourceFacetSpec => {
738
- const counts: Map<string, number> = new Map();
739
- for (const fv of facets[key] || []) {
740
- counts.set(fv.value, fv.count);
741
- }
742
795
  return {
743
796
  facetKey: key,
744
- counts,
797
+ counts: serviceCounts,
745
798
  searchText: facetSearchText?.[key],
746
799
  limit,
747
800
  };
@@ -68,9 +68,7 @@ export class AddTelemetryResourceMetadataColumns1780931863719
68
68
 
69
69
  public async down(queryRunner: QueryRunner): Promise<void> {
70
70
  // Host
71
- await queryRunner.query(
72
- `ALTER TABLE "Host" DROP COLUMN "cloudAccountId"`,
73
- );
71
+ await queryRunner.query(`ALTER TABLE "Host" DROP COLUMN "cloudAccountId"`);
74
72
  await queryRunner.query(`ALTER TABLE "Host" DROP COLUMN "cloudRegion"`);
75
73
  await queryRunner.query(`ALTER TABLE "Host" DROP COLUMN "cloudPlatform"`);
76
74
  await queryRunner.query(`ALTER TABLE "Host" DROP COLUMN "cloudProvider"`);
@@ -175,7 +175,9 @@ export class AddServerlessFunctionTables1780933132562
175
175
  await queryRunner.query(
176
176
  `DROP INDEX "public"."IDX_SrvlessFnOwnerUser_notified"`,
177
177
  );
178
- await queryRunner.query(`DROP INDEX "public"."IDX_SrvlessFnOwnerUser_fnId"`);
178
+ await queryRunner.query(
179
+ `DROP INDEX "public"."IDX_SrvlessFnOwnerUser_fnId"`,
180
+ );
179
181
  await queryRunner.query(
180
182
  `DROP INDEX "public"."IDX_SrvlessFnOwnerUser_userId"`,
181
183
  );
@@ -186,7 +188,9 @@ export class AddServerlessFunctionTables1780933132562
186
188
  await queryRunner.query(
187
189
  `DROP INDEX "public"."IDX_SrvlessFnOwnerTeam_notified"`,
188
190
  );
189
- await queryRunner.query(`DROP INDEX "public"."IDX_SrvlessFnOwnerTeam_fnId"`);
191
+ await queryRunner.query(
192
+ `DROP INDEX "public"."IDX_SrvlessFnOwnerTeam_fnId"`,
193
+ );
190
194
  await queryRunner.query(
191
195
  `DROP INDEX "public"."IDX_SrvlessFnOwnerTeam_teamId"`,
192
196
  );
@@ -166,13 +166,19 @@ export class AddCloudResourceTables1780935387827 implements MigrationInterface {
166
166
  await queryRunner.query(
167
167
  `DROP INDEX "public"."IDX_CloudResourceLabel_labelId"`,
168
168
  );
169
- await queryRunner.query(`DROP INDEX "public"."IDX_CloudResourceLabel_resId"`);
169
+ await queryRunner.query(
170
+ `DROP INDEX "public"."IDX_CloudResourceLabel_resId"`,
171
+ );
170
172
  await queryRunner.query(`DROP TABLE "CloudResourceLabel"`);
171
173
  await queryRunner.query(
172
174
  `DROP INDEX "public"."IDX_CloudResOwnerUser_notified"`,
173
175
  );
174
- await queryRunner.query(`DROP INDEX "public"."IDX_CloudResOwnerUser_resId"`);
175
- await queryRunner.query(`DROP INDEX "public"."IDX_CloudResOwnerUser_userId"`);
176
+ await queryRunner.query(
177
+ `DROP INDEX "public"."IDX_CloudResOwnerUser_resId"`,
178
+ );
179
+ await queryRunner.query(
180
+ `DROP INDEX "public"."IDX_CloudResOwnerUser_userId"`,
181
+ );
176
182
  await queryRunner.query(
177
183
  `DROP INDEX "public"."IDX_CloudResOwnerUser_projectId"`,
178
184
  );
@@ -180,8 +186,12 @@ export class AddCloudResourceTables1780935387827 implements MigrationInterface {
180
186
  await queryRunner.query(
181
187
  `DROP INDEX "public"."IDX_CloudResOwnerTeam_notified"`,
182
188
  );
183
- await queryRunner.query(`DROP INDEX "public"."IDX_CloudResOwnerTeam_resId"`);
184
- await queryRunner.query(`DROP INDEX "public"."IDX_CloudResOwnerTeam_teamId"`);
189
+ await queryRunner.query(
190
+ `DROP INDEX "public"."IDX_CloudResOwnerTeam_resId"`,
191
+ );
192
+ await queryRunner.query(
193
+ `DROP INDEX "public"."IDX_CloudResOwnerTeam_teamId"`,
194
+ );
185
195
  await queryRunner.query(
186
196
  `DROP INDEX "public"."IDX_CloudResOwnerTeam_projectId"`,
187
197
  );
@@ -189,7 +199,9 @@ export class AddCloudResourceTables1780935387827 implements MigrationInterface {
189
199
  await queryRunner.query(
190
200
  `DROP INDEX "public"."UQ_CloudResource_project_resId"`,
191
201
  );
192
- await queryRunner.query(`DROP INDEX "public"."IDX_CloudResource_projectId"`);
202
+ await queryRunner.query(
203
+ `DROP INDEX "public"."IDX_CloudResource_projectId"`,
204
+ );
193
205
  await queryRunner.query(`DROP TABLE "CloudResource"`);
194
206
  }
195
207
  }