@oneuptime/common 10.4.9 → 10.4.11
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 +47 -1
- package/Models/AnalyticsModels/Log.ts +47 -1
- package/Models/AnalyticsModels/Metric.ts +1 -7
- package/Models/AnalyticsModels/Profile.ts +47 -1
- package/Models/AnalyticsModels/ProfileSample.ts +47 -1
- package/Models/AnalyticsModels/Span.ts +47 -1
- package/Models/DatabaseModels/DockerHost.ts +83 -0
- package/Models/DatabaseModels/Host.ts +83 -0
- package/Models/DatabaseModels/Index.ts +0 -2
- package/Models/DatabaseModels/KubernetesCluster.ts +83 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1779199346010-AddTelemetryRetentionConfig.ts +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1779277271302-DropServiceDependencyTable.ts +44 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1779282769946-AddTelemetryRetentionToHostDockerKubernetes.ts +50 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Services/AlertService.ts +2 -4
- package/Server/Services/IncidentService.ts +2 -4
- package/Server/Services/Index.ts +0 -2
- package/Server/Services/LogAggregationService.ts +54 -6
- package/Server/Services/OpenTelemetryIngestService.ts +132 -0
- package/Server/Services/TraceAggregationService.ts +83 -8
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +2 -4
- package/Server/Utils/Telemetry/Telemetry.ts +38 -0
- package/Tests/Server/Middleware/UserAuthorization.test.ts +5 -0
- package/Types/Permission.ts +0 -46
- package/Types/Telemetry/ServiceType.ts +19 -0
- package/Types/Time/RangeStartAndEndDateTime.ts +8 -0
- package/Types/Time/TimeRange.ts +1 -0
- package/UI/Components/Forms/Validation.ts +2 -2
- package/UI/Components/LogsViewer/LogsViewer.tsx +135 -17
- package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +1 -0
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +84 -1
- package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +0 -1
- package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +1 -0
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +41 -1
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Log.js +41 -1
- package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Metric.js +0 -7
- package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Profile.js +41 -1
- package/build/dist/Models/AnalyticsModels/Profile.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ProfileSample.js +41 -1
- package/build/dist/Models/AnalyticsModels/ProfileSample.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Span.js +41 -1
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js +84 -0
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Host.js +84 -0
- package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +0 -2
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +84 -0
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779199346010-AddTelemetryRetentionConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779277271302-DropServiceDependencyTable.js +42 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779277271302-DropServiceDependencyTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779282769946-AddTelemetryRetentionToHostDockerKubernetes.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779282769946-AddTelemetryRetentionToHostDockerKubernetes.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +2 -1
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +2 -1
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +0 -2
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +46 -4
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +103 -0
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +66 -6
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +2 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +26 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js +3 -0
- package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js.map +1 -1
- package/build/dist/Types/Permission.js +0 -40
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Telemetry/ServiceType.js +20 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -0
- package/build/dist/Types/Time/RangeStartAndEndDateTime.js +4 -0
- package/build/dist/Types/Time/RangeStartAndEndDateTime.js.map +1 -1
- package/build/dist/Types/Time/TimeRange.js +1 -0
- package/build/dist/Types/Time/TimeRange.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +2 -2
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +106 -16
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +1 -0
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +67 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
- package/package.json +1 -1
- package/Models/DatabaseModels/ServiceDependency.ts +0 -529
- package/Server/Services/ServiceDependencyService.ts +0 -48
- package/UI/Components/Graphs/ServiceDependencyGraph.tsx +0 -286
- package/build/dist/Models/DatabaseModels/ServiceDependency.js +0 -545
- package/build/dist/Models/DatabaseModels/ServiceDependency.js.map +0 -1
- package/build/dist/Server/Services/ServiceDependencyService.js +0 -47
- package/build/dist/Server/Services/ServiceDependencyService.js.map +0 -1
- package/build/dist/UI/Components/Graphs/ServiceDependencyGraph.js +0 -206
- package/build/dist/UI/Components/Graphs/ServiceDependencyGraph.js.map +0 -1
|
@@ -5,10 +5,8 @@ import MetricService from "../../Services/MetricService";
|
|
|
5
5
|
import GlobalConfigService from "../../Services/GlobalConfigService";
|
|
6
6
|
import GlobalConfig from "../../../Models/DatabaseModels/GlobalConfig";
|
|
7
7
|
import DataToProcess from "./DataToProcess";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
ServiceType,
|
|
11
|
-
} from "../../../Models/AnalyticsModels/Metric";
|
|
8
|
+
import { MetricPointType } from "../../../Models/AnalyticsModels/Metric";
|
|
9
|
+
import ServiceType from "../../../Types/Telemetry/ServiceType";
|
|
12
10
|
import MetricType from "../../../Models/DatabaseModels/MetricType";
|
|
13
11
|
import BasicInfrastructureMetrics, {
|
|
14
12
|
NetworkInterfaceMetrics,
|
|
@@ -135,6 +135,44 @@ export default class TelemetryUtil {
|
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
/*
|
|
139
|
+
* Cross-cutting resource stamps. Spread alongside the service stamp on
|
|
140
|
+
* every analytics row so a single ClickHouse query can find "all
|
|
141
|
+
* telemetry from host X" / "from docker host Y" / "from cluster Z"
|
|
142
|
+
* regardless of which Service the row primarily belongs to. Without
|
|
143
|
+
* these, host context would only be queryable as the raw OTel
|
|
144
|
+
* `resource.host.name` string with no stable id link.
|
|
145
|
+
*/
|
|
146
|
+
public static getAttributesForHostIdAndHostName(data: {
|
|
147
|
+
hostId: ObjectID;
|
|
148
|
+
hostName: string;
|
|
149
|
+
}): Dictionary<AttributeType> {
|
|
150
|
+
return {
|
|
151
|
+
"oneuptime.host.id": data.hostId.toString(),
|
|
152
|
+
"oneuptime.host.name": data.hostName,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public static getAttributesForDockerHostIdAndHostName(data: {
|
|
157
|
+
dockerHostId: ObjectID;
|
|
158
|
+
hostName: string;
|
|
159
|
+
}): Dictionary<AttributeType> {
|
|
160
|
+
return {
|
|
161
|
+
"oneuptime.docker.host.id": data.dockerHostId.toString(),
|
|
162
|
+
"oneuptime.docker.host.name": data.hostName,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public static getAttributesForKubernetesClusterIdAndName(data: {
|
|
167
|
+
kubernetesClusterId: ObjectID;
|
|
168
|
+
clusterName: string;
|
|
169
|
+
}): Dictionary<AttributeType> {
|
|
170
|
+
return {
|
|
171
|
+
"oneuptime.kubernetes.cluster.id": data.kubernetesClusterId.toString(),
|
|
172
|
+
"oneuptime.kubernetes.cluster.name": data.clusterName,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
138
176
|
@CaptureSpan()
|
|
139
177
|
public static getAttributes(data: {
|
|
140
178
|
prefixKeysWithString: string;
|
|
@@ -2,6 +2,7 @@ import ProjectMiddleware from "../../../Server/Middleware/ProjectAuthorization";
|
|
|
2
2
|
import UserMiddleware from "../../../Server/Middleware/UserAuthorization";
|
|
3
3
|
import AccessTokenService from "../../../Server/Services/AccessTokenService";
|
|
4
4
|
import ProjectService from "../../../Server/Services/ProjectService";
|
|
5
|
+
import TeamMemberService from "../../../Server/Services/TeamMemberService";
|
|
5
6
|
import UserService from "../../../Server/Services/UserService";
|
|
6
7
|
import {
|
|
7
8
|
ExpressRequest,
|
|
@@ -44,6 +45,7 @@ jest.mock("../../../Server/Services/UserService");
|
|
|
44
45
|
jest.mock("../../../Server/Services/AccessTokenService");
|
|
45
46
|
jest.mock("../../../Server/Utils/Response");
|
|
46
47
|
jest.mock("../../../Server/Services/ProjectService");
|
|
48
|
+
jest.mock("../../../Server/Services/TeamMemberService");
|
|
47
49
|
jest.mock("../../../Types/HashedString");
|
|
48
50
|
jest.mock("../../../Types/JSONFunctions");
|
|
49
51
|
|
|
@@ -290,6 +292,9 @@ describe("UserMiddleware", () => {
|
|
|
290
292
|
).mockReturnValue(mockedAccessToken);
|
|
291
293
|
getJestSpyOn(JSONWebToken, "decode").mockReturnValue(jwtTokenData);
|
|
292
294
|
getJestSpyOn(HashedString, "hashValue").mockResolvedValue(hashValue);
|
|
295
|
+
getJestSpyOn(TeamMemberService, "getTeamIdsForUser").mockResolvedValue(
|
|
296
|
+
[],
|
|
297
|
+
);
|
|
293
298
|
});
|
|
294
299
|
|
|
295
300
|
beforeEach(() => {
|
package/Types/Permission.ts
CHANGED
|
@@ -1124,11 +1124,6 @@ enum Permission {
|
|
|
1124
1124
|
EditService = "EditService",
|
|
1125
1125
|
ReadService = "ReadService",
|
|
1126
1126
|
|
|
1127
|
-
CreateServiceDependency = "CreateServiceDependency",
|
|
1128
|
-
DeleteServiceDependency = "DeleteServiceDependency",
|
|
1129
|
-
EditServiceDependency = "EditServiceDependency",
|
|
1130
|
-
ReadServiceDependency = "ReadServiceDependency",
|
|
1131
|
-
|
|
1132
1127
|
CreateServiceMonitor = "CreateServiceMonitor",
|
|
1133
1128
|
DeleteServiceMonitor = "DeleteServiceMonitor",
|
|
1134
1129
|
EditServiceMonitor = "EditServiceMonitor",
|
|
@@ -7528,47 +7523,6 @@ export class PermissionHelper {
|
|
|
7528
7523
|
group: PermissionGroup.ServiceCatalog,
|
|
7529
7524
|
},
|
|
7530
7525
|
|
|
7531
|
-
{
|
|
7532
|
-
permission: Permission.CreateServiceDependency,
|
|
7533
|
-
title: "Create Service Dependency",
|
|
7534
|
-
description:
|
|
7535
|
-
"This permission can create Service Dependencies in this project.",
|
|
7536
|
-
isAssignableToTenant: true,
|
|
7537
|
-
isAccessControlPermission: false,
|
|
7538
|
-
isRolePermission: false,
|
|
7539
|
-
group: PermissionGroup.ServiceCatalog,
|
|
7540
|
-
},
|
|
7541
|
-
{
|
|
7542
|
-
permission: Permission.DeleteServiceDependency,
|
|
7543
|
-
title: "Delete Service Dependency",
|
|
7544
|
-
description:
|
|
7545
|
-
"This permission can delete Service Dependencies of this project.",
|
|
7546
|
-
isAssignableToTenant: true,
|
|
7547
|
-
isAccessControlPermission: false,
|
|
7548
|
-
isRolePermission: false,
|
|
7549
|
-
group: PermissionGroup.ServiceCatalog,
|
|
7550
|
-
},
|
|
7551
|
-
{
|
|
7552
|
-
permission: Permission.EditServiceDependency,
|
|
7553
|
-
title: "Edit Service Dependency",
|
|
7554
|
-
description:
|
|
7555
|
-
"This permission can edit Service Dependencies of this project.",
|
|
7556
|
-
isAssignableToTenant: true,
|
|
7557
|
-
isAccessControlPermission: false,
|
|
7558
|
-
isRolePermission: false,
|
|
7559
|
-
group: PermissionGroup.ServiceCatalog,
|
|
7560
|
-
},
|
|
7561
|
-
{
|
|
7562
|
-
permission: Permission.ReadServiceDependency,
|
|
7563
|
-
title: "Read Service Dependency",
|
|
7564
|
-
description:
|
|
7565
|
-
"This permission can read Service Dependencies of this project.",
|
|
7566
|
-
isAssignableToTenant: true,
|
|
7567
|
-
isAccessControlPermission: false,
|
|
7568
|
-
isRolePermission: false,
|
|
7569
|
-
group: PermissionGroup.ServiceCatalog,
|
|
7570
|
-
},
|
|
7571
|
-
|
|
7572
7526
|
{
|
|
7573
7527
|
permission: Permission.CreateServiceMonitor,
|
|
7574
7528
|
title: "Create Service Monitor",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Discriminator stored in the `serviceType` column of every telemetry
|
|
3
|
+
* row. Tells the read side which Postgres table the row's `serviceId`
|
|
4
|
+
* points at (the column name is historical — semantically it's a
|
|
5
|
+
* resource-type discriminator, since hosts, docker hosts, k8s clusters
|
|
6
|
+
* and monitors all reuse the `serviceId` slot to avoid synthesising
|
|
7
|
+
* placeholder Service rows just to satisfy the ClickHouse primary key).
|
|
8
|
+
*/
|
|
9
|
+
enum ServiceType {
|
|
10
|
+
OpenTelemetry = "OpenTelemetry",
|
|
11
|
+
Monitor = "Monitor",
|
|
12
|
+
Alert = "Alert",
|
|
13
|
+
Incident = "Incident",
|
|
14
|
+
Host = "Host",
|
|
15
|
+
DockerHost = "DockerHost",
|
|
16
|
+
KubernetesCluster = "KubernetesCluster",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default ServiceType;
|
|
@@ -21,6 +21,14 @@ export class RangeStartAndEndDateTimeUtil {
|
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
// 15 mins.
|
|
25
|
+
if (dashboardStartAndEndDate.range === TimeRange.PAST_FIFTEEN_MINS) {
|
|
26
|
+
return new InBetween<Date>(
|
|
27
|
+
OneUptimeDate.addRemoveMinutes(currentDate, -15),
|
|
28
|
+
currentDate,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
// 30 mins.
|
|
25
33
|
if (dashboardStartAndEndDate.range === TimeRange.PAST_THIRTY_MINS) {
|
|
26
34
|
return new InBetween<Date>(
|
package/Types/Time/TimeRange.ts
CHANGED
|
@@ -47,8 +47,8 @@ export default class Validation {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (field.validation.noSpecialCharacters) {
|
|
50
|
-
if (!content.match(/^[A-Za-z0-
|
|
51
|
-
return `${field.title || name}
|
|
50
|
+
if (!content.match(/^[A-Za-z0-9_-]*$/)) {
|
|
51
|
+
return `${field.title || name} can only contain letters, numbers, hyphens (-), and underscores (_).`;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -21,6 +21,9 @@ import { APP_API_URL } from "../../Config";
|
|
|
21
21
|
import PageLoader from "../Loader/PageLoader";
|
|
22
22
|
import ErrorMessage from "../ErrorMessage/ErrorMessage";
|
|
23
23
|
import Service from "../../../Models/DatabaseModels/Service";
|
|
24
|
+
import Host from "../../../Models/DatabaseModels/Host";
|
|
25
|
+
import DockerHost from "../../../Models/DatabaseModels/DockerHost";
|
|
26
|
+
import KubernetesCluster from "../../../Models/DatabaseModels/KubernetesCluster";
|
|
24
27
|
import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
|
|
25
28
|
import SortOrder from "../../../Types/BaseDatabase/SortOrder";
|
|
26
29
|
import ListResult from "../../../Types/BaseDatabase/ListResult";
|
|
@@ -210,6 +213,13 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
|
|
|
210
213
|
const [pageError, setPageError] = useState<string>("");
|
|
211
214
|
|
|
212
215
|
const [serviceMap, setServiceMap] = useState<Dictionary<Service>>({});
|
|
216
|
+
const [hostMap, setHostMap] = useState<Dictionary<Host>>({});
|
|
217
|
+
const [dockerHostMap, setDockerHostMap] = useState<Dictionary<DockerHost>>(
|
|
218
|
+
{},
|
|
219
|
+
);
|
|
220
|
+
const [kubernetesClusterMap, setKubernetesClusterMap] = useState<
|
|
221
|
+
Dictionary<KubernetesCluster>
|
|
222
|
+
>({});
|
|
213
223
|
|
|
214
224
|
const [selectedLogId, setSelectedLogId] = useState<string | null>(null);
|
|
215
225
|
const [focusedRowIndex, setFocusedRowIndex] = useState<number>(-1);
|
|
@@ -373,33 +383,105 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
|
|
|
373
383
|
setIsPageLoading(true);
|
|
374
384
|
setPageError("");
|
|
375
385
|
|
|
376
|
-
const telemetryServices
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
386
|
+
const [telemetryServices, hosts, dockerHosts, kubernetesClusters]: [
|
|
387
|
+
ListResult<Service>,
|
|
388
|
+
ListResult<Host>,
|
|
389
|
+
ListResult<DockerHost>,
|
|
390
|
+
ListResult<KubernetesCluster>,
|
|
391
|
+
] = await Promise.all([
|
|
392
|
+
ModelAPI.getList({
|
|
393
|
+
modelType: Service,
|
|
394
|
+
query: {},
|
|
395
|
+
select: {
|
|
396
|
+
name: true,
|
|
397
|
+
serviceColor: true,
|
|
398
|
+
},
|
|
399
|
+
limit: LIMIT_PER_PROJECT,
|
|
400
|
+
skip: 0,
|
|
401
|
+
sort: {
|
|
402
|
+
name: SortOrder.Ascending,
|
|
403
|
+
},
|
|
404
|
+
}),
|
|
405
|
+
ModelAPI.getList({
|
|
406
|
+
modelType: Host,
|
|
407
|
+
query: {},
|
|
408
|
+
select: {
|
|
409
|
+
name: true,
|
|
410
|
+
hostIdentifier: true,
|
|
411
|
+
},
|
|
412
|
+
limit: LIMIT_PER_PROJECT,
|
|
413
|
+
skip: 0,
|
|
414
|
+
sort: {
|
|
415
|
+
name: SortOrder.Ascending,
|
|
416
|
+
},
|
|
417
|
+
}),
|
|
418
|
+
ModelAPI.getList({
|
|
419
|
+
modelType: DockerHost,
|
|
420
|
+
query: {},
|
|
421
|
+
select: {
|
|
422
|
+
name: true,
|
|
423
|
+
hostIdentifier: true,
|
|
424
|
+
},
|
|
425
|
+
limit: LIMIT_PER_PROJECT,
|
|
426
|
+
skip: 0,
|
|
427
|
+
sort: {
|
|
428
|
+
name: SortOrder.Ascending,
|
|
429
|
+
},
|
|
430
|
+
}),
|
|
431
|
+
ModelAPI.getList({
|
|
432
|
+
modelType: KubernetesCluster,
|
|
433
|
+
query: {},
|
|
434
|
+
select: {
|
|
435
|
+
name: true,
|
|
436
|
+
clusterIdentifier: true,
|
|
437
|
+
},
|
|
438
|
+
limit: LIMIT_PER_PROJECT,
|
|
439
|
+
skip: 0,
|
|
440
|
+
sort: {
|
|
441
|
+
name: SortOrder.Ascending,
|
|
442
|
+
},
|
|
443
|
+
}),
|
|
444
|
+
]);
|
|
390
445
|
|
|
446
|
+
const services: Dictionary<Service> = {};
|
|
391
447
|
telemetryServices.data.forEach((service: Service) => {
|
|
392
448
|
if (!service.id) {
|
|
393
449
|
return;
|
|
394
450
|
}
|
|
395
|
-
|
|
396
451
|
services[service.id.toString()] = service;
|
|
397
452
|
});
|
|
398
453
|
|
|
454
|
+
const hostsById: Dictionary<Host> = {};
|
|
455
|
+
hosts.data.forEach((host: Host) => {
|
|
456
|
+
if (!host.id) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
hostsById[host.id.toString()] = host;
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
const dockerHostsById: Dictionary<DockerHost> = {};
|
|
463
|
+
dockerHosts.data.forEach((dockerHost: DockerHost) => {
|
|
464
|
+
if (!dockerHost.id) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
dockerHostsById[dockerHost.id.toString()] = dockerHost;
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
const clustersById: Dictionary<KubernetesCluster> = {};
|
|
471
|
+
kubernetesClusters.data.forEach((cluster: KubernetesCluster) => {
|
|
472
|
+
if (!cluster.id) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
clustersById[cluster.id.toString()] = cluster;
|
|
476
|
+
});
|
|
477
|
+
|
|
399
478
|
setServiceMap(services);
|
|
479
|
+
setHostMap(hostsById);
|
|
480
|
+
setDockerHostMap(dockerHostsById);
|
|
481
|
+
setKubernetesClusterMap(clustersById);
|
|
400
482
|
} catch (err) {
|
|
401
483
|
setPageError(
|
|
402
|
-
`We couldn't load telemetry
|
|
484
|
+
`We couldn't load telemetry resource metadata. ${API.getFriendlyErrorMessage(err as Error)}`,
|
|
403
485
|
);
|
|
404
486
|
} finally {
|
|
405
487
|
setIsPageLoading(false);
|
|
@@ -724,10 +806,43 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
|
|
|
724
806
|
displayValue: service?.name || filter.value,
|
|
725
807
|
};
|
|
726
808
|
}
|
|
809
|
+
if (filter.facetKey === "hostId" && hostMap[filter.value]) {
|
|
810
|
+
const host: Host | undefined = hostMap[filter.value];
|
|
811
|
+
return {
|
|
812
|
+
...filter,
|
|
813
|
+
displayValue: host?.name || host?.hostIdentifier || filter.value,
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
if (filter.facetKey === "dockerHostId" && dockerHostMap[filter.value]) {
|
|
817
|
+
const dockerHost: DockerHost | undefined = dockerHostMap[filter.value];
|
|
818
|
+
return {
|
|
819
|
+
...filter,
|
|
820
|
+
displayValue:
|
|
821
|
+
dockerHost?.name || dockerHost?.hostIdentifier || filter.value,
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
if (
|
|
825
|
+
filter.facetKey === "kubernetesClusterId" &&
|
|
826
|
+
kubernetesClusterMap[filter.value]
|
|
827
|
+
) {
|
|
828
|
+
const cluster: KubernetesCluster | undefined =
|
|
829
|
+
kubernetesClusterMap[filter.value];
|
|
830
|
+
return {
|
|
831
|
+
...filter,
|
|
832
|
+
displayValue:
|
|
833
|
+
cluster?.name || cluster?.clusterIdentifier || filter.value,
|
|
834
|
+
};
|
|
835
|
+
}
|
|
727
836
|
|
|
728
837
|
return filter;
|
|
729
838
|
});
|
|
730
|
-
}, [
|
|
839
|
+
}, [
|
|
840
|
+
props.activeFilters,
|
|
841
|
+
serviceMap,
|
|
842
|
+
hostMap,
|
|
843
|
+
dockerHostMap,
|
|
844
|
+
kubernetesClusterMap,
|
|
845
|
+
]);
|
|
731
846
|
|
|
732
847
|
/*
|
|
733
848
|
* Replace serviceId UUIDs with human-readable names in value suggestions,
|
|
@@ -939,6 +1054,9 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
|
|
|
939
1054
|
facetData={props.facetData}
|
|
940
1055
|
isLoading={props.facetLoading || false}
|
|
941
1056
|
serviceMap={serviceMap}
|
|
1057
|
+
hostMap={hostMap}
|
|
1058
|
+
dockerHostMap={dockerHostMap}
|
|
1059
|
+
kubernetesClusterMap={kubernetesClusterMap}
|
|
942
1060
|
onIncludeFilter={props.onFacetInclude || (() => {})}
|
|
943
1061
|
onExcludeFilter={props.onFacetExclude || (() => {})}
|
|
944
1062
|
activeFilters={props.activeFilters}
|
|
@@ -23,6 +23,7 @@ export interface LogTimeRangePickerProps {
|
|
|
23
23
|
// Preset options to show in the dropdown (ordered for log investigation use)
|
|
24
24
|
const PRESET_OPTIONS: Array<{ range: TimeRange; label: string }> = [
|
|
25
25
|
{ range: TimeRange.PAST_FIVE_MINS, label: "Past 5 Minutes" },
|
|
26
|
+
{ range: TimeRange.PAST_FIFTEEN_MINS, label: "Past 15 Minutes" },
|
|
26
27
|
{ range: TimeRange.PAST_THIRTY_MINS, label: "Past 30 Minutes" },
|
|
27
28
|
{ range: TimeRange.PAST_ONE_HOUR, label: "Past 1 Hour" },
|
|
28
29
|
{ range: TimeRange.PAST_TWO_HOURS, label: "Past 2 Hours" },
|
|
@@ -7,6 +7,9 @@ import {
|
|
|
7
7
|
} from "../types";
|
|
8
8
|
import FacetSection from "./FacetSection";
|
|
9
9
|
import Service from "../../../../Models/DatabaseModels/Service";
|
|
10
|
+
import Host from "../../../../Models/DatabaseModels/Host";
|
|
11
|
+
import DockerHost from "../../../../Models/DatabaseModels/DockerHost";
|
|
12
|
+
import KubernetesCluster from "../../../../Models/DatabaseModels/KubernetesCluster";
|
|
10
13
|
import Dictionary from "../../../../Types/Dictionary";
|
|
11
14
|
import ComponentLoader from "../../ComponentLoader/ComponentLoader";
|
|
12
15
|
import { getSeverityColor } from "./severityColors";
|
|
@@ -16,6 +19,9 @@ export interface LogsFacetSidebarProps {
|
|
|
16
19
|
facetData: FacetData;
|
|
17
20
|
isLoading: boolean;
|
|
18
21
|
serviceMap: Dictionary<Service>;
|
|
22
|
+
hostMap?: Dictionary<Host>;
|
|
23
|
+
dockerHostMap?: Dictionary<DockerHost>;
|
|
24
|
+
kubernetesClusterMap?: Dictionary<KubernetesCluster>;
|
|
19
25
|
onIncludeFilter: (facetKey: string, value: string) => void;
|
|
20
26
|
onExcludeFilter: (facetKey: string, value: string) => void;
|
|
21
27
|
activeFilters?: Array<ActiveFilter> | undefined;
|
|
@@ -72,10 +78,63 @@ function buildServiceColorMap(
|
|
|
72
78
|
return map;
|
|
73
79
|
}
|
|
74
80
|
|
|
81
|
+
function buildHostDisplayMap(
|
|
82
|
+
hostMap: Dictionary<Host> | undefined,
|
|
83
|
+
): Record<string, string> {
|
|
84
|
+
const map: Record<string, string> = {};
|
|
85
|
+
if (!hostMap) {
|
|
86
|
+
return map;
|
|
87
|
+
}
|
|
88
|
+
for (const [id, host] of Object.entries(hostMap)) {
|
|
89
|
+
const label: string | undefined = host?.name || host?.hostIdentifier;
|
|
90
|
+
if (label) {
|
|
91
|
+
map[id] = label;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return map;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function buildDockerHostDisplayMap(
|
|
98
|
+
dockerHostMap: Dictionary<DockerHost> | undefined,
|
|
99
|
+
): Record<string, string> {
|
|
100
|
+
const map: Record<string, string> = {};
|
|
101
|
+
if (!dockerHostMap) {
|
|
102
|
+
return map;
|
|
103
|
+
}
|
|
104
|
+
for (const [id, dockerHost] of Object.entries(dockerHostMap)) {
|
|
105
|
+
const label: string | undefined =
|
|
106
|
+
dockerHost?.name || dockerHost?.hostIdentifier;
|
|
107
|
+
if (label) {
|
|
108
|
+
map[id] = label;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return map;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function buildClusterDisplayMap(
|
|
115
|
+
clusterMap: Dictionary<KubernetesCluster> | undefined,
|
|
116
|
+
): Record<string, string> {
|
|
117
|
+
const map: Record<string, string> = {};
|
|
118
|
+
if (!clusterMap) {
|
|
119
|
+
return map;
|
|
120
|
+
}
|
|
121
|
+
for (const [id, cluster] of Object.entries(clusterMap)) {
|
|
122
|
+
const label: string | undefined =
|
|
123
|
+
cluster?.name || cluster?.clusterIdentifier;
|
|
124
|
+
if (label) {
|
|
125
|
+
map[id] = label;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return map;
|
|
129
|
+
}
|
|
130
|
+
|
|
75
131
|
function getFacetTitle(key: string): string {
|
|
76
132
|
const titleMap: Record<string, string> = {
|
|
77
133
|
severityText: "Severity",
|
|
78
134
|
serviceId: "Service",
|
|
135
|
+
hostId: "Host",
|
|
136
|
+
dockerHostId: "Docker Host",
|
|
137
|
+
kubernetesClusterId: "Kubernetes Cluster",
|
|
79
138
|
traceId: "Trace ID",
|
|
80
139
|
spanId: "Span ID",
|
|
81
140
|
};
|
|
@@ -98,8 +157,26 @@ const LogsFacetSidebar: FunctionComponent<LogsFacetSidebarProps> = (
|
|
|
98
157
|
return buildServiceColorMap(props.serviceMap);
|
|
99
158
|
}, [props.serviceMap]);
|
|
100
159
|
|
|
160
|
+
const hostDisplayMap: Record<string, string> = useMemo(() => {
|
|
161
|
+
return buildHostDisplayMap(props.hostMap);
|
|
162
|
+
}, [props.hostMap]);
|
|
163
|
+
|
|
164
|
+
const dockerHostDisplayMap: Record<string, string> = useMemo(() => {
|
|
165
|
+
return buildDockerHostDisplayMap(props.dockerHostMap);
|
|
166
|
+
}, [props.dockerHostMap]);
|
|
167
|
+
|
|
168
|
+
const clusterDisplayMap: Record<string, string> = useMemo(() => {
|
|
169
|
+
return buildClusterDisplayMap(props.kubernetesClusterMap);
|
|
170
|
+
}, [props.kubernetesClusterMap]);
|
|
171
|
+
|
|
101
172
|
const facetKeys: Array<string> = useMemo(() => {
|
|
102
|
-
const priorityKeys: Array<string> = [
|
|
173
|
+
const priorityKeys: Array<string> = [
|
|
174
|
+
"severityText",
|
|
175
|
+
"serviceId",
|
|
176
|
+
"hostId",
|
|
177
|
+
"dockerHostId",
|
|
178
|
+
"kubernetesClusterId",
|
|
179
|
+
];
|
|
103
180
|
const otherKeys: Array<string> = Object.keys(props.facetData).filter(
|
|
104
181
|
(key: string) => {
|
|
105
182
|
return !priorityKeys.includes(key);
|
|
@@ -191,6 +268,12 @@ const LogsFacetSidebar: FunctionComponent<LogsFacetSidebarProps> = (
|
|
|
191
268
|
if (key === "serviceId") {
|
|
192
269
|
valueDisplayMap = serviceDisplayMap;
|
|
193
270
|
valueColorMap = serviceColorMap;
|
|
271
|
+
} else if (key === "hostId") {
|
|
272
|
+
valueDisplayMap = hostDisplayMap;
|
|
273
|
+
} else if (key === "dockerHostId") {
|
|
274
|
+
valueDisplayMap = dockerHostDisplayMap;
|
|
275
|
+
} else if (key === "kubernetesClusterId") {
|
|
276
|
+
valueDisplayMap = clusterDisplayMap;
|
|
194
277
|
} else if (key === "severityText") {
|
|
195
278
|
valueColorMap = severityColorMap;
|
|
196
279
|
}
|
|
@@ -11,7 +11,6 @@ import FieldLabelElement from "../Detail/FieldLabel";
|
|
|
11
11
|
import Input, { InputType } from "../Input/Input";
|
|
12
12
|
|
|
13
13
|
export interface ComponentProps {
|
|
14
|
-
error?: string | undefined;
|
|
15
14
|
onChange?: ((value: TelemetryRetentionConfig | null) => void) | undefined;
|
|
16
15
|
value?: TelemetryRetentionConfig | undefined;
|
|
17
16
|
initialValue?: TelemetryRetentionConfig | undefined;
|
|
@@ -22,6 +22,7 @@ export interface TelemetryTimeRangePickerProps {
|
|
|
22
22
|
|
|
23
23
|
const PRESET_OPTIONS: Array<{ range: TimeRange; label: string }> = [
|
|
24
24
|
{ range: TimeRange.PAST_FIVE_MINS, label: "Past 5 Minutes" },
|
|
25
|
+
{ range: TimeRange.PAST_FIFTEEN_MINS, label: "Past 15 Minutes" },
|
|
25
26
|
{ range: TimeRange.PAST_THIRTY_MINS, label: "Past 30 Minutes" },
|
|
26
27
|
{ range: TimeRange.PAST_ONE_HOUR, label: "Past 1 Hour" },
|
|
27
28
|
{ range: TimeRange.PAST_TWO_HOURS, label: "Past 2 Hours" },
|
|
@@ -38,7 +38,7 @@ export default class ExceptionInstance extends AnalyticsBaseModel {
|
|
|
38
38
|
const serviceIdColumn = new AnalyticsTableColumn({
|
|
39
39
|
key: "serviceId",
|
|
40
40
|
title: "Service ID",
|
|
41
|
-
description: "ID of the Service
|
|
41
|
+
description: "ID of the resource the exception belongs to (Service / Host / DockerHost / KubernetesCluster / Monitor — disambiguated by serviceType)",
|
|
42
42
|
required: true,
|
|
43
43
|
type: TableColumnType.ObjectID,
|
|
44
44
|
accessControl: {
|
|
@@ -62,6 +62,39 @@ export default class ExceptionInstance extends AnalyticsBaseModel {
|
|
|
62
62
|
update: [],
|
|
63
63
|
},
|
|
64
64
|
});
|
|
65
|
+
const serviceTypeColumn = new AnalyticsTableColumn({
|
|
66
|
+
key: "serviceType",
|
|
67
|
+
title: "Service Type",
|
|
68
|
+
description: "Discriminator for serviceId — tells the read side which resource table to dispatch to",
|
|
69
|
+
required: false,
|
|
70
|
+
type: TableColumnType.Text,
|
|
71
|
+
skipIndex: {
|
|
72
|
+
name: "idx_service_type",
|
|
73
|
+
type: SkipIndexType.Set,
|
|
74
|
+
params: [10],
|
|
75
|
+
granularity: 4,
|
|
76
|
+
},
|
|
77
|
+
accessControl: {
|
|
78
|
+
read: [
|
|
79
|
+
Permission.ProjectOwner,
|
|
80
|
+
Permission.ProjectAdmin,
|
|
81
|
+
Permission.ProjectMember,
|
|
82
|
+
Permission.TelemetryAdmin,
|
|
83
|
+
Permission.TelemetryMember,
|
|
84
|
+
Permission.TelemetryViewer,
|
|
85
|
+
Permission.ReadTelemetryException,
|
|
86
|
+
],
|
|
87
|
+
create: [
|
|
88
|
+
Permission.ProjectOwner,
|
|
89
|
+
Permission.ProjectAdmin,
|
|
90
|
+
Permission.ProjectMember,
|
|
91
|
+
Permission.TelemetryAdmin,
|
|
92
|
+
Permission.TelemetryMember,
|
|
93
|
+
Permission.CreateTelemetryException,
|
|
94
|
+
],
|
|
95
|
+
update: [],
|
|
96
|
+
},
|
|
97
|
+
});
|
|
65
98
|
const timeColumn = new AnalyticsTableColumn({
|
|
66
99
|
key: "time",
|
|
67
100
|
title: "Time",
|
|
@@ -573,6 +606,7 @@ export default class ExceptionInstance extends AnalyticsBaseModel {
|
|
|
573
606
|
tableColumns: [
|
|
574
607
|
projectIdColumn,
|
|
575
608
|
serviceIdColumn,
|
|
609
|
+
serviceTypeColumn,
|
|
576
610
|
timeColumn,
|
|
577
611
|
timeUnixNanoColumn,
|
|
578
612
|
exceptionTypeColumn,
|
|
@@ -614,6 +648,12 @@ export default class ExceptionInstance extends AnalyticsBaseModel {
|
|
|
614
648
|
set serviceId(v) {
|
|
615
649
|
this.setColumnValue("serviceId", v);
|
|
616
650
|
}
|
|
651
|
+
get serviceType() {
|
|
652
|
+
return this.getColumnValue("serviceType");
|
|
653
|
+
}
|
|
654
|
+
set serviceType(v) {
|
|
655
|
+
this.setColumnValue("serviceType", v);
|
|
656
|
+
}
|
|
617
657
|
get time() {
|
|
618
658
|
return this.getColumnValue("time");
|
|
619
659
|
}
|