@oneuptime/common 10.5.9 → 10.5.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 (106) hide show
  1. package/Models/AnalyticsModels/ExceptionInstance.ts +1 -1
  2. package/Models/AnalyticsModels/Log.ts +1 -1
  3. package/Models/AnalyticsModels/Metric.ts +1 -1
  4. package/Models/AnalyticsModels/Profile.ts +1 -1
  5. package/Models/AnalyticsModels/ProfileSample.ts +1 -1
  6. package/Models/AnalyticsModels/Span.ts +1 -1
  7. package/Models/DatabaseModels/TelemetryException.ts +46 -34
  8. package/Models/DatabaseModels/TelemetryUsageBilling.ts +35 -2
  9. package/Server/API/AIAgentDataAPI.ts +25 -7
  10. package/Server/API/TelemetryExceptionAPI.ts +6 -2
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1780381124553-MigrationName.ts +28 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1780382837019-MigrationName.ts +24 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1780387560604-MigrationName.ts +47 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1780388219225-MigrationName.ts +34 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  16. package/Server/Infrastructure/QueueWorker.ts +40 -1
  17. package/Server/Services/AnalyticsDatabaseService.ts +87 -0
  18. package/Server/Services/DatabaseService.ts +73 -0
  19. package/Server/Services/TelemetryExceptionService.ts +24 -49
  20. package/Server/Services/TelemetryUsageBillingService.ts +289 -166
  21. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +102 -72
  22. package/Server/Types/Database/Permissions/OwnedScopePermission.ts +81 -60
  23. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +67 -0
  24. package/Server/Utils/Logger.ts +12 -1
  25. package/Server/Utils/StartServer.ts +13 -5
  26. package/Server/Utils/Telemetry/ContextSpanProcessor.ts +48 -0
  27. package/Server/Utils/Telemetry/SpanUtil.ts +16 -35
  28. package/Server/Utils/Telemetry/TelemetryContext.ts +190 -0
  29. package/Server/Utils/Telemetry.ts +18 -2
  30. package/Types/Database/AccessControl/OwnedThrough.ts +31 -3
  31. package/Types/Telemetry/ServiceType.ts +10 -0
  32. package/UI/Components/LogsViewer/LogsViewer.tsx +16 -0
  33. package/UI/Utils/Project.ts +6 -0
  34. package/UI/Utils/Telemetry/Telemetry.ts +65 -0
  35. package/UI/Utils/TelemetryService.ts +150 -0
  36. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +1 -1
  37. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
  38. package/build/dist/Models/AnalyticsModels/Log.js +1 -1
  39. package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
  40. package/build/dist/Models/AnalyticsModels/Metric.js +1 -1
  41. package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
  42. package/build/dist/Models/AnalyticsModels/Profile.js +1 -1
  43. package/build/dist/Models/AnalyticsModels/Profile.js.map +1 -1
  44. package/build/dist/Models/AnalyticsModels/ProfileSample.js +1 -1
  45. package/build/dist/Models/AnalyticsModels/ProfileSample.js.map +1 -1
  46. package/build/dist/Models/AnalyticsModels/Span.js +1 -1
  47. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  48. package/build/dist/Models/DatabaseModels/TelemetryException.js +47 -33
  49. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  50. package/build/dist/Models/DatabaseModels/TelemetryUsageBilling.js +36 -2
  51. package/build/dist/Models/DatabaseModels/TelemetryUsageBilling.js.map +1 -1
  52. package/build/dist/Server/API/AIAgentDataAPI.js +24 -8
  53. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  54. package/build/dist/Server/API/TelemetryExceptionAPI.js +6 -2
  55. package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
  56. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780381124553-MigrationName.js +23 -0
  57. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780381124553-MigrationName.js.map +1 -0
  58. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780382837019-MigrationName.js +19 -0
  59. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780382837019-MigrationName.js.map +1 -0
  60. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780387560604-MigrationName.js +22 -0
  61. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780387560604-MigrationName.js.map +1 -0
  62. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780388219225-MigrationName.js +25 -0
  63. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780388219225-MigrationName.js.map +1 -0
  64. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  65. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  66. package/build/dist/Server/Infrastructure/QueueWorker.js +31 -1
  67. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  68. package/build/dist/Server/Services/AnalyticsDatabaseService.js +59 -0
  69. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  70. package/build/dist/Server/Services/DatabaseService.js +62 -0
  71. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  72. package/build/dist/Server/Services/TelemetryExceptionService.js +16 -41
  73. package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
  74. package/build/dist/Server/Services/TelemetryUsageBillingService.js +211 -147
  75. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  76. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +84 -63
  77. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  78. package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js +67 -49
  79. package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js.map +1 -1
  80. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +51 -0
  81. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  82. package/build/dist/Server/Utils/Logger.js +8 -1
  83. package/build/dist/Server/Utils/Logger.js.map +1 -1
  84. package/build/dist/Server/Utils/StartServer.js +12 -4
  85. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  86. package/build/dist/Server/Utils/Telemetry/ContextSpanProcessor.js +37 -0
  87. package/build/dist/Server/Utils/Telemetry/ContextSpanProcessor.js.map +1 -0
  88. package/build/dist/Server/Utils/Telemetry/SpanUtil.js +15 -24
  89. package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
  90. package/build/dist/Server/Utils/Telemetry/TelemetryContext.js +124 -0
  91. package/build/dist/Server/Utils/Telemetry/TelemetryContext.js.map +1 -0
  92. package/build/dist/Server/Utils/Telemetry.js +12 -1
  93. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  94. package/build/dist/Types/Database/AccessControl/OwnedThrough.js +7 -2
  95. package/build/dist/Types/Database/AccessControl/OwnedThrough.js.map +1 -1
  96. package/build/dist/Types/Telemetry/ServiceType.js +10 -0
  97. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  98. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +15 -0
  99. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  100. package/build/dist/UI/Utils/Project.js +5 -0
  101. package/build/dist/UI/Utils/Project.js.map +1 -1
  102. package/build/dist/UI/Utils/Telemetry/Telemetry.js +44 -0
  103. package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
  104. package/build/dist/UI/Utils/TelemetryService.js +113 -0
  105. package/build/dist/UI/Utils/TelemetryService.js.map +1 -0
  106. package/package.json +1 -1
