@oneuptime/common 10.5.8 → 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.
- package/Models/AnalyticsModels/ExceptionInstance.ts +1 -1
- package/Models/AnalyticsModels/Log.ts +1 -1
- package/Models/AnalyticsModels/Metric.ts +1 -1
- package/Models/AnalyticsModels/Profile.ts +1 -1
- package/Models/AnalyticsModels/ProfileSample.ts +1 -1
- package/Models/AnalyticsModels/Span.ts +1 -1
- package/Models/DatabaseModels/SmsLog.ts +111 -0
- package/Models/DatabaseModels/TelemetryException.ts +46 -34
- package/Models/DatabaseModels/TelemetryUsageBilling.ts +35 -2
- package/Server/API/AIAgentDataAPI.ts +25 -7
- package/Server/API/DashboardAPI.ts +616 -0
- package/Server/API/TelemetryExceptionAPI.ts +6 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1780317745887-AddDeliveryTrackingToSmsLog.ts +39 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1780381124553-MigrationName.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1780382837019-MigrationName.ts +24 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1780387560604-MigrationName.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1780388219225-MigrationName.ts +34 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Infrastructure/QueueWorker.ts +40 -1
- package/Server/Services/AnalyticsDatabaseService.ts +87 -0
- package/Server/Services/DatabaseService.ts +73 -0
- package/Server/Services/TelemetryExceptionService.ts +24 -49
- package/Server/Services/TelemetryUsageBillingService.ts +289 -166
- package/Server/Types/AnalyticsDatabase/ModelPermission.ts +102 -72
- package/Server/Types/Database/Permissions/OwnedScopePermission.ts +81 -60
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +67 -0
- package/Server/Utils/Logger.ts +12 -1
- package/Server/Utils/StartServer.ts +13 -5
- package/Server/Utils/Telemetry/ContextSpanProcessor.ts +48 -0
- package/Server/Utils/Telemetry/SpanUtil.ts +16 -35
- package/Server/Utils/Telemetry/TelemetryContext.ts +190 -0
- package/Server/Utils/Telemetry.ts +18 -2
- package/Types/Database/AccessControl/OwnedThrough.ts +31 -3
- package/Types/SmsStatus.ts +16 -0
- package/Types/Telemetry/ServiceType.ts +10 -0
- package/UI/Components/LogsViewer/LogsViewer.tsx +16 -0
- package/UI/Utils/Project.ts +6 -0
- package/UI/Utils/Telemetry/Telemetry.ts +65 -0
- package/UI/Utils/TelemetryService.ts +150 -0
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +1 -1
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Log.js +1 -1
- package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Metric.js +1 -1
- package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Profile.js +1 -1
- package/build/dist/Models/AnalyticsModels/Profile.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ProfileSample.js +1 -1
- package/build/dist/Models/AnalyticsModels/ProfileSample.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Span.js +1 -1
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/SmsLog.js +112 -0
- package/build/dist/Models/DatabaseModels/SmsLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +47 -33
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryUsageBilling.js +36 -2
- package/build/dist/Models/DatabaseModels/TelemetryUsageBilling.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +24 -8
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +459 -2
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryExceptionAPI.js +6 -2
- package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780317745887-AddDeliveryTrackingToSmsLog.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780317745887-AddDeliveryTrackingToSmsLog.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780381124553-MigrationName.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780381124553-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780382837019-MigrationName.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780382837019-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780387560604-MigrationName.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780387560604-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780388219225-MigrationName.js +25 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780388219225-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +31 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +59 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +62 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryExceptionService.js +16 -41
- package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +211 -147
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +84 -63
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js +67 -49
- package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +51 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Logger.js +8 -1
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +12 -4
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ContextSpanProcessor.js +37 -0
- package/build/dist/Server/Utils/Telemetry/ContextSpanProcessor.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js +15 -24
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryContext.js +124 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryContext.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry.js +12 -1
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/OwnedThrough.js +7 -2
- package/build/dist/Types/Database/AccessControl/OwnedThrough.js.map +1 -1
- package/build/dist/Types/SmsStatus.js +15 -0
- package/build/dist/Types/SmsStatus.js.map +1 -1
- package/build/dist/Types/Telemetry/ServiceType.js +10 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +15 -0
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Utils/Project.js +5 -0
- package/build/dist/UI/Utils/Project.js.map +1 -1
- package/build/dist/UI/Utils/Telemetry/Telemetry.js +44 -0
- package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +113 -0
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -0
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@ import { MeteredPlanUtil } from "../Types/Billing/MeteredPlan/AllMeteredPlans";
|
|
|
2
2
|
import TelemetryMeteredPlan from "../Types/Billing/MeteredPlan/TelemetryMeteredPlan";
|
|
3
3
|
import DatabaseService from "./DatabaseService";
|
|
4
4
|
import SortOrder from "../../Types/BaseDatabase/SortOrder";
|
|
5
|
-
import LIMIT_MAX
|
|
5
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
6
6
|
import OneUptimeDate from "../../Types/Date";
|
|
7
7
|
import Decimal from "../../Types/Decimal";
|
|
8
8
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
@@ -12,17 +12,24 @@ import Model, {
|
|
|
12
12
|
DEFAULT_RETENTION_IN_DAYS,
|
|
13
13
|
} from "../../Models/DatabaseModels/TelemetryUsageBilling";
|
|
14
14
|
import ServiceService from "./ServiceService";
|
|
15
|
+
import ProjectService from "./ProjectService";
|
|
16
|
+
import Project from "../../Models/DatabaseModels/Project";
|
|
15
17
|
import SpanService from "./SpanService";
|
|
16
18
|
import LogService from "./LogService";
|
|
17
19
|
import MetricService from "./MetricService";
|
|
18
20
|
import ExceptionInstanceService from "./ExceptionInstanceService";
|
|
19
21
|
import ProfileService from "./ProfileService";
|
|
20
22
|
import ProfileSampleService from "./ProfileSampleService";
|
|
21
|
-
import AnalyticsQueryHelper from "../Types/AnalyticsDatabase/QueryHelper";
|
|
22
23
|
import DiskSize from "../../Types/DiskSize";
|
|
23
24
|
import logger from "../Utils/Logger";
|
|
24
|
-
import PositiveNumber from "../../Types/PositiveNumber";
|
|
25
25
|
import ServiceModel from "../../Models/DatabaseModels/Service";
|
|
26
|
+
import HostService from "./HostService";
|
|
27
|
+
import DockerHostService from "./DockerHostService";
|
|
28
|
+
import KubernetesClusterService from "./KubernetesClusterService";
|
|
29
|
+
import Host from "../../Models/DatabaseModels/Host";
|
|
30
|
+
import DockerHost from "../../Models/DatabaseModels/DockerHost";
|
|
31
|
+
import KubernetesCluster from "../../Models/DatabaseModels/KubernetesCluster";
|
|
32
|
+
import ServiceType from "../../Types/Telemetry/ServiceType";
|
|
26
33
|
import {
|
|
27
34
|
AverageSpanRowSizeInBytes,
|
|
28
35
|
AverageLogRowSizeInBytes,
|
|
@@ -116,13 +123,157 @@ export class Service extends DatabaseService<Model> {
|
|
|
116
123
|
const startOfDay: Date = OneUptimeDate.getStartOfDay(usageDate);
|
|
117
124
|
const endOfDay: Date = OneUptimeDate.getEndOfDay(usageDate);
|
|
118
125
|
|
|
119
|
-
|
|
126
|
+
/*
|
|
127
|
+
* Enumerate usage from ClickHouse by (serviceId, serviceType) in a
|
|
128
|
+
* single aggregation scan per analytics table. Unlike the old
|
|
129
|
+
* per-Service-row loop, this surfaces EVERY resource that emitted
|
|
130
|
+
* telemetry — real Services AND Hosts / Docker hosts / Kubernetes
|
|
131
|
+
* clusters / unattributed (serviceId = projectId) — so infrastructure
|
|
132
|
+
* telemetry is no longer ingested for free. `byteSize(*)` gives the
|
|
133
|
+
* estimated ingested bytes per group; the configured average row size
|
|
134
|
+
* is only a fallback if the engine returns 0.
|
|
135
|
+
*/
|
|
136
|
+
type ServiceUsage = {
|
|
137
|
+
serviceType: string | null;
|
|
138
|
+
bytes: number;
|
|
139
|
+
};
|
|
140
|
+
const usageByServiceId: Map<string, ServiceUsage> = new Map();
|
|
141
|
+
|
|
142
|
+
const addUsage: (
|
|
143
|
+
rows: Array<{
|
|
144
|
+
serviceId: string;
|
|
145
|
+
serviceType: string | null;
|
|
146
|
+
rowCount: number;
|
|
147
|
+
estimatedBytes: number;
|
|
148
|
+
}>,
|
|
149
|
+
fallbackRowSizeInBytes: number,
|
|
150
|
+
) => void = (
|
|
151
|
+
rows: Array<{
|
|
152
|
+
serviceId: string;
|
|
153
|
+
serviceType: string | null;
|
|
154
|
+
rowCount: number;
|
|
155
|
+
estimatedBytes: number;
|
|
156
|
+
}>,
|
|
157
|
+
fallbackRowSizeInBytes: number,
|
|
158
|
+
): void => {
|
|
159
|
+
for (const row of rows) {
|
|
160
|
+
const bytes: number =
|
|
161
|
+
row.estimatedBytes > 0
|
|
162
|
+
? row.estimatedBytes
|
|
163
|
+
: row.rowCount * fallbackRowSizeInBytes;
|
|
164
|
+
const existing: ServiceUsage | undefined = usageByServiceId.get(
|
|
165
|
+
row.serviceId,
|
|
166
|
+
);
|
|
167
|
+
if (existing) {
|
|
168
|
+
existing.bytes += bytes;
|
|
169
|
+
if (!existing.serviceType && row.serviceType) {
|
|
170
|
+
existing.serviceType = row.serviceType;
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
usageByServiceId.set(row.serviceId, {
|
|
174
|
+
serviceType: row.serviceType,
|
|
175
|
+
bytes,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
if (data.productType === ProductType.Traces) {
|
|
183
|
+
addUsage(
|
|
184
|
+
await SpanService.groupTelemetryUsageByService({
|
|
185
|
+
projectId: data.projectId,
|
|
186
|
+
timestampColumnName: "startTime",
|
|
187
|
+
startDate: startOfDay,
|
|
188
|
+
endDate: endOfDay,
|
|
189
|
+
}),
|
|
190
|
+
averageRowSizeInBytes,
|
|
191
|
+
);
|
|
192
|
+
addUsage(
|
|
193
|
+
await ExceptionInstanceService.groupTelemetryUsageByService({
|
|
194
|
+
projectId: data.projectId,
|
|
195
|
+
timestampColumnName: "time",
|
|
196
|
+
startDate: startOfDay,
|
|
197
|
+
endDate: endOfDay,
|
|
198
|
+
}),
|
|
199
|
+
averageExceptionRowSizeInBytes,
|
|
200
|
+
);
|
|
201
|
+
} else if (data.productType === ProductType.Logs) {
|
|
202
|
+
addUsage(
|
|
203
|
+
await LogService.groupTelemetryUsageByService({
|
|
204
|
+
projectId: data.projectId,
|
|
205
|
+
timestampColumnName: "time",
|
|
206
|
+
startDate: startOfDay,
|
|
207
|
+
endDate: endOfDay,
|
|
208
|
+
}),
|
|
209
|
+
averageRowSizeInBytes,
|
|
210
|
+
);
|
|
211
|
+
} else if (data.productType === ProductType.Metrics) {
|
|
212
|
+
addUsage(
|
|
213
|
+
await MetricService.groupTelemetryUsageByService({
|
|
214
|
+
projectId: data.projectId,
|
|
215
|
+
timestampColumnName: "time",
|
|
216
|
+
startDate: startOfDay,
|
|
217
|
+
endDate: endOfDay,
|
|
218
|
+
}),
|
|
219
|
+
averageRowSizeInBytes,
|
|
220
|
+
);
|
|
221
|
+
} else if (data.productType === ProductType.Profiles) {
|
|
222
|
+
addUsage(
|
|
223
|
+
await ProfileService.groupTelemetryUsageByService({
|
|
224
|
+
projectId: data.projectId,
|
|
225
|
+
timestampColumnName: "startTime",
|
|
226
|
+
startDate: startOfDay,
|
|
227
|
+
endDate: endOfDay,
|
|
228
|
+
}),
|
|
229
|
+
averageRowSizeInBytes,
|
|
230
|
+
);
|
|
231
|
+
addUsage(
|
|
232
|
+
await ProfileSampleService.groupTelemetryUsageByService({
|
|
233
|
+
projectId: data.projectId,
|
|
234
|
+
timestampColumnName: "time",
|
|
235
|
+
startDate: startOfDay,
|
|
236
|
+
endDate: endOfDay,
|
|
237
|
+
}),
|
|
238
|
+
averageProfileSampleRowSizeInBytes,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
logger.error(
|
|
243
|
+
`Failed to aggregate telemetry usage for project ${data.projectId.toString()} (${data.productType}):`,
|
|
244
|
+
);
|
|
245
|
+
logger.error(error as Error);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (usageByServiceId.size === 0) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/*
|
|
254
|
+
* Resolve retention per resource (Service / Host / DockerHost /
|
|
255
|
+
* KubernetesCluster overrides), defaulting to the project default for
|
|
256
|
+
* everything else — including the unattributed bucket. Retention
|
|
257
|
+
* scales the billed cost, so we honor per-resource overrides.
|
|
258
|
+
*/
|
|
259
|
+
const retentionByServiceId: Map<string, number> =
|
|
260
|
+
await this.buildTelemetryRetentionMap(data.projectId);
|
|
261
|
+
const projectDefaultRetentionInDays: number =
|
|
262
|
+
await this.getProjectDefaultRetentionInDays(data.projectId);
|
|
263
|
+
|
|
264
|
+
/*
|
|
265
|
+
* Skip serviceIds already staged for this day so re-runs of the cron
|
|
266
|
+
* don't double-count (updateUsageBilling accumulates into the day's
|
|
267
|
+
* row). One query instead of a findOneBy per serviceId.
|
|
268
|
+
*/
|
|
269
|
+
const alreadyStaged: Array<Model> = await this.findBy({
|
|
120
270
|
query: {
|
|
121
271
|
projectId: data.projectId,
|
|
272
|
+
productType: data.productType,
|
|
273
|
+
day: usageDayString,
|
|
122
274
|
},
|
|
123
275
|
select: {
|
|
124
|
-
|
|
125
|
-
retainTelemetryDataForDays: true,
|
|
276
|
+
serviceId: true,
|
|
126
277
|
},
|
|
127
278
|
skip: 0,
|
|
128
279
|
limit: LIMIT_MAX,
|
|
@@ -130,187 +281,155 @@ export class Service extends DatabaseService<Model> {
|
|
|
130
281
|
isRoot: true,
|
|
131
282
|
},
|
|
132
283
|
});
|
|
284
|
+
const stagedServiceIds: Set<string> = new Set(
|
|
285
|
+
alreadyStaged
|
|
286
|
+
.map((row: Model) => {
|
|
287
|
+
return row.serviceId?.toString();
|
|
288
|
+
})
|
|
289
|
+
.filter((id: string | undefined): id is string => {
|
|
290
|
+
return Boolean(id);
|
|
291
|
+
}),
|
|
292
|
+
);
|
|
133
293
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
294
|
+
for (const [serviceIdStr, usage] of usageByServiceId) {
|
|
295
|
+
/*
|
|
296
|
+
* Monitor telemetry is billed via the Active Monitoring plan, and
|
|
297
|
+
* Alert/Incident telemetry is OneUptime's own operational data —
|
|
298
|
+
* neither is charged as ingested telemetry volume.
|
|
299
|
+
*/
|
|
300
|
+
if (
|
|
301
|
+
usage.serviceType === ServiceType.Monitor ||
|
|
302
|
+
usage.serviceType === ServiceType.Alert ||
|
|
303
|
+
usage.serviceType === ServiceType.Incident
|
|
304
|
+
) {
|
|
140
305
|
continue;
|
|
141
306
|
}
|
|
142
307
|
|
|
143
|
-
|
|
144
|
-
query: {
|
|
145
|
-
projectId: data.projectId,
|
|
146
|
-
productType: data.productType,
|
|
147
|
-
serviceId: service.id,
|
|
148
|
-
day: usageDayString,
|
|
149
|
-
},
|
|
150
|
-
select: {
|
|
151
|
-
_id: true,
|
|
152
|
-
},
|
|
153
|
-
props: {
|
|
154
|
-
isRoot: true,
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
if (existingEntry) {
|
|
308
|
+
if (stagedServiceIds.has(serviceIdStr)) {
|
|
159
309
|
continue;
|
|
160
310
|
}
|
|
161
311
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const spanCount: PositiveNumber = await SpanService.countBy({
|
|
167
|
-
query: {
|
|
168
|
-
projectId: data.projectId,
|
|
169
|
-
serviceId: service.id,
|
|
170
|
-
startTime: AnalyticsQueryHelper.inBetween(startOfDay, endOfDay),
|
|
171
|
-
},
|
|
172
|
-
skip: 0,
|
|
173
|
-
limit: LIMIT_INFINITY,
|
|
174
|
-
props: {
|
|
175
|
-
isRoot: true,
|
|
176
|
-
},
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
const exceptionCount: PositiveNumber =
|
|
180
|
-
await ExceptionInstanceService.countBy({
|
|
181
|
-
query: {
|
|
182
|
-
projectId: data.projectId,
|
|
183
|
-
serviceId: service.id,
|
|
184
|
-
time: AnalyticsQueryHelper.inBetween(startOfDay, endOfDay),
|
|
185
|
-
},
|
|
186
|
-
skip: 0,
|
|
187
|
-
limit: LIMIT_INFINITY,
|
|
188
|
-
props: {
|
|
189
|
-
isRoot: true,
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
const totalSpanCount: number = spanCount.toNumber();
|
|
194
|
-
const totalExceptionCount: number = exceptionCount.toNumber();
|
|
195
|
-
|
|
196
|
-
if (totalSpanCount <= 0 && totalExceptionCount <= 0) {
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
estimatedBytes =
|
|
201
|
-
totalSpanCount * averageRowSizeInBytes +
|
|
202
|
-
totalExceptionCount * averageExceptionRowSizeInBytes;
|
|
203
|
-
} else if (data.productType === ProductType.Logs) {
|
|
204
|
-
const count: PositiveNumber = await LogService.countBy({
|
|
205
|
-
query: {
|
|
206
|
-
projectId: data.projectId,
|
|
207
|
-
serviceId: service.id,
|
|
208
|
-
time: AnalyticsQueryHelper.inBetween(startOfDay, endOfDay),
|
|
209
|
-
},
|
|
210
|
-
skip: 0,
|
|
211
|
-
limit: LIMIT_INFINITY,
|
|
212
|
-
props: {
|
|
213
|
-
isRoot: true,
|
|
214
|
-
},
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
const totalRowCount: number = count.toNumber();
|
|
218
|
-
|
|
219
|
-
if (totalRowCount <= 0) {
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
312
|
+
const estimatedGigabytes: number = DiskSize.byteSizeToGB(usage.bytes);
|
|
313
|
+
if (!Number.isFinite(estimatedGigabytes) || estimatedGigabytes <= 0) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
222
316
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const count: PositiveNumber = await MetricService.countBy({
|
|
226
|
-
query: {
|
|
227
|
-
projectId: data.projectId,
|
|
228
|
-
serviceId: service.id,
|
|
229
|
-
time: AnalyticsQueryHelper.inBetween(startOfDay, endOfDay),
|
|
230
|
-
},
|
|
231
|
-
skip: 0,
|
|
232
|
-
limit: LIMIT_INFINITY,
|
|
233
|
-
props: {
|
|
234
|
-
isRoot: true,
|
|
235
|
-
},
|
|
236
|
-
});
|
|
317
|
+
const retentionInDays: number =
|
|
318
|
+
retentionByServiceId.get(serviceIdStr) ?? projectDefaultRetentionInDays;
|
|
237
319
|
|
|
238
|
-
|
|
320
|
+
/*
|
|
321
|
+
* Legacy rows (pre-discriminator) and any null serviceType are
|
|
322
|
+
* treated as OpenTelemetry — historically every billed serviceId was
|
|
323
|
+
* a real Service.
|
|
324
|
+
*/
|
|
325
|
+
const serviceType: ServiceType =
|
|
326
|
+
(usage.serviceType as ServiceType | null) ?? ServiceType.OpenTelemetry;
|
|
239
327
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
},
|
|
252
|
-
skip: 0,
|
|
253
|
-
limit: LIMIT_INFINITY,
|
|
254
|
-
props: {
|
|
255
|
-
isRoot: true,
|
|
256
|
-
},
|
|
257
|
-
});
|
|
328
|
+
await this.updateUsageBilling({
|
|
329
|
+
projectId: data.projectId,
|
|
330
|
+
productType: data.productType,
|
|
331
|
+
serviceId: new ObjectID(serviceIdStr),
|
|
332
|
+
serviceType: serviceType,
|
|
333
|
+
dataIngestedInGB: estimatedGigabytes,
|
|
334
|
+
retentionInDays: retentionInDays,
|
|
335
|
+
usageDate: usageDate,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
258
339
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
const totalProfileCount: number = profileCount.toNumber();
|
|
274
|
-
const totalProfileSampleCount: number = profileSampleCount.toNumber();
|
|
275
|
-
|
|
276
|
-
if (totalProfileCount <= 0 && totalProfileSampleCount <= 0) {
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
340
|
+
/*
|
|
341
|
+
* Map of resourceId -> retainTelemetryDataForDays for every resource in
|
|
342
|
+
* the project that can own telemetry (Service, Host, DockerHost,
|
|
343
|
+
* KubernetesCluster). Used to scale billed cost by the actual retention
|
|
344
|
+
* applied to each resource's telemetry. Resources without an override
|
|
345
|
+
* (and the unattributed bucket) fall back to the project default.
|
|
346
|
+
*/
|
|
347
|
+
@CaptureSpan()
|
|
348
|
+
private async buildTelemetryRetentionMap(
|
|
349
|
+
projectId: ObjectID,
|
|
350
|
+
): Promise<Map<string, number>> {
|
|
351
|
+
const retentionByServiceId: Map<string, number> = new Map();
|
|
279
352
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
353
|
+
const services: Array<ServiceModel> = await ServiceService.findBy({
|
|
354
|
+
query: { projectId: projectId },
|
|
355
|
+
select: { _id: true, retainTelemetryDataForDays: true },
|
|
356
|
+
skip: 0,
|
|
357
|
+
limit: LIMIT_MAX,
|
|
358
|
+
props: { isRoot: true },
|
|
359
|
+
});
|
|
360
|
+
for (const service of services) {
|
|
361
|
+
if (service.id && service.retainTelemetryDataForDays) {
|
|
362
|
+
retentionByServiceId.set(
|
|
363
|
+
service.id.toString(),
|
|
364
|
+
service.retainTelemetryDataForDays,
|
|
287
365
|
);
|
|
288
|
-
logger.error(error as Error);
|
|
289
|
-
continue;
|
|
290
366
|
}
|
|
367
|
+
}
|
|
291
368
|
|
|
292
|
-
|
|
293
|
-
|
|
369
|
+
const hosts: Array<Host> = await HostService.findBy({
|
|
370
|
+
query: { projectId: projectId },
|
|
371
|
+
select: { _id: true, retainTelemetryDataForDays: true },
|
|
372
|
+
skip: 0,
|
|
373
|
+
limit: LIMIT_MAX,
|
|
374
|
+
props: { isRoot: true },
|
|
375
|
+
});
|
|
376
|
+
for (const host of hosts) {
|
|
377
|
+
if (host.id && host.retainTelemetryDataForDays) {
|
|
378
|
+
retentionByServiceId.set(
|
|
379
|
+
host.id.toString(),
|
|
380
|
+
host.retainTelemetryDataForDays,
|
|
381
|
+
);
|
|
294
382
|
}
|
|
383
|
+
}
|
|
295
384
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
385
|
+
const dockerHosts: Array<DockerHost> = await DockerHostService.findBy({
|
|
386
|
+
query: { projectId: projectId },
|
|
387
|
+
select: { _id: true, retainTelemetryDataForDays: true },
|
|
388
|
+
skip: 0,
|
|
389
|
+
limit: LIMIT_MAX,
|
|
390
|
+
props: { isRoot: true },
|
|
391
|
+
});
|
|
392
|
+
for (const dockerHost of dockerHosts) {
|
|
393
|
+
if (dockerHost.id && dockerHost.retainTelemetryDataForDays) {
|
|
394
|
+
retentionByServiceId.set(
|
|
395
|
+
dockerHost.id.toString(),
|
|
396
|
+
dockerHost.retainTelemetryDataForDays,
|
|
397
|
+
);
|
|
300
398
|
}
|
|
399
|
+
}
|
|
301
400
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
dataIngestedInGB: estimatedGigabytes,
|
|
310
|
-
retentionInDays: dataRetentionInDays,
|
|
311
|
-
usageDate: usageDate,
|
|
401
|
+
const clusters: Array<KubernetesCluster> =
|
|
402
|
+
await KubernetesClusterService.findBy({
|
|
403
|
+
query: { projectId: projectId },
|
|
404
|
+
select: { _id: true, retainTelemetryDataForDays: true },
|
|
405
|
+
skip: 0,
|
|
406
|
+
limit: LIMIT_MAX,
|
|
407
|
+
props: { isRoot: true },
|
|
312
408
|
});
|
|
409
|
+
for (const cluster of clusters) {
|
|
410
|
+
if (cluster.id && cluster.retainTelemetryDataForDays) {
|
|
411
|
+
retentionByServiceId.set(
|
|
412
|
+
cluster.id.toString(),
|
|
413
|
+
cluster.retainTelemetryDataForDays,
|
|
414
|
+
);
|
|
415
|
+
}
|
|
313
416
|
}
|
|
417
|
+
|
|
418
|
+
return retentionByServiceId;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
@CaptureSpan()
|
|
422
|
+
private async getProjectDefaultRetentionInDays(
|
|
423
|
+
projectId: ObjectID,
|
|
424
|
+
): Promise<number> {
|
|
425
|
+
const project: Project | null = await ProjectService.findOneById({
|
|
426
|
+
id: projectId,
|
|
427
|
+
select: { defaultTelemetryRetentionInDays: true },
|
|
428
|
+
props: { isRoot: true },
|
|
429
|
+
});
|
|
430
|
+
return (
|
|
431
|
+
project?.defaultTelemetryRetentionInDays || DEFAULT_RETENTION_IN_DAYS
|
|
432
|
+
);
|
|
314
433
|
}
|
|
315
434
|
|
|
316
435
|
@CaptureSpan()
|
|
@@ -318,6 +437,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
318
437
|
projectId: ObjectID;
|
|
319
438
|
productType: ProductType;
|
|
320
439
|
serviceId: ObjectID;
|
|
440
|
+
serviceType?: ServiceType | undefined;
|
|
321
441
|
dataIngestedInGB: number;
|
|
322
442
|
retentionInDays: number;
|
|
323
443
|
usageDate?: Date;
|
|
@@ -404,6 +524,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
404
524
|
usageBilling.productType = data.productType;
|
|
405
525
|
usageBilling.dataIngestedInGB = new Decimal(data.dataIngestedInGB);
|
|
406
526
|
usageBilling.serviceId = data.serviceId;
|
|
527
|
+
if (data.serviceType) {
|
|
528
|
+
usageBilling.serviceType = data.serviceType;
|
|
529
|
+
}
|
|
407
530
|
usageBilling.retainTelemetryDataForDays = data.retentionInDays;
|
|
408
531
|
usageBilling.isReportedToBillingProvider = false;
|
|
409
532
|
usageBilling.createdAt = usageDate;
|