@oneuptime/common 10.5.31 → 10.5.33

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 (82) hide show
  1. package/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.ts +45 -0
  2. package/Models/AnalyticsModels/AuditLog.ts +3 -0
  3. package/Models/AnalyticsModels/ExceptionInstance.ts +3 -0
  4. package/Models/AnalyticsModels/Index.ts +2 -0
  5. package/Models/AnalyticsModels/Log.ts +3 -0
  6. package/Models/AnalyticsModels/Metric.ts +3 -0
  7. package/Models/AnalyticsModels/Span.ts +3 -0
  8. package/Models/DatabaseModels/Index.ts +4 -0
  9. package/Models/DatabaseModels/KubernetesResource.ts +37 -0
  10. package/Models/DatabaseModels/MetricSavedView.ts +334 -0
  11. package/Models/DatabaseModels/TraceSavedView.ts +334 -0
  12. package/Server/API/KubernetesResourceAPI.ts +18 -9
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1780645560183-AddMetricAndTraceSavedView.ts +81 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1780651429467-AddKubernetesLatestMemoryPercent.ts +19 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  16. package/Server/Services/KubernetesResourceService.ts +37 -11
  17. package/Server/Services/MetricSavedViewService.ts +109 -0
  18. package/Server/Services/TraceSavedViewService.ts +109 -0
  19. package/Server/Utils/Monitor/MonitorAlert.ts +34 -0
  20. package/Server/Utils/Monitor/MonitorIncident.ts +60 -93
  21. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +229 -0
  22. package/Server/Utils/Monitor/MonitorResource.ts +18 -0
  23. package/Server/Utils/Monitor/SeriesResourceLabels.ts +156 -0
  24. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +211 -0
  25. package/Types/Telemetry/TelemetrySavedViewState.ts +26 -0
  26. package/UI/Components/Table/TableHeader.tsx +6 -2
  27. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +175 -0
  28. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js +32 -0
  29. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js.map +1 -1
  30. package/build/dist/Models/AnalyticsModels/AuditLog.js +2 -0
  31. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  32. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +2 -0
  33. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
  34. package/build/dist/Models/AnalyticsModels/Index.js +2 -0
  35. package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
  36. package/build/dist/Models/AnalyticsModels/Log.js +2 -0
  37. package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
  38. package/build/dist/Models/AnalyticsModels/Metric.js +2 -0
  39. package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
  40. package/build/dist/Models/AnalyticsModels/Span.js +2 -0
  41. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  42. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  43. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  44. package/build/dist/Models/DatabaseModels/KubernetesResource.js +38 -0
  45. package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -1
  46. package/build/dist/Models/DatabaseModels/MetricSavedView.js +356 -0
  47. package/build/dist/Models/DatabaseModels/MetricSavedView.js.map +1 -0
  48. package/build/dist/Models/DatabaseModels/TraceSavedView.js +356 -0
  49. package/build/dist/Models/DatabaseModels/TraceSavedView.js.map +1 -0
  50. package/build/dist/Server/API/KubernetesResourceAPI.js +6 -4
  51. package/build/dist/Server/API/KubernetesResourceAPI.js.map +1 -1
  52. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780645560183-AddMetricAndTraceSavedView.js +34 -0
  53. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780645560183-AddMetricAndTraceSavedView.js.map +1 -0
  54. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780651429467-AddKubernetesLatestMemoryPercent.js +12 -0
  55. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780651429467-AddKubernetesLatestMemoryPercent.js.map +1 -0
  56. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  57. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  58. package/build/dist/Server/Services/KubernetesResourceService.js +13 -5
  59. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  60. package/build/dist/Server/Services/MetricSavedViewService.js +82 -0
  61. package/build/dist/Server/Services/MetricSavedViewService.js.map +1 -0
  62. package/build/dist/Server/Services/TraceSavedViewService.js +82 -0
  63. package/build/dist/Server/Services/TraceSavedViewService.js.map +1 -0
  64. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +36 -17
  65. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  66. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +60 -107
  67. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  68. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +165 -0
  69. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -0
  70. package/build/dist/Server/Utils/Monitor/MonitorResource.js +16 -0
  71. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  72. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +106 -0
  73. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -0
  74. package/build/dist/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.js +142 -0
  75. package/build/dist/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.js.map +1 -0
  76. package/build/dist/Types/Telemetry/TelemetrySavedViewState.js +9 -0
  77. package/build/dist/Types/Telemetry/TelemetrySavedViewState.js.map +1 -0
  78. package/build/dist/UI/Components/Table/TableHeader.js +2 -2
  79. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  80. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +58 -0
  81. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -0
  82. package/package.json +1 -1