@@ -54,6 +54,7 @@ import HashedString from "../../Types/HashedString";
54
54
  import { JSONObject, JSONValue } from "../../Types/JSON";
55
55
  import JSONFunctions from "../../Types/JSONFunctions";
56
56
  import ObjectID from "../../Types/ObjectID";
57
+ import TelemetryContext from "../Utils/Telemetry/TelemetryContext";
57
58
  import PositiveNumber from "../../Types/PositiveNumber";
58
59
  import Text from "../../Types/Text";
59
60
  import Typeof from "../../Types/Typeof";
@@ -681,6 +682,69 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
681
682
  }
682
683
  }
683
684
 
685
+ /**
686
+ * Derive the telemetry attribute key for this model's primary id, e.g.
687
+ * `Incident` -> `incidentId`, `Monitor` -> `monitorId`. Matches the keys in
688
+ * TelemetryContextAttributes so dashboards/queries stay consistent.
689
+ */
690
+ private getTelemetryEntityIdKey(): string {
691
+ const name: string = this.modelName || "entity";
692
+ return name.charAt(0).toLowerCase() + name.slice(1) + "Id";
693
+ }
694
+
695
+ /**
696
+ * Seed the ambient telemetry context with the project (tenant) of an
697
+ * operation so worker/cron/service spans and logs — which run outside the
698
+ * HTTP request scope — still carry projectId. Best-effort and safe to call
699
+ * anywhere.
700
+ */
701
+ protected setTelemetryContextFromProps(
702
+ props: DatabaseCommonInteractionProps | undefined,
703
+ ): void {
704
+ try {
705
+ if (props?.tenantId) {
706
+ TelemetryContext.setAttributes({
707
+ projectId: props.tenantId.toString(),
708
+ });
709
+ }
710
+ } catch {
711
+ // Telemetry must never break a database operation.
712
+ }
713
+ }
714
+
715
+ /**
716
+ * Seed the ambient telemetry context from a concrete model instance: the
717
+ * project (tenant) and the entity's own id (e.g. incidentId, monitorId).
718
+ * Used on create, where a new entity id is minted. Best-effort and safe.
719
+ */
720
+ protected setTelemetryContextFromItem(item: TBaseModel | undefined): void {
721
+ try {
722
+ if (!item) {
723
+ return;
724
+ }
725
+
726
+ const attributes: { [key: string]: string } = {};
727
+
728
+ const tenantColumn: string | null = this.model.getTenantColumn();
729
+ if (tenantColumn) {
730
+ const tenantValue: unknown = item.getColumnValue(tenantColumn);
731
+ if (tenantValue) {
732
+ attributes["projectId"] = String(tenantValue);
733
+ }
734
+ }
735
+
736
+ if (item.id) {
737
+ attributes[this.getTelemetryEntityIdKey()] = item.id.toString();
738
+ }
739
+
740
+ if (Object.keys(attributes).length > 0) {
741
+ TelemetryContext.setAttributes(attributes);
742
+ }
743
+ } catch {
744
+ // Telemetry must never break a database operation.
745
+ }
746
+ }
747
+
684
748
  @CaptureSpan()
