@oneuptime/common 10.0.54 → 10.0.56
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/DatabaseModels/DockerHost.ts +662 -0
- package/Models/DatabaseModels/GlobalConfig.ts +112 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Server/API/TelemetryAPI.ts +352 -16
- package/Server/Infrastructure/ClickhouseConfig.ts +9 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1774000000002-MigrationName.ts +76 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1775766676723-MigrationName.ts +133 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1775900000000-AddGlobalSmtpOAuth.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Services/DockerHostService.ts +173 -0
- package/Server/Services/ExceptionAggregationService.ts +335 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/LogAggregationService.ts +17 -0
- package/Server/Services/MonitorProbeService.ts +42 -21
- package/Server/Services/MonitorService.ts +21 -21
- package/Server/Services/TraceAggregationService.ts +514 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +73 -1
- package/Tests/Server/Services/LogAggregationService.test.ts +2 -2
- package/Tests/__mocks__/mermaid.js +18 -0
- package/Tests/__mocks__/react-markdown.js +17 -0
- package/Tests/__mocks__/react-syntax-highlighter.js +19 -0
- package/Tests/__mocks__/remark-gfm.js +8 -0
- package/Types/Icon/IconProp.ts +1 -0
- package/Types/Monitor/DockerAlertTemplates.ts +507 -0
- package/Types/Monitor/DockerMetricCatalog.ts +226 -0
- package/Types/Monitor/MonitorStep.ts +33 -0
- package/Types/Monitor/MonitorStepDockerMonitor.ts +38 -0
- package/Types/Monitor/MonitorType.ts +15 -1
- package/Types/Permission.ts +38 -0
- package/UI/Components/Icon/Icon.tsx +87 -0
- package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +7 -132
- package/UI/Components/ModelDetail/CardModelDetail.tsx +11 -1
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +285 -0
- package/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.tsx +85 -0
- package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +156 -0
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSection.tsx +160 -0
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +85 -0
- package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +102 -0
- package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +280 -0
- package/UI/Components/TelemetryViewer/components/TelemetryHistogramTooltip.tsx +125 -0
- package/UI/Components/TelemetryViewer/components/TelemetryPagination.tsx +114 -0
- package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +378 -0
- package/UI/Components/TelemetryViewer/components/TelemetrySearchHelp.tsx +78 -0
- package/UI/Components/TelemetryViewer/components/TelemetrySearchSuggestions.tsx +64 -0
- package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +193 -0
- package/UI/Components/TelemetryViewer/types.ts +67 -0
- package/build/dist/Models/DatabaseModels/DockerHost.js +686 -0
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +117 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +237 -16
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js +9 -0
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1774000000002-MigrationName.js +35 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1774000000002-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1775766676723-MigrationName.js +52 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1775766676723-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1775900000000-AddGlobalSmtpOAuth.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1775900000000-AddGlobalSmtpOAuth.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +162 -0
- package/build/dist/Server/Services/DockerHostService.js.map +1 -0
- package/build/dist/Server/Services/ExceptionAggregationService.js +224 -0
- package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -0
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +11 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +28 -14
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +19 -17
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +364 -0
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +46 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Tests/Server/Services/LogAggregationService.test.js +2 -2
- package/build/dist/Tests/Server/Services/LogAggregationService.test.js.map +1 -1
- package/build/dist/Types/Icon/IconProp.js +1 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/Types/Monitor/DockerAlertTemplates.js +410 -0
- package/build/dist/Types/Monitor/DockerAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/DockerMetricCatalog.js +192 -0
- package/build/dist/Types/Monitor/DockerMetricCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStep.js +23 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDockerMonitor.js +21 -0
- package/build/dist/Types/Monitor/MonitorStepDockerMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorType.js +14 -1
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Permission.js +36 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +13 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +7 -75
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +8 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +71 -0
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js +39 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryActiveFilterChips.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +61 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js +66 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSection.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +41 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +35 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +132 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogramTooltip.js +65 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogramTooltip.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js +52 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +224 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchHelp.js +35 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchHelp.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchSuggestions.js +27 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchSuggestions.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +97 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/types.js +6 -0
- package/build/dist/UI/Components/TelemetryViewer/types.js.map +1 -0
- package/jest.config.json +6 -1
- package/package.json +1 -1
|
@@ -10,6 +10,8 @@ import TableColumn from "../../Types/Database/TableColumn";
|
|
|
10
10
|
import TableColumnType from "../../Types/Database/TableColumnType";
|
|
11
11
|
import TableMetadata from "../../Types/Database/TableMetadata";
|
|
12
12
|
import Email from "../../Types/Email";
|
|
13
|
+
import OAuthProviderType from "../../Types/Email/OAuthProviderType";
|
|
14
|
+
import SMTPAuthenticationType from "../../Types/Email/SMTPAuthenticationType";
|
|
13
15
|
import IconProp from "../../Types/Icon/IconProp";
|
|
14
16
|
import ObjectID from "../../Types/ObjectID";
|
|
15
17
|
import Phone from "../../Types/Phone";
|
|
@@ -206,6 +208,116 @@ export default class GlobalConfig extends GlobalConfigModel {
|
|
|
206
208
|
})
|
|
207
209
|
public smtpFromName?: string = undefined;
|
|
208
210
|
|
|
211
|
+
// SMTP OAuth 2.0 Settings.
|
|
212
|
+
|
|
213
|
+
@ColumnAccessControl({
|
|
214
|
+
create: [],
|
|
215
|
+
read: [],
|
|
216
|
+
update: [],
|
|
217
|
+
})
|
|
218
|
+
@TableColumn({
|
|
219
|
+
type: TableColumnType.ShortText,
|
|
220
|
+
title: "SMTP Authentication Type",
|
|
221
|
+
description:
|
|
222
|
+
"The type of authentication to use for this SMTP server. Options: Username and Password, OAuth, or None.",
|
|
223
|
+
defaultValue: SMTPAuthenticationType.UsernamePassword,
|
|
224
|
+
})
|
|
225
|
+
@Column({
|
|
226
|
+
type: ColumnType.ShortText,
|
|
227
|
+
length: ColumnLength.ShortText,
|
|
228
|
+
nullable: true,
|
|
229
|
+
default: SMTPAuthenticationType.UsernamePassword,
|
|
230
|
+
})
|
|
231
|
+
public smtpAuthType?: SMTPAuthenticationType = undefined;
|
|
232
|
+
|
|
233
|
+
@ColumnAccessControl({
|
|
234
|
+
create: [],
|
|
235
|
+
read: [],
|
|
236
|
+
update: [],
|
|
237
|
+
})
|
|
238
|
+
@TableColumn({
|
|
239
|
+
type: TableColumnType.ShortText,
|
|
240
|
+
title: "SMTP OAuth Client ID",
|
|
241
|
+
description:
|
|
242
|
+
"The Client ID from your OAuth application registration. Required for OAuth authentication.",
|
|
243
|
+
})
|
|
244
|
+
@Column({
|
|
245
|
+
type: ColumnType.ShortText,
|
|
246
|
+
length: ColumnLength.ShortText,
|
|
247
|
+
nullable: true,
|
|
248
|
+
})
|
|
249
|
+
public smtpClientId?: string = undefined;
|
|
250
|
+
|
|
251
|
+
@ColumnAccessControl({
|
|
252
|
+
create: [],
|
|
253
|
+
read: [],
|
|
254
|
+
update: [],
|
|
255
|
+
})
|
|
256
|
+
@TableColumn({
|
|
257
|
+
type: TableColumnType.VeryLongText,
|
|
258
|
+
title: "SMTP OAuth Client Secret",
|
|
259
|
+
description:
|
|
260
|
+
"The Client Secret from your OAuth application registration. Required for OAuth authentication. For Google service accounts, this is the private key from the JSON key file.",
|
|
261
|
+
})
|
|
262
|
+
@Column({
|
|
263
|
+
type: ColumnType.VeryLongText,
|
|
264
|
+
nullable: true,
|
|
265
|
+
})
|
|
266
|
+
public smtpClientSecret?: string = undefined;
|
|
267
|
+
|
|
268
|
+
@ColumnAccessControl({
|
|
269
|
+
create: [],
|
|
270
|
+
read: [],
|
|
271
|
+
update: [],
|
|
272
|
+
})
|
|
273
|
+
@TableColumn({
|
|
274
|
+
type: TableColumnType.LongURL,
|
|
275
|
+
title: "SMTP OAuth Token URL",
|
|
276
|
+
description:
|
|
277
|
+
"The OAuth token endpoint URL. For Microsoft 365: https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token. For Google: https://oauth2.googleapis.com/token",
|
|
278
|
+
})
|
|
279
|
+
@Column({
|
|
280
|
+
type: ColumnType.LongURL,
|
|
281
|
+
nullable: true,
|
|
282
|
+
})
|
|
283
|
+
public smtpTokenUrl?: string = undefined;
|
|
284
|
+
|
|
285
|
+
@ColumnAccessControl({
|
|
286
|
+
create: [],
|
|
287
|
+
read: [],
|
|
288
|
+
update: [],
|
|
289
|
+
})
|
|
290
|
+
@TableColumn({
|
|
291
|
+
type: TableColumnType.LongText,
|
|
292
|
+
title: "SMTP OAuth Scope",
|
|
293
|
+
description:
|
|
294
|
+
"The OAuth scope(s) required for SMTP access. For Microsoft 365: https://outlook.office365.com/.default. For Google: https://mail.google.com/",
|
|
295
|
+
})
|
|
296
|
+
@Column({
|
|
297
|
+
type: ColumnType.LongText,
|
|
298
|
+
length: ColumnLength.LongText,
|
|
299
|
+
nullable: true,
|
|
300
|
+
})
|
|
301
|
+
public smtpScope?: string = undefined;
|
|
302
|
+
|
|
303
|
+
@ColumnAccessControl({
|
|
304
|
+
create: [],
|
|
305
|
+
read: [],
|
|
306
|
+
update: [],
|
|
307
|
+
})
|
|
308
|
+
@TableColumn({
|
|
309
|
+
type: TableColumnType.ShortText,
|
|
310
|
+
title: "SMTP OAuth Provider Type",
|
|
311
|
+
description:
|
|
312
|
+
"The OAuth grant type to use. 'Client Credentials' for Microsoft 365 and most providers. 'JWT Bearer' for Google Workspace service accounts.",
|
|
313
|
+
})
|
|
314
|
+
@Column({
|
|
315
|
+
type: ColumnType.ShortText,
|
|
316
|
+
length: ColumnLength.ShortText,
|
|
317
|
+
nullable: true,
|
|
318
|
+
})
|
|
319
|
+
public smtpOAuthProviderType?: OAuthProviderType = undefined;
|
|
320
|
+
|
|
209
321
|
// Twilio config.
|
|
210
322
|
|
|
211
323
|
@ColumnAccessControl({
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import AcmeCertificate from "./AcmeCertificate";
|
|
2
2
|
import AcmeChallenge from "./AcmeChallenge";
|
|
3
3
|
import KubernetesCluster from "./KubernetesCluster";
|
|
4
|
+
import DockerHost from "./DockerHost";
|
|
4
5
|
// API Keys
|
|
5
6
|
import ApiKey from "./ApiKey";
|
|
6
7
|
import ApiKeyPermission from "./ApiKeyPermission";
|
|
@@ -506,6 +507,7 @@ const AllModelTypes: Array<{
|
|
|
506
507
|
StatusPageSCIMLog,
|
|
507
508
|
|
|
508
509
|
KubernetesCluster,
|
|
510
|
+
DockerHost,
|
|
509
511
|
];
|
|
510
512
|
|
|
511
513
|
const modelTypeMap: { [key: string]: { new (): BaseModel } } = {};
|
|
@@ -23,6 +23,16 @@ import LogAggregationService, {
|
|
|
23
23
|
AnalyticsTopItem,
|
|
24
24
|
AnalyticsTableRow,
|
|
25
25
|
} from "../Services/LogAggregationService";
|
|
26
|
+
import TraceAggregationService, {
|
|
27
|
+
HistogramBucket as TraceHistogramBucket,
|
|
28
|
+
HistogramRequest as TraceHistogramRequest,
|
|
29
|
+
FacetValue as TraceFacetValue,
|
|
30
|
+
MultiFacetRequest as TraceMultiFacetRequest,
|
|
31
|
+
} from "../Services/TraceAggregationService";
|
|
32
|
+
import ExceptionAggregationService, {
|
|
33
|
+
HistogramBucket as ExceptionHistogramBucket,
|
|
34
|
+
HistogramRequest as ExceptionHistogramRequest,
|
|
35
|
+
} from "../Services/ExceptionAggregationService";
|
|
26
36
|
import ProfileAggregationService, {
|
|
27
37
|
FlamegraphRequest,
|
|
28
38
|
FunctionListRequest,
|
|
@@ -349,24 +359,259 @@ router.post(
|
|
|
349
359
|
? (body["attributes"] as Record<string, string>)
|
|
350
360
|
: undefined;
|
|
351
361
|
|
|
352
|
-
|
|
362
|
+
/*
|
|
363
|
+
* Capture tenantId locally so TypeScript narrowing survives the
|
|
364
|
+
* async closure below (narrowing is lost across closure boundaries).
|
|
365
|
+
*/
|
|
366
|
+
const projectId: ObjectID = databaseProps.tenantId;
|
|
367
|
+
|
|
368
|
+
/*
|
|
369
|
+
* Run facet queries in parallel so a slow individual facet can't
|
|
370
|
+
* starve the endpoint. Per-facet errors degrade gracefully to [].
|
|
371
|
+
*/
|
|
372
|
+
const facetResults: Array<readonly [string, Array<FacetValue>]> =
|
|
373
|
+
await Promise.all(
|
|
374
|
+
facetKeys.map(
|
|
375
|
+
async (
|
|
376
|
+
facetKey: string,
|
|
377
|
+
): Promise<readonly [string, Array<FacetValue>]> => {
|
|
378
|
+
try {
|
|
379
|
+
const request: FacetRequest = {
|
|
380
|
+
projectId,
|
|
381
|
+
startTime,
|
|
382
|
+
endTime,
|
|
383
|
+
facetKey,
|
|
384
|
+
limit,
|
|
385
|
+
serviceIds,
|
|
386
|
+
severityTexts,
|
|
387
|
+
bodySearchText,
|
|
388
|
+
traceIds,
|
|
389
|
+
spanIds,
|
|
390
|
+
attributes,
|
|
391
|
+
};
|
|
392
|
+
const values: Array<FacetValue> =
|
|
393
|
+
await LogAggregationService.getFacetValues(request);
|
|
394
|
+
return [facetKey, values] as const;
|
|
395
|
+
} catch {
|
|
396
|
+
return [facetKey, [] as Array<FacetValue>] as const;
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
),
|
|
400
|
+
);
|
|
353
401
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
402
|
+
const facets: Record<string, Array<FacetValue>> = Object.fromEntries(
|
|
403
|
+
facetResults,
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
return Response.sendJsonObjectResponse(req, res, {
|
|
407
|
+
facets: facets as unknown as JSONObject,
|
|
408
|
+
});
|
|
409
|
+
} catch (err: unknown) {
|
|
410
|
+
next(err);
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
// --- Trace Histogram Endpoint ---
|
|
416
|
+
|
|
417
|
+
router.post(
|
|
418
|
+
"/telemetry/traces/histogram",
|
|
419
|
+
UserMiddleware.getUserMiddleware,
|
|
420
|
+
async (
|
|
421
|
+
req: ExpressRequest,
|
|
422
|
+
res: ExpressResponse,
|
|
423
|
+
next: NextFunction,
|
|
424
|
+
): Promise<void> => {
|
|
425
|
+
try {
|
|
426
|
+
const databaseProps: DatabaseCommonInteractionProps =
|
|
427
|
+
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
428
|
+
|
|
429
|
+
if (!databaseProps?.tenantId) {
|
|
430
|
+
return Response.sendErrorResponse(
|
|
431
|
+
req,
|
|
432
|
+
res,
|
|
433
|
+
new BadDataException("Invalid Project ID"),
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const body: JSONObject = req.body as JSONObject;
|
|
438
|
+
|
|
439
|
+
const startTime: Date = body["startTime"]
|
|
440
|
+
? OneUptimeDate.fromString(body["startTime"] as string)
|
|
441
|
+
: OneUptimeDate.addRemoveHours(OneUptimeDate.getCurrentDate(), -1);
|
|
442
|
+
|
|
443
|
+
const endTime: Date = body["endTime"]
|
|
444
|
+
? OneUptimeDate.fromString(body["endTime"] as string)
|
|
445
|
+
: OneUptimeDate.getCurrentDate();
|
|
446
|
+
|
|
447
|
+
const bucketSizeInMinutes: number =
|
|
448
|
+
(body["bucketSizeInMinutes"] as number) ||
|
|
449
|
+
computeDefaultBucketSize(startTime, endTime);
|
|
450
|
+
|
|
451
|
+
const serviceIds: Array<ObjectID> | undefined = body["serviceIds"]
|
|
452
|
+
? (body["serviceIds"] as Array<string>).map((id: string) => {
|
|
453
|
+
return new ObjectID(id);
|
|
454
|
+
})
|
|
455
|
+
: undefined;
|
|
456
|
+
|
|
457
|
+
const statusCodes: Array<number> | undefined = body["statusCodes"]
|
|
458
|
+
? (body["statusCodes"] as Array<number>)
|
|
459
|
+
: undefined;
|
|
460
|
+
|
|
461
|
+
const spanKinds: Array<string> | undefined = body["spanKinds"]
|
|
462
|
+
? (body["spanKinds"] as Array<string>)
|
|
463
|
+
: undefined;
|
|
464
|
+
|
|
465
|
+
const spanNames: Array<string> | undefined = body["spanNames"]
|
|
466
|
+
? (body["spanNames"] as Array<string>)
|
|
467
|
+
: undefined;
|
|
468
|
+
|
|
469
|
+
const traceIds: Array<string> | undefined = body["traceIds"]
|
|
470
|
+
? (body["traceIds"] as Array<string>)
|
|
471
|
+
: undefined;
|
|
472
|
+
|
|
473
|
+
const nameSearchText: string | undefined = body["nameSearchText"]
|
|
474
|
+
? (body["nameSearchText"] as string)
|
|
475
|
+
: undefined;
|
|
476
|
+
|
|
477
|
+
const rootOnly: boolean | undefined =
|
|
478
|
+
body["rootOnly"] === undefined ? undefined : Boolean(body["rootOnly"]);
|
|
479
|
+
|
|
480
|
+
const attributes: Record<string, string> | undefined = body["attributes"]
|
|
481
|
+
? (body["attributes"] as Record<string, string>)
|
|
482
|
+
: undefined;
|
|
483
|
+
|
|
484
|
+
const request: TraceHistogramRequest = {
|
|
485
|
+
projectId: databaseProps.tenantId,
|
|
486
|
+
startTime,
|
|
487
|
+
endTime,
|
|
488
|
+
bucketSizeInMinutes,
|
|
489
|
+
serviceIds,
|
|
490
|
+
statusCodes,
|
|
491
|
+
spanKinds,
|
|
492
|
+
spanNames,
|
|
493
|
+
traceIds,
|
|
494
|
+
nameSearchText,
|
|
495
|
+
rootOnly,
|
|
496
|
+
attributes,
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
const buckets: Array<TraceHistogramBucket> =
|
|
500
|
+
await TraceAggregationService.getHistogram(request);
|
|
501
|
+
|
|
502
|
+
return Response.sendJsonObjectResponse(req, res, {
|
|
503
|
+
buckets: buckets as unknown as JSONObject,
|
|
504
|
+
});
|
|
505
|
+
} catch (err: unknown) {
|
|
506
|
+
next(err);
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
// --- Trace Facets Endpoint ---
|
|
512
|
+
|
|
513
|
+
router.post(
|
|
514
|
+
"/telemetry/traces/facets",
|
|
515
|
+
UserMiddleware.getUserMiddleware,
|
|
516
|
+
async (
|
|
517
|
+
req: ExpressRequest,
|
|
518
|
+
res: ExpressResponse,
|
|
519
|
+
next: NextFunction,
|
|
520
|
+
): Promise<void> => {
|
|
521
|
+
try {
|
|
522
|
+
const databaseProps: DatabaseCommonInteractionProps =
|
|
523
|
+
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
524
|
+
|
|
525
|
+
if (!databaseProps?.tenantId) {
|
|
526
|
+
return Response.sendErrorResponse(
|
|
527
|
+
req,
|
|
528
|
+
res,
|
|
529
|
+
new BadDataException("Invalid Project ID"),
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const body: JSONObject = req.body as JSONObject;
|
|
534
|
+
|
|
535
|
+
const facetKeys: Array<string> = body["facetKeys"]
|
|
536
|
+
? (body["facetKeys"] as Array<string>)
|
|
537
|
+
: ["serviceId", "statusCode", "kind", "name"];
|
|
538
|
+
|
|
539
|
+
const startTime: Date = body["startTime"]
|
|
540
|
+
? OneUptimeDate.fromString(body["startTime"] as string)
|
|
541
|
+
: OneUptimeDate.addRemoveHours(OneUptimeDate.getCurrentDate(), -1);
|
|
542
|
+
|
|
543
|
+
const endTime: Date = body["endTime"]
|
|
544
|
+
? OneUptimeDate.fromString(body["endTime"] as string)
|
|
545
|
+
: OneUptimeDate.getCurrentDate();
|
|
546
|
+
|
|
547
|
+
const limit: number = (body["limit"] as number) || 500;
|
|
548
|
+
|
|
549
|
+
const serviceIds: Array<ObjectID> | undefined = body["serviceIds"]
|
|
550
|
+
? (body["serviceIds"] as Array<string>).map((id: string) => {
|
|
551
|
+
return new ObjectID(id);
|
|
552
|
+
})
|
|
553
|
+
: undefined;
|
|
554
|
+
|
|
555
|
+
const statusCodes: Array<number> | undefined = body["statusCodes"]
|
|
556
|
+
? (body["statusCodes"] as Array<number>)
|
|
557
|
+
: undefined;
|
|
558
|
+
|
|
559
|
+
const spanKinds: Array<string> | undefined = body["spanKinds"]
|
|
560
|
+
? (body["spanKinds"] as Array<string>)
|
|
561
|
+
: undefined;
|
|
562
|
+
|
|
563
|
+
const spanNames: Array<string> | undefined = body["spanNames"]
|
|
564
|
+
? (body["spanNames"] as Array<string>)
|
|
565
|
+
: undefined;
|
|
566
|
+
|
|
567
|
+
const traceIds: Array<string> | undefined = body["traceIds"]
|
|
568
|
+
? (body["traceIds"] as Array<string>)
|
|
569
|
+
: undefined;
|
|
368
570
|
|
|
369
|
-
|
|
571
|
+
const nameSearchText: string | undefined = body["nameSearchText"]
|
|
572
|
+
? (body["nameSearchText"] as string)
|
|
573
|
+
: undefined;
|
|
574
|
+
|
|
575
|
+
const rootOnly: boolean | undefined =
|
|
576
|
+
body["rootOnly"] === undefined ? undefined : Boolean(body["rootOnly"]);
|
|
577
|
+
|
|
578
|
+
const attributes: Record<string, string> | undefined = body["attributes"]
|
|
579
|
+
? (body["attributes"] as Record<string, string>)
|
|
580
|
+
: undefined;
|
|
581
|
+
|
|
582
|
+
/*
|
|
583
|
+
* Compute all facets from a single sort-key-aligned sample query
|
|
584
|
+
* (ORDER BY startTime DESC LIMIT N) and count top-K in Node. This
|
|
585
|
+
* avoids ClickHouse GROUP BY aggregations that can't return partial
|
|
586
|
+
* results under max_execution_time 'break' mode, and returns in
|
|
587
|
+
* <1s even over 14-day windows.
|
|
588
|
+
*/
|
|
589
|
+
const multiRequest: TraceMultiFacetRequest = {
|
|
590
|
+
projectId: databaseProps.tenantId,
|
|
591
|
+
startTime,
|
|
592
|
+
endTime,
|
|
593
|
+
facetKeys,
|
|
594
|
+
limit,
|
|
595
|
+
serviceIds,
|
|
596
|
+
statusCodes,
|
|
597
|
+
spanKinds,
|
|
598
|
+
spanNames,
|
|
599
|
+
traceIds,
|
|
600
|
+
nameSearchText,
|
|
601
|
+
rootOnly,
|
|
602
|
+
attributes,
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
let facets: Record<string, Array<TraceFacetValue>>;
|
|
606
|
+
try {
|
|
607
|
+
facets =
|
|
608
|
+
await TraceAggregationService.getFacetValuesFromSample(multiRequest);
|
|
609
|
+
} catch {
|
|
610
|
+
facets = Object.fromEntries(
|
|
611
|
+
facetKeys.map((key: string): [string, Array<TraceFacetValue>] => {
|
|
612
|
+
return [key, []];
|
|
613
|
+
}),
|
|
614
|
+
);
|
|
370
615
|
}
|
|
371
616
|
|
|
372
617
|
return Response.sendJsonObjectResponse(req, res, {
|
|
@@ -378,6 +623,97 @@ router.post(
|
|
|
378
623
|
},
|
|
379
624
|
);
|
|
380
625
|
|
|
626
|
+
// --- Exception Histogram Endpoint ---
|
|
627
|
+
|
|
628
|
+
router.post(
|
|
629
|
+
"/telemetry/exceptions/histogram",
|
|
630
|
+
UserMiddleware.getUserMiddleware,
|
|
631
|
+
async (
|
|
632
|
+
req: ExpressRequest,
|
|
633
|
+
res: ExpressResponse,
|
|
634
|
+
next: NextFunction,
|
|
635
|
+
): Promise<void> => {
|
|
636
|
+
try {
|
|
637
|
+
const databaseProps: DatabaseCommonInteractionProps =
|
|
638
|
+
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
639
|
+
|
|
640
|
+
if (!databaseProps?.tenantId) {
|
|
641
|
+
return Response.sendErrorResponse(
|
|
642
|
+
req,
|
|
643
|
+
res,
|
|
644
|
+
new BadDataException("Invalid Project ID"),
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
const body: JSONObject = req.body as JSONObject;
|
|
649
|
+
|
|
650
|
+
const startTime: Date = body["startTime"]
|
|
651
|
+
? OneUptimeDate.fromString(body["startTime"] as string)
|
|
652
|
+
: OneUptimeDate.addRemoveHours(OneUptimeDate.getCurrentDate(), -24);
|
|
653
|
+
|
|
654
|
+
const endTime: Date = body["endTime"]
|
|
655
|
+
? OneUptimeDate.fromString(body["endTime"] as string)
|
|
656
|
+
: OneUptimeDate.getCurrentDate();
|
|
657
|
+
|
|
658
|
+
const bucketSizeInMinutes: number =
|
|
659
|
+
(body["bucketSizeInMinutes"] as number) ||
|
|
660
|
+
computeDefaultBucketSize(startTime, endTime);
|
|
661
|
+
|
|
662
|
+
const serviceIds: Array<ObjectID> | undefined = body["serviceIds"]
|
|
663
|
+
? (body["serviceIds"] as Array<string>).map((id: string) => {
|
|
664
|
+
return new ObjectID(id);
|
|
665
|
+
})
|
|
666
|
+
: undefined;
|
|
667
|
+
|
|
668
|
+
const exceptionTypes: Array<string> | undefined = body["exceptionTypes"]
|
|
669
|
+
? (body["exceptionTypes"] as Array<string>)
|
|
670
|
+
: undefined;
|
|
671
|
+
|
|
672
|
+
const environments: Array<string> | undefined = body["environments"]
|
|
673
|
+
? (body["environments"] as Array<string>)
|
|
674
|
+
: undefined;
|
|
675
|
+
|
|
676
|
+
const fingerprints: Array<string> | undefined = body["fingerprints"]
|
|
677
|
+
? (body["fingerprints"] as Array<string>)
|
|
678
|
+
: undefined;
|
|
679
|
+
|
|
680
|
+
const traceIds: Array<string> | undefined = body["traceIds"]
|
|
681
|
+
? (body["traceIds"] as Array<string>)
|
|
682
|
+
: undefined;
|
|
683
|
+
|
|
684
|
+
const escaped: boolean | undefined =
|
|
685
|
+
body["escaped"] === undefined ? undefined : Boolean(body["escaped"]);
|
|
686
|
+
|
|
687
|
+
const messageSearchText: string | undefined = body["messageSearchText"]
|
|
688
|
+
? (body["messageSearchText"] as string)
|
|
689
|
+
: undefined;
|
|
690
|
+
|
|
691
|
+
const request: ExceptionHistogramRequest = {
|
|
692
|
+
projectId: databaseProps.tenantId,
|
|
693
|
+
startTime,
|
|
694
|
+
endTime,
|
|
695
|
+
bucketSizeInMinutes,
|
|
696
|
+
serviceIds,
|
|
697
|
+
exceptionTypes,
|
|
698
|
+
environments,
|
|
699
|
+
fingerprints,
|
|
700
|
+
traceIds,
|
|
701
|
+
escaped,
|
|
702
|
+
messageSearchText,
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
const buckets: Array<ExceptionHistogramBucket> =
|
|
706
|
+
await ExceptionAggregationService.getHistogram(request);
|
|
707
|
+
|
|
708
|
+
return Response.sendJsonObjectResponse(req, res, {
|
|
709
|
+
buckets: buckets as unknown as JSONObject,
|
|
710
|
+
});
|
|
711
|
+
} catch (err: unknown) {
|
|
712
|
+
next(err);
|
|
713
|
+
}
|
|
714
|
+
},
|
|
715
|
+
);
|
|
716
|
+
|
|
381
717
|
// --- Log Analytics Endpoint ---
|
|
382
718
|
|
|
383
719
|
router.post(
|
|
@@ -26,6 +26,15 @@ const options: ClickHouseClientConfigOptions = {
|
|
|
26
26
|
password: ClickhousePassword,
|
|
27
27
|
database: ClickhouseDatabase,
|
|
28
28
|
application: "oneuptime",
|
|
29
|
+
/*
|
|
30
|
+
* The default @clickhouse/client request_timeout is 30s which is too
|
|
31
|
+
* short for aggregation queries over wide time ranges on large span /
|
|
32
|
+
* log tables. Cap it just under nginx's 60s proxy_read_timeout so that
|
|
33
|
+
* (a) a slow query still has headroom and (b) nginx never hits its
|
|
34
|
+
* upstream timeout first. Per-query SETTINGS max_execution_time on
|
|
35
|
+
* aggregation statements provides the hard server-side cap.
|
|
36
|
+
*/
|
|
37
|
+
request_timeout: 58_000,
|
|
29
38
|
};
|
|
30
39
|
|
|
31
40
|
if (ShouldClickhouseSslEnable && ClickhouseTlsCa) {
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class MigrationName1774000000002 implements MigrationInterface {
|
|
4
|
+
public name = "MigrationName1774000000002";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(
|
|
8
|
+
`CREATE TABLE "DockerHost" ("_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(100) NOT NULL, "slug" character varying(100) NOT NULL, "description" character varying(500), "hostIdentifier" character varying(100) NOT NULL, "otelCollectorStatus" character varying(100) DEFAULT 'disconnected', "lastSeenAt" TIMESTAMP WITH TIME ZONE, "containersRunning" integer DEFAULT '0', "containersStopped" integer DEFAULT '0', "containersPaused" integer DEFAULT '0', "osType" character varying(100), "osVersion" character varying(100), "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_docker_host_id" PRIMARY KEY ("_id"))`,
|
|
9
|
+
);
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`CREATE INDEX "IDX_docker_host_projectId" ON "DockerHost" ("projectId")`,
|
|
12
|
+
);
|
|
13
|
+
await queryRunner.query(
|
|
14
|
+
`CREATE INDEX "IDX_docker_host_hostIdentifier" ON "DockerHost" ("hostIdentifier")`,
|
|
15
|
+
);
|
|
16
|
+
await queryRunner.query(
|
|
17
|
+
`CREATE UNIQUE INDEX "IDX_docker_host_slug" ON "DockerHost" ("slug")`,
|
|
18
|
+
);
|
|
19
|
+
await queryRunner.query(
|
|
20
|
+
`ALTER TABLE "DockerHost" ADD CONSTRAINT "FK_docker_host_projectId" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
21
|
+
);
|
|
22
|
+
await queryRunner.query(
|
|
23
|
+
`ALTER TABLE "DockerHost" ADD CONSTRAINT "FK_docker_host_createdByUserId" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
24
|
+
);
|
|
25
|
+
await queryRunner.query(
|
|
26
|
+
`ALTER TABLE "DockerHost" ADD CONSTRAINT "FK_docker_host_deletedByUserId" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
27
|
+
);
|
|
28
|
+
// Label join table
|
|
29
|
+
await queryRunner.query(
|
|
30
|
+
`CREATE TABLE "DockerHostLabel" ("dockerHostId" uuid NOT NULL, "labelId" uuid NOT NULL, CONSTRAINT "PK_docker_host_label" PRIMARY KEY ("dockerHostId", "labelId"))`,
|
|
31
|
+
);
|
|
32
|
+
await queryRunner.query(
|
|
33
|
+
`CREATE INDEX "IDX_docker_host_label_dockerHostId" ON "DockerHostLabel" ("dockerHostId")`,
|
|
34
|
+
);
|
|
35
|
+
await queryRunner.query(
|
|
36
|
+
`CREATE INDEX "IDX_docker_host_label_labelId" ON "DockerHostLabel" ("labelId")`,
|
|
37
|
+
);
|
|
38
|
+
await queryRunner.query(
|
|
39
|
+
`ALTER TABLE "DockerHostLabel" ADD CONSTRAINT "FK_docker_host_label_dockerHostId" FOREIGN KEY ("dockerHostId") REFERENCES "DockerHost"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
|
|
40
|
+
);
|
|
41
|
+
await queryRunner.query(
|
|
42
|
+
`ALTER TABLE "DockerHostLabel" ADD CONSTRAINT "FK_docker_host_label_labelId" FOREIGN KEY ("labelId") REFERENCES "Label"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
47
|
+
await queryRunner.query(
|
|
48
|
+
`ALTER TABLE "DockerHostLabel" DROP CONSTRAINT "FK_docker_host_label_labelId"`,
|
|
49
|
+
);
|
|
50
|
+
await queryRunner.query(
|
|
51
|
+
`ALTER TABLE "DockerHostLabel" DROP CONSTRAINT "FK_docker_host_label_dockerHostId"`,
|
|
52
|
+
);
|
|
53
|
+
await queryRunner.query(
|
|
54
|
+
`DROP INDEX "public"."IDX_docker_host_label_labelId"`,
|
|
55
|
+
);
|
|
56
|
+
await queryRunner.query(
|
|
57
|
+
`DROP INDEX "public"."IDX_docker_host_label_dockerHostId"`,
|
|
58
|
+
);
|
|
59
|
+
await queryRunner.query(`DROP TABLE "DockerHostLabel"`);
|
|
60
|
+
await queryRunner.query(
|
|
61
|
+
`ALTER TABLE "DockerHost" DROP CONSTRAINT "FK_docker_host_deletedByUserId"`,
|
|
62
|
+
);
|
|
63
|
+
await queryRunner.query(
|
|
64
|
+
`ALTER TABLE "DockerHost" DROP CONSTRAINT "FK_docker_host_createdByUserId"`,
|
|
65
|
+
);
|
|
66
|
+
await queryRunner.query(
|
|
67
|
+
`ALTER TABLE "DockerHost" DROP CONSTRAINT "FK_docker_host_projectId"`,
|
|
68
|
+
);
|
|
69
|
+
await queryRunner.query(`DROP INDEX "public"."IDX_docker_host_slug"`);
|
|
70
|
+
await queryRunner.query(
|
|
71
|
+
`DROP INDEX "public"."IDX_docker_host_hostIdentifier"`,
|
|
72
|
+
);
|
|
73
|
+
await queryRunner.query(`DROP INDEX "public"."IDX_docker_host_projectId"`);
|
|
74
|
+
await queryRunner.query(`DROP TABLE "DockerHost"`);
|
|
75
|
+
}
|
|
76
|
+
}
|