@@ -0,0 +1,334 @@
1
+ import Project from "./Project";
2
+ import User from "./User";
3
+ import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
4
+ import Route from "../../Types/API/Route";
5
+ import TelemetrySavedViewState from "../../Types/Telemetry/TelemetrySavedViewState";
6
+ import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
7
+ import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
8
+ import TableBillingAccessControl from "../../Types/Database/AccessControl/TableBillingAccessControl";
9
+ import ColumnLength from "../../Types/Database/ColumnLength";
10
+ import ColumnType from "../../Types/Database/ColumnType";
11
+ import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
12
+ import EnableDocumentation from "../../Types/Database/EnableDocumentation";
13
+ import TableColumn from "../../Types/Database/TableColumn";
14
+ import TableColumnType from "../../Types/Database/TableColumnType";
15
+ import TableMetadata from "../../Types/Database/TableMetadata";
16
+ import TenantColumn from "../../Types/Database/TenantColumn";
17
+ import IconProp from "../../Types/Icon/IconProp";
18
+ import ObjectID from "../../Types/ObjectID";
19
+ import Permission from "../../Types/Permission";
20
+ import { PlanType } from "../../Types/Billing/SubscriptionPlan";
21
+ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
22
+
23
+ @EnableDocumentation()
24
+ @TableBillingAccessControl({
25
+ create: PlanType.Free,
26
+ read: PlanType.Free,
27
+ update: PlanType.Free,
28
+ delete: PlanType.Free,
29
+ })
30
+ @TenantColumn("projectId")
31
+ @CrudApiEndpoint(new Route("/trace-saved-view"))
32
+ @Entity({
33
+ name: "TraceSavedView",
34
+ })
35
+ @TableMetadata({
36
+ tableName: "TraceSavedView",
37
+ singularName: "Trace Saved View",
38
+ pluralName: "Trace Saved Views",
39
+ icon: IconProp.Window,
40
+ tableDescription:
41
+ "Save and reuse traces explorer views, including the current search, filters, time range, and page size.",
42
+ })
43
+ @TableAccessControl({
44
+ create: [
45
+ Permission.ProjectOwner,
46
+ Permission.ProjectAdmin,
47
+ Permission.ProjectMember,
48
+ ],
49
+ read: [
50
+ Permission.ProjectOwner,
51
+ Permission.ProjectAdmin,
52
+ Permission.ProjectMember,
53
+ Permission.Viewer,
54
+ ],
55
+ delete: [
56
+ Permission.ProjectOwner,
57
+ Permission.ProjectAdmin,
58
+ Permission.ProjectMember,
59
+ ],
60
+ update: [
61
+ Permission.ProjectOwner,
62
+ Permission.ProjectAdmin,
63
+ Permission.ProjectMember,
64
+ ],
65
+ })
66
+ export default class TraceSavedView extends BaseModel {
67
+ @ColumnAccessControl({
68
+ create: [
69
+ Permission.ProjectOwner,
70
+ Permission.ProjectAdmin,
71
+ Permission.ProjectMember,
72
+ ],
73
+ read: [
74
+ Permission.ProjectOwner,
75
+ Permission.ProjectAdmin,
76
+ Permission.ProjectMember,
77
+ Permission.Viewer,
78
+ ],
79
+ update: [],
80
+ })
81
+ @TableColumn({
82
+ manyToOneRelationColumn: "projectId",
83
+ type: TableColumnType.Entity,
84
+ modelType: Project,
85
+ title: "Project",
86
+ description: "Relation to the project this saved trace view belongs to.",
87
+ })
88
+ @ManyToOne(
89
+ () => {
90
+ return Project;
91
+ },
92
+ {
93
+ eager: false,
94
+ nullable: true,
95
+ onDelete: "CASCADE",
96
+ orphanedRowAction: "nullify",
97
+ },
98
+ )
99
+ @JoinColumn({ name: "projectId" })
100
+ public project?: Project = undefined;
101
+
102
+ @ColumnAccessControl({
103
+ create: [
104
+ Permission.ProjectOwner,
105
+ Permission.ProjectAdmin,
106
+ Permission.ProjectMember,
107
+ ],
108
+ read: [
109
+ Permission.ProjectOwner,
110
+ Permission.ProjectAdmin,
111
+ Permission.ProjectMember,
112
+ Permission.Viewer,
113
+ ],
114
+ update: [],
115
+ })
116
+ @Index()
117
+ @TableColumn({
118
+ type: TableColumnType.ObjectID,
119
+ required: true,
120
+ canReadOnRelationQuery: true,
121
+ title: "Project ID",
122
+ description: "ID of the project this saved trace view belongs to.",
123
+ })
124
+ @Column({
125
+ type: ColumnType.ObjectID,
126
+ nullable: false,
127
+ transformer: ObjectID.getDatabaseTransformer(),
128
+ })
129
+ public projectId?: ObjectID = undefined;
130
+
131
+ @ColumnAccessControl({
132
+ create: [
133
+ Permission.ProjectOwner,
134
+ Permission.ProjectAdmin,
135
+ Permission.ProjectMember,
136
+ ],
137
+ read: [
138
+ Permission.ProjectOwner,
139
+ Permission.ProjectAdmin,
140
+ Permission.ProjectMember,
141
+ Permission.Viewer,
142
+ ],
143
+ update: [
144
+ Permission.ProjectOwner,
145
+ Permission.ProjectAdmin,
146
+ Permission.ProjectMember,
147
+ ],
148
+ })
149
+ @TableColumn({
150
+ required: true,
151
+ type: TableColumnType.Name,
152
+ canReadOnRelationQuery: true,
153
+ title: "Name",
154
+ description: "Friendly name for this saved trace view.",
155
+ })
156
+ @Column({
157
+ nullable: false,
158
+ type: ColumnType.Name,
159
+ length: ColumnLength.Name,
160
+ })
161
+ public name?: string = undefined;
162
+
163
+ @ColumnAccessControl({
164
+ create: [],
165
+ read: [
166
+ Permission.ProjectOwner,
167
+ Permission.ProjectAdmin,
168
+ Permission.ProjectMember,
169
+ Permission.Viewer,
170
+ ],
171
+ update: [],
172
+ })
173
+ @TableColumn({
174
+ manyToOneRelationColumn: "createdByUserId",
175
+ type: TableColumnType.Entity,
176
+ modelType: User,
177
+ title: "Created By User",
178
+ description: "Relation to the user who created this saved trace view.",
179
+ })
180
+ @ManyToOne(
181
+ () => {
182
+ return User;
183
+ },
184
+ {
185
+ eager: false,
186
+ nullable: true,
187
+ onDelete: "SET NULL",
188
+ orphanedRowAction: "nullify",
189
+ },
190
+ )
191
+ @JoinColumn({ name: "createdByUserId" })
192
+ public createdByUser?: User = undefined;
193
+
194
+ @ColumnAccessControl({
195
+ create: [],
196
+ read: [
197
+ Permission.ProjectOwner,
198
+ Permission.ProjectAdmin,
199
+ Permission.ProjectMember,
200
+ Permission.Viewer,
201
+ ],
202
+ update: [],
203
+ })
204
+ @TableColumn({
205
+ type: TableColumnType.ObjectID,
206
+ title: "Created By User ID",
207
+ description: "ID of the user who created this saved trace view.",
208
+ })
209
+ @Column({
210
+ type: ColumnType.ObjectID,
211
+ nullable: true,
212
+ transformer: ObjectID.getDatabaseTransformer(),
213
+ })
214
+ public createdByUserId?: ObjectID = undefined;
215
+
216
+ @ColumnAccessControl({
217
+ create: [],
218
+ read: [
219
+ Permission.ProjectOwner,
220
+ Permission.ProjectAdmin,
221
+ Permission.ProjectMember,
222
+ Permission.Viewer,
223
+ ],
224
+ update: [],
225
+ })
226
+ @TableColumn({
227
+ manyToOneRelationColumn: "deletedByUserId",
228
+ type: TableColumnType.Entity,
229
+ modelType: User,
230
+ title: "Deleted By User",
231
+ description: "Relation to the user who deleted this saved trace view.",
232
+ })
233
+ @ManyToOne(
234
+ () => {
235
+ return User;
236
+ },
237
+ {
238
+ eager: false,
239
+ nullable: true,
240
+ onDelete: "SET NULL",
241
+ orphanedRowAction: "nullify",
242
+ },
243
+ )
244
+ @JoinColumn({ name: "deletedByUserId" })
245
+ public deletedByUser?: User = undefined;
246
+
247
+ @ColumnAccessControl({
248
+ create: [],
249
+ read: [
250
+ Permission.ProjectOwner,
251
+ Permission.ProjectAdmin,
252
+ Permission.ProjectMember,
253
+ Permission.Viewer,
254
+ ],
255
+ update: [],
256
+ })
257
+ @TableColumn({
258
+ type: TableColumnType.ObjectID,
259
+ title: "Deleted By User ID",
260
+ description: "ID of the user who deleted this saved trace view.",
261
+ })
262
+ @Column({
263
+ type: ColumnType.ObjectID,
264
+ nullable: true,
265
+ transformer: ObjectID.getDatabaseTransformer(),
266
+ })
267
+ public deletedByUserId?: ObjectID = undefined;
268
+
269
+ @ColumnAccessControl({
270
+ create: [
271
+ Permission.ProjectOwner,
272
+ Permission.ProjectAdmin,
273
+ Permission.ProjectMember,
274
+ ],
275
+ read: [
276
+ Permission.ProjectOwner,
277
+ Permission.ProjectAdmin,
278
+ Permission.ProjectMember,
279
+ Permission.Viewer,
280
+ ],
281
+ update: [
282
+ Permission.ProjectOwner,
283
+ Permission.ProjectAdmin,
284
+ Permission.ProjectMember,
285
+ ],
286
+ })
287
+ @TableColumn({
288
+ title: "Query",
289
+ required: true,
290
+ type: TableColumnType.JSON,
291
+ canReadOnRelationQuery: true,
292
+ description:
293
+ "Serialized traces explorer view state (search, filters, time range, page size) for this saved view.",
294
+ })
295
+ @Column({
296
+ type: ColumnType.JSON,
297
+ nullable: false,
298
+ })
299
+ public query?: TelemetrySavedViewState = undefined;
300
+
301
+ @ColumnAccessControl({
302
+ create: [
303
+ Permission.ProjectOwner,
304
+ Permission.ProjectAdmin,
305
+ Permission.ProjectMember,
306
+ ],
307
+ read: [
308
+ Permission.ProjectOwner,
309
+ Permission.ProjectAdmin,
310
+ Permission.ProjectMember,
311
+ Permission.Viewer,
312
+ ],
313
+ update: [
314
+ Permission.ProjectOwner,
315
+ Permission.ProjectAdmin,
316
+ Permission.ProjectMember,
317
+ ],
318
+ })
319
+ @Index()
320
+ @TableColumn({
321
+ required: true,
322
+ type: TableColumnType.Boolean,
323
+ canReadOnRelationQuery: true,
324
+ title: "Is Default",
325
+ description: "Whether this saved trace view should be applied by default.",
326
+ defaultValue: false,
327
+ })
328
+ @Column({
329
+ nullable: false,
330
+ type: ColumnType.Boolean,
331
+ default: false,
332
+ })
333
+ public isDefault?: boolean = undefined;
334
+ }
@@ -143,19 +143,24 @@ export default class KubernetesResourceAPI extends BaseAPI<
143
143
 