685
749
  public async create(createBy: CreateBy<TBaseModel>): Promise<TBaseModel> {
686
750
  const onCreate: OnCreate<TBaseModel> = createBy.props.ignoreHooks
@@ -742,6 +806,9 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
742
806
  try {
743
807
  createBy.data = await this.getRepository().save(createBy.data);
744
808
 
809
+ // Seed telemetry context with projectId + <model>Id for this create.
810
+ this.setTelemetryContextFromItem(createBy.data);
811
+
745
812
  if (!createBy.props.ignoreHooks) {
746
813
  createBy.data = await this.onCreateSuccess(
747
814
  {
@@ -1216,6 +1283,8 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
1216
1283
 
1217
1284
  private async _deleteBy(deleteBy: DeleteBy<TBaseModel>): Promise<number> {
1218
1285
  try {
1286
+ this.setTelemetryContextFromProps(deleteBy.props);
1287
+
1219
1288
  if (this.doNotAllowDelete && !deleteBy.props.isRoot) {
1220
1289
  throw new BadDataException("Delete not allowed");
1221
1290
  }
@@ -1444,6 +1513,8 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
1444
1513
  withDeleted?: boolean | undefined,
1445
1514
  ): Promise<Array<TBaseModel>> {
1446
1515
  try {
1516
+ this.setTelemetryContextFromProps(findBy.props);
1517
+
1447
1518
  let automaticallyAddedCreatedAtInSelect: boolean = false;
1448
1519
 
1449
1520
  if (!findBy.sort || Object.keys(findBy.sort).length === 0) {
@@ -1638,6 +1709,8 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
1638
1709
 
1639
1710
  private async _updateBy(updateBy: UpdateBy<TBaseModel>): Promise<number> {
1640
1711
  try {
1712
+ this.setTelemetryContextFromProps(updateBy.props);
1713
+
1641
1714
  const onUpdate: OnUpdate<TBaseModel> = updateBy.props.ignoreHooks
1642
1715
  ? { updateBy, carryForward: [] }
1643
1716
  : await this.onBeforeUpdate(updateBy);
@@ -1,10 +1,9 @@
1
1
  import DatabaseService from "./DatabaseService";
2
2
  import Model from "../../Models/DatabaseModels/TelemetryException";
3
- import TelemetryServiceModel from "../../Models/DatabaseModels/Service";
3
+ import ServiceType from "../../Types/Telemetry/ServiceType";
4
4
  import AIAgentTask from "../../Models/DatabaseModels/AIAgentTask";
5
5
  import AIAgentTaskTelemetryException from "../../Models/DatabaseModels/AIAgentTaskTelemetryException";
6
6
  import ObjectID from "../../Types/ObjectID";
7
- import PositiveNumber from "../../Types/PositiveNumber";
8
7
  import SortOrder from "../../Types/BaseDatabase/SortOrder";
9
8
  import BadDataException from "../../Types/Exception/BadDataException";
10
9
  import AIAgentTaskType from "../../Types/AI/AIAgentTaskType";
@@ -13,7 +12,6 @@ import { FixExceptionTaskMetadata } from "../../Types/AI/AIAgentTaskMetadata";
13
12
  import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
14
13
  import AIAgentTaskService from "./AIAgentTaskService";
15
14
  import AIAgentTaskTelemetryExceptionService from "./AIAgentTaskTelemetryExceptionService";
16
- import ServiceService from "./ServiceService";
17
15
  import QueryHelper from "../Types/Database/QueryHelper";
18
16
  import ModelPermission from "../Types/Database/Permissions/Index";
19
17
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
@@ -24,7 +22,13 @@ export interface CreateAIAgentTaskForExceptionParams {
24
22
  }
25
23
 
26
24
  export interface DashboardServiceSummary {
27
- service: TelemetryServiceModel;
25
+ /*
26
+ * Polymorphic: a real Service, a Host/DockerHost/KubernetesCluster id, or
27
+ * the projectId for unattributed telemetry. The client resolves the
28
+ * display name per serviceType.
29
+ */
30
+ serviceId: string;
31
+ serviceType: ServiceType | null;
28
32
  unresolvedCount: number;
29
33
  totalOccurrences: number;
30
34
  }
@@ -182,11 +186,9 @@ export class Service extends DatabaseService<Model> {
182
186
  lastSeenAt: true,
183
187
  firstSeenAt: true,
184
188
  environment: true,
185
- service: {
186
- _id: true,
187
- name: true,
188
- serviceColor: true,
189
- },
189
+ // serviceId is polymorphic; the client resolves it per serviceType.
190
+ serviceId: true,
191
+ serviceType: true,
190
192
  };
191
193
 
192
194
  const [
@@ -284,6 +286,7 @@ export class Service extends DatabaseService<Model> {
284
286
 
285
287
  interface AggregateRow {
286
288
  serviceId: string | null;
289
+ serviceType: string | null;
287
290
  unresolvedCount: string;
288
291
  totalOccurrences: string | null;
289
292
  }
@@ -292,6 +295,7 @@ export class Service extends DatabaseService<Model> {
292
295
  "TelemetryException",
293
296
  )
294
297
  .select(`"TelemetryException"."serviceId"`, "serviceId")
298
+ .addSelect(`"TelemetryException"."serviceType"`, "serviceType")
295
299
  .addSelect(`COUNT(*)`, "unresolvedCount")
296
300
  .addSelect(
297
301
  `COALESCE(SUM("TelemetryException"."occuranceCount"), 0)`,
@@ -305,6 +309,7 @@ export class Service extends DatabaseService<Model> {
305
309
  .andWhere(`"TelemetryException"."deletedAt" IS NULL`)
306
310
  .andWhere(`"TelemetryException"."serviceId" IS NOT NULL`)
307
311
  .groupBy(`"TelemetryException"."serviceId"`)
312
+ .addGroupBy(`"TelemetryException"."serviceType"`)
308
313
  .orderBy(`"unresolvedCount"`, "DESC")
309
314
  .getRawMany()) as Array<AggregateRow>;
310
315
 
@@ -312,52 +317,22 @@ export class Service extends DatabaseService<Model> {
312
317
  return [];
313
318
  }
314
319
 
315
- const serviceIds: Array<string> = [];
316
- for (const row of rows) {
317
- if (row.serviceId) {
318
- serviceIds.push(row.serviceId);
319
- }
320
- }
321
-
322
- if (serviceIds.length === 0) {
323
- return [];
324
- }
325
-
326
- const services: Array<TelemetryServiceModel> = await ServiceService.findBy({
327
- query: {
328
- projectId,
329
- _id: QueryHelper.any(serviceIds),
330
- },
331
- select: {
332
- _id: true,
333
- name: true,
334
- serviceColor: true,
335
- },
336
- limit: new PositiveNumber(serviceIds.length),
337
- skip: new PositiveNumber(0),
338
- props,
339
- });
340
-
341
- const serviceById: Map<string, TelemetryServiceModel> = new Map();
342
- for (const service of services) {
343
- if (service._id) {
344
- serviceById.set(service._id, service);
345
- }
346
- }
347
-
320
+ /*
321
+ * serviceId is polymorphic do NOT resolve it to a Service here. The
322
+ * old code looked each serviceId up in the Service table and dropped
323
+ * any that didn't match, which silently excluded Host / DockerHost /
324
+ * KubernetesCluster and unattributed (Unknown) telemetry. Return the
325
+ * raw (serviceId, serviceType) + counts; the client resolves the
326
+ * display name per serviceType.
327
+ */
348
328
  const summaries: Array<DashboardServiceSummary> = [];
349
329
  for (const row of rows) {
350
330
  if (!row.serviceId) {
351
331
  continue;
352
332
  }
353
- const service: TelemetryServiceModel | undefined = serviceById.get(
354
- row.serviceId,
355
- );
356
- if (!service) {
357
- continue;
358
- }
359
333
  summaries.push({
360
- service,
334
+ serviceId: row.serviceId,
335
+ serviceType: (row.serviceType as ServiceType | null) ?? null,
361
336
  unresolvedCount: parseInt(row.unresolvedCount, 10) || 0,
362
337
  totalOccurrences: parseInt(row.totalOccurrences || "0", 10) || 0,
363
338
  });