@oneuptime/common 10.4.5 → 10.4.6
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/Project.ts +25 -0
- package/Models/DatabaseModels/Service.ts +42 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1779199346010-AddTelemetryRetentionConfig.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/OpenTelemetryIngestService.ts +50 -46
- package/Types/Telemetry/TelemetryRetentionConfig.ts +105 -0
- package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +308 -0
- package/UI/Components/Telemetry/TelemetryRetentionConfigSummary.tsx +105 -0
- package/build/dist/Models/DatabaseModels/Project.js +25 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Service.js +42 -0
- package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779199346010-AddTelemetryRetentionConfig.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779199346010-AddTelemetryRetentionConfig.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +27 -23
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Types/Telemetry/TelemetryRetentionConfig.js +44 -0
- package/build/dist/Types/Telemetry/TelemetryRetentionConfig.js.map +1 -0
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js +159 -0
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +1 -0
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js +53 -0
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import MetricDownsamplingRetentionDays from "../../Types/Metrics/MetricDownsamplingRetentionDays";
|
|
2
|
+
import TelemetryRetentionConfig from "../../Types/Telemetry/TelemetryRetentionConfig";
|
|
2
3
|
import Reseller from "./Reseller";
|
|
3
4
|
import ResellerPlan from "./ResellerPlan";
|
|
4
5
|
import User from "./User";
|
|
@@ -2028,6 +2029,30 @@ export default class Project extends TenantModel {
|
|
|
2028
2029
|
})
|
|
2029
2030
|
public defaultTelemetryRetentionInDays?: number = undefined;
|
|
2030
2031
|
|
|
2032
|
+
@ColumnAccessControl({
|
|
2033
|
+
create: [],
|
|
2034
|
+
read: [
|
|
2035
|
+
Permission.ProjectOwner,
|
|
2036
|
+
Permission.ProjectAdmin,
|
|
2037
|
+
Permission.ProjectMember,
|
|
2038
|
+
Permission.Viewer,
|
|
2039
|
+
Permission.ReadProject,
|
|
2040
|
+
],
|
|
2041
|
+
update: [Permission.ProjectOwner, Permission.ProjectAdmin],
|
|
2042
|
+
})
|
|
2043
|
+
@TableColumn({
|
|
2044
|
+
type: TableColumnType.JSON,
|
|
2045
|
+
required: false,
|
|
2046
|
+
title: "Telemetry Data Retention Overrides",
|
|
2047
|
+
description:
|
|
2048
|
+
"Project-wide per-pillar retention overrides for telemetry data (logs by severity, traces by status, metrics, profiles). Falls back to defaultTelemetryRetentionInDays when a pillar or bucket is not set.",
|
|
2049
|
+
})
|
|
2050
|
+
@Column({
|
|
2051
|
+
type: ColumnType.JSON,
|
|
2052
|
+
nullable: true,
|
|
2053
|
+
})
|
|
2054
|
+
public telemetryRetentionConfig?: TelemetryRetentionConfig = undefined;
|
|
2055
|
+
|
|
2031
2056
|
@ColumnAccessControl({
|
|
2032
2057
|
create: [],
|
|
2033
2058
|
read: [
|
|
@@ -25,6 +25,7 @@ import ObjectID from "../../Types/ObjectID";
|
|
|
25
25
|
import Permission from "../../Types/Permission";
|
|
26
26
|
import TechStack from "../../Types/Service/TechStack";
|
|
27
27
|
import MetricDownsamplingRetentionDays from "../../Types/Metrics/MetricDownsamplingRetentionDays";
|
|
28
|
+
import TelemetryRetentionConfig from "../../Types/Telemetry/TelemetryRetentionConfig";
|
|
28
29
|
import {
|
|
29
30
|
Column,
|
|
30
31
|
Entity,
|
|
@@ -795,6 +796,47 @@ export default class Service extends BaseModel {
|
|
|
795
796
|
public metricDownsamplingRetentionDays?: MetricDownsamplingRetentionDays =
|
|
796
797
|
undefined;
|
|
797
798
|
|
|
799
|
+
@ColumnAccessControl({
|
|
800
|
+
create: [
|
|
801
|
+
Permission.ProjectOwner,
|
|
802
|
+
Permission.ProjectAdmin,
|
|
803
|
+
Permission.ProjectMember,
|
|
804
|
+
Permission.SettingsAdmin,
|
|
805
|
+
Permission.SettingsMember,
|
|
806
|
+
Permission.CreateService,
|
|
807
|
+
],
|
|
808
|
+
read: [
|
|
809
|
+
Permission.ProjectOwner,
|
|
810
|
+
Permission.ProjectAdmin,
|
|
811
|
+
Permission.ProjectMember,
|
|
812
|
+
Permission.Viewer,
|
|
813
|
+
Permission.SettingsAdmin,
|
|
814
|
+
Permission.SettingsMember,
|
|
815
|
+
Permission.SettingsViewer,
|
|
816
|
+
Permission.ReadService,
|
|
817
|
+
],
|
|
818
|
+
update: [
|
|
819
|
+
Permission.ProjectOwner,
|
|
820
|
+
Permission.ProjectAdmin,
|
|
821
|
+
Permission.ProjectMember,
|
|
822
|
+
Permission.SettingsAdmin,
|
|
823
|
+
Permission.SettingsMember,
|
|
824
|
+
Permission.EditService,
|
|
825
|
+
],
|
|
826
|
+
})
|
|
827
|
+
@TableColumn({
|
|
828
|
+
type: TableColumnType.JSON,
|
|
829
|
+
required: false,
|
|
830
|
+
title: "Telemetry Data Retention Overrides",
|
|
831
|
+
description:
|
|
832
|
+
"Per-pillar retention overrides for this service (logs by severity, traces by status, metrics, profiles). Unset fields inherit the project-level config and umbrella default.",
|
|
833
|
+
})
|
|
834
|
+
@Column({
|
|
835
|
+
type: ColumnType.JSON,
|
|
836
|
+
nullable: true,
|
|
837
|
+
})
|
|
838
|
+
public telemetryRetentionConfig?: TelemetryRetentionConfig = undefined;
|
|
839
|
+
|
|
798
840
|
@ColumnAccessControl({
|
|
799
841
|
create: [],
|
|
800
842
|
read: [
|
package/Server/Infrastructure/Postgres/SchemaMigrations/1779199346010-AddTelemetryRetentionConfig.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class AddTelemetryRetentionConfig1779199346010
|
|
4
|
+
implements MigrationInterface
|
|
5
|
+
{
|
|
6
|
+
name = "AddTelemetryRetentionConfig1779199346010";
|
|
7
|
+
|
|
8
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
9
|
+
await queryRunner.query(
|
|
10
|
+
`ALTER TABLE "Project" ADD "telemetryRetentionConfig" jsonb`,
|
|
11
|
+
);
|
|
12
|
+
await queryRunner.query(
|
|
13
|
+
`ALTER TABLE "Service" ADD "telemetryRetentionConfig" jsonb`,
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
18
|
+
await queryRunner.query(
|
|
19
|
+
`ALTER TABLE "Service" DROP COLUMN "telemetryRetentionConfig"`,
|
|
20
|
+
);
|
|
21
|
+
await queryRunner.query(
|
|
22
|
+
`ALTER TABLE "Project" DROP COLUMN "telemetryRetentionConfig"`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -337,6 +337,7 @@ import { MigrateLegacyManagerRolesToAdmin1778900000000 } from "./1778900000000-M
|
|
|
337
337
|
import { AddOnCallDutyPolicyScheduleOwners1778929624633 } from "./1778929624633-AddOnCallDutyPolicyScheduleOwners";
|
|
338
338
|
import { AddOnCallIncomingCallOwnersAndRules1778931537020 } from "./1778931537020-AddOnCallIncomingCallOwnersAndRules";
|
|
339
339
|
import { IncreaseSmtpUsernameLength1779125489830 } from "./1779125489830-IncreaseSmtpUsernameLength";
|
|
340
|
+
import { AddTelemetryRetentionConfig1779199346010 } from "./1779199346010-AddTelemetryRetentionConfig";
|
|
340
341
|
export default [
|
|
341
342
|
InitialMigration,
|
|
342
343
|
MigrationName1717678334852,
|
|
@@ -677,4 +678,5 @@ export default [
|
|
|
677
678
|
AddOnCallDutyPolicyScheduleOwners1778929624633,
|
|
678
679
|
AddOnCallIncomingCallOwnersAndRules1778931537020,
|
|
679
680
|
IncreaseSmtpUsernameLength1779125489830,
|
|
681
|
+
AddTelemetryRetentionConfig1779199346010,
|
|
680
682
|
];
|
|
@@ -15,6 +15,7 @@ import { extractOneuptimeLabelNames } from "../Utils/Telemetry/OneuptimeLabel";
|
|
|
15
15
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
16
16
|
import SortOrder from "../../Types/BaseDatabase/SortOrder";
|
|
17
17
|
import logger from "../Utils/Logger";
|
|
18
|
+
import TelemetryRetentionConfig from "../../Types/Telemetry/TelemetryRetentionConfig";
|
|
18
19
|
|
|
19
20
|
export enum OtelAggregationTemporality {
|
|
20
21
|
Cumulative = "AGGREGATION_TEMPORALITY_CUMULATIVE",
|
|
@@ -25,26 +26,38 @@ export interface TelemetryServiceMetadata {
|
|
|
25
26
|
serviceName: string;
|
|
26
27
|
serviceId: ObjectID;
|
|
27
28
|
dataRententionInDays: number;
|
|
29
|
+
serviceRetentionConfig: TelemetryRetentionConfig | null;
|
|
30
|
+
serviceUmbrellaInDays: number | null;
|
|
31
|
+
projectRetentionConfig: TelemetryRetentionConfig | null;
|
|
32
|
+
projectUmbrellaInDays: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface ProjectRetentionContext {
|
|
36
|
+
projectRetentionConfig: TelemetryRetentionConfig | null;
|
|
37
|
+
projectUmbrellaInDays: number;
|
|
28
38
|
}
|
|
29
39
|
|
|
30
40
|
export default class OTelIngestService {
|
|
31
41
|
@CaptureSpan()
|
|
32
|
-
private static async
|
|
42
|
+
private static async getProjectRetentionContext(
|
|
33
43
|
projectId: ObjectID,
|
|
34
|
-
): Promise<
|
|
44
|
+
): Promise<ProjectRetentionContext> {
|
|
35
45
|
const project: Project | null = await ProjectService.findOneById({
|
|
36
46
|
id: projectId,
|
|
37
47
|
select: {
|
|
38
48
|
defaultTelemetryRetentionInDays: true,
|
|
49
|
+
telemetryRetentionConfig: true,
|
|
39
50
|
},
|
|
40
51
|
props: {
|
|
41
52
|
isRoot: true,
|
|
42
53
|
},
|
|
43
54
|
});
|
|
44
55
|
|
|
45
|
-
return
|
|
46
|
-
project?.
|
|
47
|
-
|
|
56
|
+
return {
|
|
57
|
+
projectRetentionConfig: project?.telemetryRetentionConfig ?? null,
|
|
58
|
+
projectUmbrellaInDays:
|
|
59
|
+
project?.defaultTelemetryRetentionInDays || DEFAULT_RETENTION_IN_DAYS,
|
|
60
|
+
};
|
|
48
61
|
}
|
|
49
62
|
|
|
50
63
|
@CaptureSpan()
|
|
@@ -52,17 +65,12 @@ export default class OTelIngestService {
|
|
|
52
65
|
serviceName: string;
|
|
53
66
|
projectId: ObjectID;
|
|
54
67
|
resourceAttributes?: JSONArray | undefined;
|
|
55
|
-
}): Promise<{
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
dataRententionInDays: number;
|
|
62
|
-
} = await this.findOrCreateTelemetryService({
|
|
63
|
-
serviceName: data.serviceName,
|
|
64
|
-
projectId: data.projectId,
|
|
65
|
-
});
|
|
68
|
+
}): Promise<TelemetryServiceMetadata> {
|
|
69
|
+
const result: TelemetryServiceMetadata =
|
|
70
|
+
await this.findOrCreateTelemetryService({
|
|
71
|
+
serviceName: data.serviceName,
|
|
72
|
+
projectId: data.projectId,
|
|
73
|
+
});
|
|
66
74
|
|
|
67
75
|
/*
|
|
68
76
|
* Touch `lastSeenAt` on the service. Throttled per-service inside
|
|
@@ -119,10 +127,7 @@ export default class OTelIngestService {
|
|
|
119
127
|
private static async findOrCreateTelemetryService(data: {
|
|
120
128
|
serviceName: string;
|
|
121
129
|
projectId: ObjectID;
|
|
122
|
-
}): Promise<{
|
|
123
|
-
serviceId: ObjectID;
|
|
124
|
-
dataRententionInDays: number;
|
|
125
|
-
}> {
|
|
130
|
+
}): Promise<TelemetryServiceMetadata> {
|
|
126
131
|
/*
|
|
127
132
|
* Sort by createdAt ASC for deterministic resolution if the
|
|
128
133
|
* DB ever ends up with duplicates (defense in depth — the
|
|
@@ -140,6 +145,7 @@ export default class OTelIngestService {
|
|
|
140
145
|
select: {
|
|
141
146
|
_id: true,
|
|
142
147
|
retainTelemetryDataForDays: true,
|
|
148
|
+
telemetryRetentionConfig: true,
|
|
143
149
|
},
|
|
144
150
|
sort: {
|
|
145
151
|
createdAt: SortOrder.Ascending,
|
|
@@ -149,10 +155,27 @@ export default class OTelIngestService {
|
|
|
149
155
|
},
|
|
150
156
|
});
|
|
151
157
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
await this.getProjectDefaultRetentionInDays(data.projectId);
|
|
158
|
+
const projectContext: ProjectRetentionContext =
|
|
159
|
+
await this.getProjectRetentionContext(data.projectId);
|
|
155
160
|
|
|
161
|
+
const buildMetadata: (svc: Service) => TelemetryServiceMetadata = (
|
|
162
|
+
svc: Service,
|
|
163
|
+
): TelemetryServiceMetadata => {
|
|
164
|
+
const serviceUmbrella: number | null =
|
|
165
|
+
svc.retainTelemetryDataForDays ?? null;
|
|
166
|
+
return {
|
|
167
|
+
serviceName: data.serviceName,
|
|
168
|
+
serviceId: svc.id!,
|
|
169
|
+
dataRententionInDays:
|
|
170
|
+
serviceUmbrella || projectContext.projectUmbrellaInDays,
|
|
171
|
+
serviceRetentionConfig: svc.telemetryRetentionConfig ?? null,
|
|
172
|
+
serviceUmbrellaInDays: serviceUmbrella,
|
|
173
|
+
projectRetentionConfig: projectContext.projectRetentionConfig,
|
|
174
|
+
projectUmbrellaInDays: projectContext.projectUmbrellaInDays,
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
if (!service) {
|
|
156
179
|
try {
|
|
157
180
|
const newService: Service = new Service();
|
|
158
181
|
newService.projectId = data.projectId;
|
|
@@ -166,10 +189,7 @@ export default class OTelIngestService {
|
|
|
166
189
|
},
|
|
167
190
|
});
|
|
168
191
|
|
|
169
|
-
return
|
|
170
|
-
serviceId: createdService.id!,
|
|
171
|
-
dataRententionInDays: projectDefaultRetention,
|
|
172
|
-
};
|
|
192
|
+
return buildMetadata(createdService);
|
|
173
193
|
} catch {
|
|
174
194
|
/*
|
|
175
195
|
* Race condition: another request created the service concurrently.
|
|
@@ -183,6 +203,7 @@ export default class OTelIngestService {
|
|
|
183
203
|
select: {
|
|
184
204
|
_id: true,
|
|
185
205
|
retainTelemetryDataForDays: true,
|
|
206
|
+
telemetryRetentionConfig: true,
|
|
186
207
|
},
|
|
187
208
|
sort: {
|
|
188
209
|
createdAt: SortOrder.Ascending,
|
|
@@ -193,12 +214,7 @@ export default class OTelIngestService {
|
|
|
193
214
|
});
|
|
194
215
|
|
|
195
216
|
if (existingService) {
|
|
196
|
-
return
|
|
197
|
-
serviceId: existingService.id!,
|
|
198
|
-
dataRententionInDays:
|
|
199
|
-
existingService.retainTelemetryDataForDays ||
|
|
200
|
-
projectDefaultRetention,
|
|
201
|
-
};
|
|
217
|
+
return buildMetadata(existingService);
|
|
202
218
|
}
|
|
203
219
|
|
|
204
220
|
throw new Error(
|
|
@@ -207,19 +223,7 @@ export default class OTelIngestService {
|
|
|
207
223
|
}
|
|
208
224
|
}
|
|
209
225
|
|
|
210
|
-
|
|
211
|
-
return {
|
|
212
|
-
serviceId: service.id!,
|
|
213
|
-
dataRententionInDays: service.retainTelemetryDataForDays,
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
serviceId: service.id!,
|
|
219
|
-
dataRententionInDays: await this.getProjectDefaultRetentionInDays(
|
|
220
|
-
data.projectId,
|
|
221
|
-
),
|
|
222
|
-
};
|
|
226
|
+
return buildMetadata(service);
|
|
223
227
|
}
|
|
224
228
|
@CaptureSpan()
|
|
225
229
|
public static getMetricFromDatapoint(data: {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import LogSeverity from "../Log/LogSeverity";
|
|
2
|
+
import { SpanStatus } from "../../Models/AnalyticsModels/Span";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Per-pillar telemetry retention overrides.
|
|
6
|
+
*
|
|
7
|
+
* Lives on Project (project-wide defaults) and Service (per-service overrides).
|
|
8
|
+
* When a row is ingested, retention falls through, narrowest-first:
|
|
9
|
+
* 1. service[pillar].byX[bucketKey]
|
|
10
|
+
* 2. service[pillar].default
|
|
11
|
+
* 3. service.retainTelemetryDataForDays (umbrella)
|
|
12
|
+
* 4. project[pillar].byX[bucketKey]
|
|
13
|
+
* 5. project[pillar].default
|
|
14
|
+
* 6. project.defaultTelemetryRetentionInDays (umbrella)
|
|
15
|
+
* 7. HARDCODED_DEFAULT_TELEMETRY_RETENTION_IN_DAYS
|
|
16
|
+
*/
|
|
17
|
+
export default interface TelemetryRetentionConfig {
|
|
18
|
+
logs?: {
|
|
19
|
+
default?: number | null;
|
|
20
|
+
bySeverity?: Partial<Record<LogSeverity, number | null>>;
|
|
21
|
+
};
|
|
22
|
+
traces?: {
|
|
23
|
+
default?: number | null;
|
|
24
|
+
byStatus?: Partial<Record<SpanStatus, number | null>>;
|
|
25
|
+
};
|
|
26
|
+
metrics?: {
|
|
27
|
+
default?: number | null;
|
|
28
|
+
};
|
|
29
|
+
profiles?: {
|
|
30
|
+
default?: number | null;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type TelemetryPillar = "logs" | "traces" | "metrics" | "profiles";
|
|
35
|
+
|
|
36
|
+
export const HARDCODED_DEFAULT_TELEMETRY_RETENTION_IN_DAYS: number = 15;
|
|
37
|
+
|
|
38
|
+
function pickPositive(value: number | null | undefined): number | null {
|
|
39
|
+
return typeof value === "number" && value > 0 ? value : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getBucketValue(
|
|
43
|
+
config: TelemetryRetentionConfig | null | undefined,
|
|
44
|
+
pillar: TelemetryPillar,
|
|
45
|
+
bucketKey: LogSeverity | SpanStatus | null | undefined,
|
|
46
|
+
): number | null {
|
|
47
|
+
if (!config || bucketKey === undefined || bucketKey === null) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (pillar === "logs") {
|
|
51
|
+
const bySeverity: Partial<Record<LogSeverity, number | null>> | undefined =
|
|
52
|
+
config.logs?.bySeverity;
|
|
53
|
+
return pickPositive(bySeverity?.[bucketKey as LogSeverity]);
|
|
54
|
+
}
|
|
55
|
+
if (pillar === "traces") {
|
|
56
|
+
const byStatus: Partial<Record<SpanStatus, number | null>> | undefined =
|
|
57
|
+
config.traces?.byStatus;
|
|
58
|
+
return pickPositive(byStatus?.[bucketKey as SpanStatus]);
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getPillarDefault(
|
|
64
|
+
config: TelemetryRetentionConfig | null | undefined,
|
|
65
|
+
pillar: TelemetryPillar,
|
|
66
|
+
): number | null {
|
|
67
|
+
if (!config) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return pickPositive(config[pillar]?.default);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function resolveTelemetryRetentionInDays(input: {
|
|
74
|
+
pillar: TelemetryPillar;
|
|
75
|
+
bucketKey?: LogSeverity | SpanStatus | null;
|
|
76
|
+
serviceConfig?: TelemetryRetentionConfig | null;
|
|
77
|
+
serviceUmbrellaInDays?: number | null;
|
|
78
|
+
projectConfig?: TelemetryRetentionConfig | null;
|
|
79
|
+
projectUmbrellaInDays?: number | null;
|
|
80
|
+
}): number {
|
|
81
|
+
const {
|
|
82
|
+
pillar,
|
|
83
|
+
bucketKey,
|
|
84
|
+
serviceConfig,
|
|
85
|
+
serviceUmbrellaInDays,
|
|
86
|
+
projectConfig,
|
|
87
|
+
projectUmbrellaInDays,
|
|
88
|
+
} = input;
|
|
89
|
+
|
|
90
|
+
const candidates: Array<number | null> = [
|
|
91
|
+
getBucketValue(serviceConfig, pillar, bucketKey),
|
|
92
|
+
getPillarDefault(serviceConfig, pillar),
|
|
93
|
+
pickPositive(serviceUmbrellaInDays),
|
|
94
|
+
getBucketValue(projectConfig, pillar, bucketKey),
|
|
95
|
+
getPillarDefault(projectConfig, pillar),
|
|
96
|
+
pickPositive(projectUmbrellaInDays),
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
for (const value of candidates) {
|
|
100
|
+
if (value !== null) {
|
|
101
|
+
return value;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return HARDCODED_DEFAULT_TELEMETRY_RETENTION_IN_DAYS;
|
|
105
|
+
}
|