144
144
  /*
145
145
  * Translate a service-layer Map of aggregates into a JSON dict
146
- * { name: { cpuPercent, memoryBytes } } suitable for the wire.
147
- * memoryBytes is stringified so values past 2 GiB don't overflow
148
- * client-side number parsing in the JSON path; the UI parses it
149
- * back to a number for rendering.
146
+ * { name: { cpuPercent, memoryBytes, memoryPercent } } suitable for
147
+ * the wire. memoryBytes is stringified so values past 2 GiB don't
148
+ * overflow client-side number parsing in the JSON path; the UI parses
149
+ * it back to a number for rendering. memoryPercent is the summed
150
+ * per-pod "% of node allocatable memory" (parallel to cpuPercent).
150
151
  */
151
152
  private mapAggregatesToJson(
152
- aggregates: Map<string, { cpuPercent: number; memoryBytes: number }>,
153
+ aggregates: Map<
154
+ string,
155
+ { cpuPercent: number; memoryBytes: number; memoryPercent: number }
156
+ >,
153
157
  ): JSONObject {
154
158
  const out: JSONObject = {};
155
159
  for (const [name, value] of aggregates.entries()) {
156
160
  out[name] = {
157
161
  cpuPercent: value.cpuPercent,
158
162
  memoryBytes: value.memoryBytes.toString(),
163
+ memoryPercent: value.memoryPercent,
159
164
  };
160
165
  }
161
166
  return out;
@@ -169,8 +174,10 @@ export default class KubernetesResourceAPI extends BaseAPI<
169
174
  await this.resolveClusterForRequest(req);
170
175
 
171
176
  const staleAfter: Date = new Date(Date.now() - 15 * 60 * 1000);
172
- const aggregates: Map<string, { cpuPercent: number; memoryBytes: number }> =
173
- await this.service.getLatestMetricsByNamespace({
177
+ const aggregates: Map<
178
+ string,
179
+ { cpuPercent: number; memoryBytes: number; memoryPercent: number }
180
+ > = await this.service.getLatestMetricsByNamespace({
174
181
  projectId,
175
182
  kubernetesClusterId,
176
183
  staleAfter,
@@ -210,8 +217,10 @@ export default class KubernetesResourceAPI extends BaseAPI<
210
217
  await this.resolveClusterForRequest(req);
211
218
 
212
219
  const staleAfter: Date = new Date(Date.now() - 15 * 60 * 1000);
213
- const aggregates: Map<string, { cpuPercent: number; memoryBytes: number }> =
214
- await this.service.getLatestMetricsByOwner({
220
+ const aggregates: Map<
221
+ string,
222
+ { cpuPercent: number; memoryBytes: number; memoryPercent: number }
223
+ > = await this.service.getLatestMetricsByOwner({
215
224
  projectId,
216
225
  kubernetesClusterId,
217
226
  ownerKind,
@@ -0,0 +1,81 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class AddMetricAndTraceSavedView1780645560183
4
+ implements MigrationInterface
5
+ {
6
+ public name = "AddMetricAndTraceSavedView1780645560183";
7
+
8
+ public async up(queryRunner: QueryRunner): Promise<void> {
9
+ await queryRunner.query(
10
+ `CREATE TABLE "MetricSavedView" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "name" character varying(50) NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "query" jsonb NOT NULL, "isDefault" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_c039adf718ddfc387e2f9182cd6" PRIMARY KEY ("_id"))`,
11
+ );
12
+ await queryRunner.query(
13
+ `CREATE INDEX "IDX_1ca87e6c282970f623562035f2" ON "MetricSavedView" ("projectId") `,
14
+ );
15
+ await queryRunner.query(
16
+ `CREATE INDEX "IDX_c68db47974161dff86906b987d" ON "MetricSavedView" ("isDefault") `,
17
+ );
18
+ await queryRunner.query(
19
+ `CREATE TABLE "TraceSavedView" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "name" character varying(50) NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "query" jsonb NOT NULL, "isDefault" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_087d7140b86556085f9aebe8ee5" PRIMARY KEY ("_id"))`,
20
+ );
21
+ await queryRunner.query(
22
+ `CREATE INDEX "IDX_a5ab6a338198ce0171d7e9e767" ON "TraceSavedView" ("projectId") `,
23
+ );
24
+ await queryRunner.query(
25
+ `CREATE INDEX "IDX_24f5967407b37b1601e8aa95cd" ON "TraceSavedView" ("isDefault") `,
26
+ );
27
+ await queryRunner.query(
28
+ `ALTER TABLE "MetricSavedView" ADD CONSTRAINT "FK_1ca87e6c282970f623562035f2b" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
29
+ );
30
+ await queryRunner.query(
31
+ `ALTER TABLE "MetricSavedView" ADD CONSTRAINT "FK_5d6c800c0070ca19e75e664b46b" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
32
+ );
33
+ await queryRunner.query(
34
+ `ALTER TABLE "MetricSavedView" ADD CONSTRAINT "FK_84e306d0d03a2a4721fe767464d" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
35
+ );
36
+ await queryRunner.query(
37
+ `ALTER TABLE "TraceSavedView" ADD CONSTRAINT "FK_a5ab6a338198ce0171d7e9e767b" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
38
+ );
39
+ await queryRunner.query(
40
+ `ALTER TABLE "TraceSavedView" ADD CONSTRAINT "FK_e22965c32f7cb0e154d2fa76d24" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
41
+ );
42
+ await queryRunner.query(
43
+ `ALTER TABLE "TraceSavedView" ADD CONSTRAINT "FK_e98727a618620d359fc766c95fc" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
44
+ );
45
+ }
46
+
47
+ public async down(queryRunner: QueryRunner): Promise<void> {
48
+ await queryRunner.query(
49
+ `ALTER TABLE "TraceSavedView" DROP CONSTRAINT "FK_e98727a618620d359fc766c95fc"`,
50
+ );
51
+ await queryRunner.query(
52
+ `ALTER TABLE "TraceSavedView" DROP CONSTRAINT "FK_e22965c32f7cb0e154d2fa76d24"`,
53
+ );
54
+ await queryRunner.query(
55
+ `ALTER TABLE "TraceSavedView" DROP CONSTRAINT "FK_a5ab6a338198ce0171d7e9e767b"`,
56
+ );
57
+ await queryRunner.query(
58
+ `ALTER TABLE "MetricSavedView" DROP CONSTRAINT "FK_84e306d0d03a2a4721fe767464d"`,
59
+ );
60
+ await queryRunner.query(
61
+ `ALTER TABLE "MetricSavedView" DROP CONSTRAINT "FK_5d6c800c0070ca19e75e664b46b"`,
62
+ );
63
+ await queryRunner.query(
64
+ `ALTER TABLE "MetricSavedView" DROP CONSTRAINT "FK_1ca87e6c282970f623562035f2b"`,
65
+ );
66
+ await queryRunner.query(
67
+ `DROP INDEX "public"."IDX_24f5967407b37b1601e8aa95cd"`,
68
+ );
69
+ await queryRunner.query(
70
+ `DROP INDEX "public"."IDX_a5ab6a338198ce0171d7e9e767"`,
71
+ );
72
+ await queryRunner.query(`DROP TABLE "TraceSavedView"`);
73
+ await queryRunner.query(
74
+ `DROP INDEX "public"."IDX_c68db47974161dff86906b987d"`,
75
+ );
76
+ await queryRunner.query(
77
+ `DROP INDEX "public"."IDX_1ca87e6c282970f623562035f2"`,
78
+ );
79
+ await queryRunner.query(`DROP TABLE "MetricSavedView"`);
80
+ }
81
+ }
@@ -0,0 +1,19 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class AddKubernetesLatestMemoryPercent1780651429467
4
+ implements MigrationInterface
5
+ {
6
+ public name = "AddKubernetesLatestMemoryPercent1780651429467";
7
+
8
+ public async up(queryRunner: QueryRunner): Promise<void> {
9
+ await queryRunner.query(
10
+ `ALTER TABLE "KubernetesResource" ADD "latestMemoryPercent" numeric`,
11
+ );
12
+ }
13
+
14
+ public async down(queryRunner: QueryRunner): Promise<void> {
15
+ await queryRunner.query(
16
+ `ALTER TABLE "KubernetesResource" DROP COLUMN "latestMemoryPercent"`,
17
+ );
18
+ }
19
+ }
@@ -365,6 +365,8 @@ import { MigrationName1780381124553 } from "./1780381124553-MigrationName";
365
365
  import { MigrationName1780382837019 } from "./1780382837019-MigrationName";
366
366
  import { MigrationName1780387560604 } from "./1780387560604-MigrationName";
367
367
  import { MigrationName1780388219225 } from "./1780388219225-MigrationName";
368
+ import { AddMetricAndTraceSavedView1780645560183 } from "./1780645560183-AddMetricAndTraceSavedView";
369
+ import { AddKubernetesLatestMemoryPercent1780651429467 } from "./1780651429467-AddKubernetesLatestMemoryPercent";
368
370
 
369
371
  export default [
370
372
  InitialMigration,
@@ -734,4 +736,6 @@ export default [
734
736
  MigrationName1780382837019,
735
737
  MigrationName1780387560604,
736
738
  MigrationName1780388219225,
739
+ AddMetricAndTraceSavedView1780645560183,
740
+ AddKubernetesLatestMemoryPercent1780651429467,
737
741
  ];
@@ -46,6 +46,7 @@ export interface ResourceLatestMetric {
46
46
  name: string;
47
47
  cpuPercent: number | null;
48
48
  memoryBytes: number | null;
49
+ memoryPercent: number | null;
49
50
  observedAt: Date;
50
51
  /*
51
52
  * Optional Pod controller lineage. Read from
@@ -447,7 +448,7 @@ export class Service extends DatabaseService<Model> {
447
448
 
448
449
  for (const m of chunk) {
449
450
  valueFragments.push(
450
- `($${paramIndex++}, $${paramIndex++}, $${paramIndex++}, $${paramIndex++}::numeric, $${paramIndex++}::bigint, $${paramIndex++}::timestamptz, $${paramIndex++}, $${paramIndex++})`,
451
+ `($${paramIndex++}, $${paramIndex++}, $${paramIndex++}, $${paramIndex++}::numeric, $${paramIndex++}::bigint, $${paramIndex++}::numeric, $${paramIndex++}::timestamptz, $${paramIndex++}, $${paramIndex++})`,
451
452
  );
452
453
  params.push(
453
454
  m.kind,
@@ -459,6 +460,9 @@ export class Service extends DatabaseService<Model> {
459
460
  m.memoryBytes !== null && m.memoryBytes !== undefined
460
461
  ? Math.trunc(m.memoryBytes).toString()
461
462
  : null,
463
+ m.memoryPercent !== null && m.memoryPercent !== undefined
464
+ ? m.memoryPercent
465
+ : null,
462
466
  m.observedAt,
463
467
  m.controllerDeploymentName ?? null,
464
468
  m.controllerCronJobName ?? null,
@@ -470,12 +474,13 @@ export class Service extends DatabaseService<Model> {
470
474
  SET
471
475
  "latestCpuPercent" = COALESCE(v."cpu", k."latestCpuPercent"),
472
476
  "latestMemoryBytes" = COALESCE(v."mem", k."latestMemoryBytes"),
477
+ "latestMemoryPercent" = COALESCE(v."memPct", k."latestMemoryPercent"),
473
478
  "metricsUpdatedAt" = v."observedAt",
474
479
  "controllerDeploymentName" = COALESCE(v."deployName", k."controllerDeploymentName"),
475
480
  "controllerCronJobName" = COALESCE(v."cronName", k."controllerCronJobName"),
476
481
  "updatedAt" = now()
477
482
  FROM (VALUES ${valueFragments.join(", ")})
478
- AS v("kind", "ns", "name", "cpu", "mem", "observedAt", "deployName", "cronName")
483
+ AS v("kind", "ns", "name", "cpu", "mem", "memPct", "observedAt", "deployName", "cronName")
479
484
  WHERE
480
485
  k."projectId" = $1
481
486
  AND k."kubernetesClusterId" = $2
@@ -744,15 +749,22 @@ export class Service extends DatabaseService<Model> {
744
749
  projectId: ObjectID;
745
750
  kubernetesClusterId: ObjectID;
746
751
  staleAfter: Date;
747
- }): Promise<Map<string, { cpuPercent: number; memoryBytes: number }>> {
752
+ }): Promise<
753
+ Map<
754
+ string,
755
+ { cpuPercent: number; memoryBytes: number; memoryPercent: number }
756
+ >
757
+ > {
748
758
  const rows: Array<{
749
759
  namespaceKey: string;
750
760
  cpu: string | null;
751
761
  mem: string | null;
762
+ memPct: string | null;
752
763
  }> = await this.getRepository().manager.query(
753
764
  `SELECT "namespaceKey",
754
765
  SUM("latestCpuPercent")::text AS cpu,
755
- SUM("latestMemoryBytes")::text AS mem
766
+ SUM("latestMemoryBytes")::text AS mem,
767
+ SUM("latestMemoryPercent")::text AS "memPct"
756
768
  FROM "KubernetesResource"
757
769
  WHERE "projectId" = $1
758
770
  AND "kubernetesClusterId" = $2
@@ -768,12 +780,15 @@ export class Service extends DatabaseService<Model> {
768
780
  ],
769
781
  );
770
782
 
771
- const out: Map<string, { cpuPercent: number; memoryBytes: number }> =
772
- new Map();
783
+ const out: Map<
784
+ string,
785
+ { cpuPercent: number; memoryBytes: number; memoryPercent: number }
786
+ > = new Map();
773
787
  for (const row of rows) {
774
788
  out.set(row.namespaceKey || "", {
775
789
  cpuPercent: row.cpu ? parseFloat(row.cpu) || 0 : 0,
776
790
  memoryBytes: row.mem ? parseInt(row.mem, 10) || 0 : 0,
791
+ memoryPercent: row.memPct ? parseFloat(row.memPct) || 0 : 0,
777
792
  });
778
793
  }
779
794
  return out;
@@ -800,11 +815,17 @@ export class Service extends DatabaseService<Model> {
800
815
  kubernetesClusterId: ObjectID;
801
816
  ownerKind: string;
802
817
  staleAfter: Date;
803
- }): Promise<Map<string, { cpuPercent: number; memoryBytes: number }>> {
818
+ }): Promise<
819
+ Map<
820
+ string,
821
+ { cpuPercent: number; memoryBytes: number; memoryPercent: number }
822
+ >
823
+ > {
804
824
  let rows: Array<{
805
825
  ownerName: string;
806
826
  cpu: string | null;
807
827
  mem: string | null;
828
+ memPct: string | null;
808
829
  }>;
809
830
 
810
831
  if (data.ownerKind === "Deployment" || data.ownerKind === "CronJob") {
@@ -816,7 +837,8 @@ export class Service extends DatabaseService<Model> {
816
837
  `SELECT
817
838
  "${column}" AS "ownerName",
818
839
  SUM("latestCpuPercent")::text AS cpu,
819
- SUM("latestMemoryBytes")::text AS mem
840
+ SUM("latestMemoryBytes")::text AS mem,
841
+ SUM("latestMemoryPercent")::text AS "memPct"
820
842
  FROM "KubernetesResource"
821
843
  WHERE "projectId" = $1
822
844
  AND "kubernetesClusterId" = $2
@@ -837,7 +859,8 @@ export class Service extends DatabaseService<Model> {
837
859
  `SELECT
838
860
  (owner->>'name') AS "ownerName",
839
861
  SUM("latestCpuPercent")::text AS cpu,
840
- SUM("latestMemoryBytes")::text AS mem
862
+ SUM("latestMemoryBytes")::text AS mem,
863
+ SUM("latestMemoryPercent")::text AS "memPct"
841
864
  FROM "KubernetesResource",
842
865
  jsonb_array_elements("ownerReferences"->'items') AS owner
843
866
  WHERE "projectId" = $1
@@ -858,8 +881,10 @@ export class Service extends DatabaseService<Model> {
858
881
  );
859
882
  }
860
883
 
861
- const out: Map<string, { cpuPercent: number; memoryBytes: number }> =
862
- new Map();
884
+ const out: Map<
885
+ string,
886
+ { cpuPercent: number; memoryBytes: number; memoryPercent: number }
887
+ > = new Map();
863
888
  for (const row of rows) {
864
889
  if (!row.ownerName) {
865
890
  continue;
@@ -867,6 +892,7 @@ export class Service extends DatabaseService<Model> {
867
892
  out.set(row.ownerName, {
868
893
  cpuPercent: row.cpu ? parseFloat(row.cpu) || 0 : 0,
869
894
  memoryBytes: row.mem ? parseInt(row.mem, 10) || 0 : 0,
895
+ memoryPercent: row.memPct ? parseFloat(row.memPct) || 0 : 0,
870
896
  });
871
897
  }
872
898
  return out;