@oneuptime/common 10.4.7 → 10.4.9
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/Service.ts +1 -1
- package/Server/API/TelemetryExceptionAPI.ts +62 -0
- package/Server/Services/OpenTelemetryIngestService.ts +8 -8
- package/Server/Services/TelemetryExceptionService.ts +225 -0
- package/Server/Types/Database/QueryHelper.ts +35 -0
- package/Server/Types/Database/QueryUtil.ts +74 -2
- package/Types/Dashboard/DashboardComponents/DashboardAlertListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardDockerContainerListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardDockerHostListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardDockerImageListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardDockerNetworkListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardDockerVolumeListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardHostListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardIncidentListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardKubernetesCronJobListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardKubernetesDaemonSetListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardKubernetesDeploymentListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardKubernetesJobListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardKubernetesNamespaceListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardKubernetesNodeListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardKubernetesPodListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardKubernetesStatefulSetListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardMonitorListComponent.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardTraceListComponent.ts +1 -0
- package/Types/Telemetry/TelemetryRetentionConfig.ts +8 -8
- package/Types/Time/RangeStartAndEndDateTime.ts +8 -0
- package/Types/Time/TimeRange.ts +1 -0
- package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +1 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +64 -17
- package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +11 -11
- package/UI/Components/Telemetry/TelemetryRetentionConfigSummary.tsx +196 -78
- package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +1 -0
- package/Utils/Dashboard/Components/DashboardAlertListComponent.ts +5 -0
- package/Utils/Dashboard/Components/DashboardDockerContainerListComponent.ts +7 -0
- package/Utils/Dashboard/Components/DashboardDockerHostListComponent.ts +5 -0
- package/Utils/Dashboard/Components/DashboardDockerImageListComponent.ts +5 -0
- package/Utils/Dashboard/Components/DashboardDockerNetworkListComponent.ts +5 -0
- package/Utils/Dashboard/Components/DashboardDockerVolumeListComponent.ts +5 -0
- package/Utils/Dashboard/Components/DashboardHostListComponent.ts +3 -0
- package/Utils/Dashboard/Components/DashboardIncidentListComponent.ts +5 -0
- package/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.ts +3 -0
- package/Utils/Dashboard/Components/DashboardListSharedArgs.ts +31 -0
- package/Utils/Dashboard/Components/DashboardMonitorListComponent.ts +5 -0
- package/Utils/Dashboard/Components/DashboardTraceListComponent.ts +5 -0
- package/build/dist/Models/DatabaseModels/Service.js +1 -1
- package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
- package/build/dist/Server/API/TelemetryExceptionAPI.js +37 -1
- package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +5 -5
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryExceptionService.js +175 -0
- package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +35 -0
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryUtil.js +58 -2
- package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
- package/build/dist/Types/Telemetry/TelemetryRetentionConfig.js +3 -3
- package/build/dist/Types/Telemetry/TelemetryRetentionConfig.js.map +1 -1
- 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/LogsViewer/components/LogTimeRangePicker.js +1 -0
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +48 -13
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js +9 -9
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +1 -1
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js +107 -41
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.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/build/dist/Utils/Dashboard/Components/DashboardAlertListComponent.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardAlertListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardDockerContainerListComponent.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDockerContainerListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardDockerHostListComponent.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDockerHostListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardDockerImageListComponent.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDockerImageListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardDockerNetworkListComponent.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDockerNetworkListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardDockerVolumeListComponent.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDockerVolumeListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardHostListComponent.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardHostListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardIncidentListComponent.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardIncidentListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardListSharedArgs.js +21 -0
- package/build/dist/Utils/Dashboard/Components/DashboardListSharedArgs.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardTraceListComponent.js +2 -0
- package/build/dist/Utils/Dashboard/Components/DashboardTraceListComponent.js.map +1 -1
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ export default interface DashboardMonitorListComponent extends BaseComponent {
|
|
|
8
8
|
arguments: {
|
|
9
9
|
title?: string | undefined;
|
|
10
10
|
maxRows?: number | undefined;
|
|
11
|
+
viewMode?: "list" | "honeycomb" | undefined;
|
|
11
12
|
statusFilter?: string | undefined;
|
|
12
13
|
monitorStatusIds?: Array<string> | undefined;
|
|
13
14
|
monitorTypes?: Array<string> | undefined;
|
|
@@ -8,10 +8,10 @@ import { SpanStatus } from "../../Models/AnalyticsModels/Span";
|
|
|
8
8
|
* When a row is ingested, retention falls through, narrowest-first:
|
|
9
9
|
* 1. service[pillar].byX[bucketKey]
|
|
10
10
|
* 2. service[pillar].default
|
|
11
|
-
* 3. service.retainTelemetryDataForDays
|
|
11
|
+
* 3. service.retainTelemetryDataForDays (service default)
|
|
12
12
|
* 4. project[pillar].byX[bucketKey]
|
|
13
13
|
* 5. project[pillar].default
|
|
14
|
-
* 6. project.defaultTelemetryRetentionInDays
|
|
14
|
+
* 6. project.defaultTelemetryRetentionInDays (project default)
|
|
15
15
|
* 7. HARDCODED_DEFAULT_TELEMETRY_RETENTION_IN_DAYS
|
|
16
16
|
*/
|
|
17
17
|
export default interface TelemetryRetentionConfig {
|
|
@@ -74,26 +74,26 @@ export function resolveTelemetryRetentionInDays(input: {
|
|
|
74
74
|
pillar: TelemetryPillar;
|
|
75
75
|
bucketKey?: LogSeverity | SpanStatus | null;
|
|
76
76
|
serviceConfig?: TelemetryRetentionConfig | null;
|
|
77
|
-
|
|
77
|
+
serviceRetentionInDays?: number | null;
|
|
78
78
|
projectConfig?: TelemetryRetentionConfig | null;
|
|
79
|
-
|
|
79
|
+
projectRetentionInDays?: number | null;
|
|
80
80
|
}): number {
|
|
81
81
|
const {
|
|
82
82
|
pillar,
|
|
83
83
|
bucketKey,
|
|
84
84
|
serviceConfig,
|
|
85
|
-
|
|
85
|
+
serviceRetentionInDays,
|
|
86
86
|
projectConfig,
|
|
87
|
-
|
|
87
|
+
projectRetentionInDays,
|
|
88
88
|
} = input;
|
|
89
89
|
|
|
90
90
|
const candidates: Array<number | null> = [
|
|
91
91
|
getBucketValue(serviceConfig, pillar, bucketKey),
|
|
92
92
|
getPillarDefault(serviceConfig, pillar),
|
|
93
|
-
pickPositive(
|
|
93
|
+
pickPositive(serviceRetentionInDays),
|
|
94
94
|
getBucketValue(projectConfig, pillar, bucketKey),
|
|
95
95
|
getPillarDefault(projectConfig, pillar),
|
|
96
|
-
pickPositive(
|
|
96
|
+
pickPositive(projectRetentionInDays),
|
|
97
97
|
];
|
|
98
98
|
|
|
99
99
|
for (const value of candidates) {
|
|
@@ -13,6 +13,14 @@ export class RangeStartAndEndDateTimeUtil {
|
|
|
13
13
|
): InBetween<Date> {
|
|
14
14
|
const currentDate: Date = OneUptimeDate.getCurrentDate();
|
|
15
15
|
|
|
16
|
+
// 5 mins.
|
|
17
|
+
if (dashboardStartAndEndDate.range === TimeRange.PAST_FIVE_MINS) {
|
|
18
|
+
return new InBetween<Date>(
|
|
19
|
+
OneUptimeDate.addRemoveMinutes(currentDate, -5),
|
|
20
|
+
currentDate,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
// 30 mins.
|
|
17
25
|
if (dashboardStartAndEndDate.range === TimeRange.PAST_THIRTY_MINS) {
|
|
18
26
|
return new InBetween<Date>(
|
package/Types/Time/TimeRange.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface LogTimeRangePickerProps {
|
|
|
22
22
|
|
|
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
|
+
{ range: TimeRange.PAST_FIVE_MINS, label: "Past 5 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" },
|
|
@@ -1807,17 +1807,21 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
1807
1807
|
(): BulkActionButtonSchema<TBaseModel> => {
|
|
1808
1808
|
return {
|
|
1809
1809
|
title: "Delete",
|
|
1810
|
-
buttonStyleType: ButtonStyleType.
|
|
1810
|
+
buttonStyleType: ButtonStyleType.DANGER,
|
|
1811
1811
|
icon: IconProp.Trash,
|
|
1812
1812
|
confirmMessage: (items: Array<TBaseModel>) => {
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1813
|
+
const itemLabel: string =
|
|
1814
|
+
items.length === 1
|
|
1815
|
+
? props.singularName || model.singularName || "item"
|
|
1816
|
+
: props.pluralName || model.pluralName || "items";
|
|
1817
|
+
return `Are you sure you want to delete ${items.length} ${itemLabel}? This action cannot be undone.`;
|
|
1816
1818
|
},
|
|
1817
1819
|
confirmTitle: (items: Array<TBaseModel>) => {
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1820
|
+
const itemLabel: string =
|
|
1821
|
+
items.length === 1
|
|
1822
|
+
? props.singularName || model.singularName || "item"
|
|
1823
|
+
: props.pluralName || model.pluralName || "items";
|
|
1824
|
+
return `Delete ${items.length} ${itemLabel}`;
|
|
1821
1825
|
},
|
|
1822
1826
|
confirmButtonStyleType: ButtonStyleType.DANGER,
|
|
1823
1827
|
onClick: async ({
|
|
@@ -1908,25 +1912,68 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
1908
1912
|
onFilterRefreshClick={async () => {
|
|
1909
1913
|
await getFilterDropdownItems();
|
|
1910
1914
|
}}
|
|
1911
|
-
bulkActions={{
|
|
1912
|
-
|
|
1915
|
+
bulkActions={(() => {
|
|
1916
|
+
const permissions: Array<Permission> =
|
|
1917
|
+
PermissionUtil.getAllPermissions();
|
|
1918
|
+
const userCanDelete: boolean =
|
|
1919
|
+
model.hasDeletePermissions(permissions);
|
|
1920
|
+
|
|
1921
|
+
const sourceButtons: Array<
|
|
1922
|
+
BulkActionButtonSchema<TBaseModel> | ModalTableBulkDefaultActions
|
|
1923
|
+
> = [...(props.bulkActions?.buttons ?? [])];
|
|
1924
|
+
|
|
1925
|
+
/*
|
|
1926
|
+
* Auto-include the default Delete bulk action whenever the user has
|
|
1927
|
+
* model-level delete permission, so every table that exposes row
|
|
1928
|
+
* selection also exposes a way to delete the selected rows. This is
|
|
1929
|
+
* intentionally decoupled from `isDeleteable` — that flag governs the
|
|
1930
|
+
* per-row Delete button in the Actions column, not bulk operations.
|
|
1931
|
+
* The confirmation modal is wired up via the schema's confirmMessage
|
|
1932
|
+
* / confirmTitle below. Skip if the table author already added it.
|
|
1933
|
+
*/
|
|
1934
|
+
const alreadyHasDeleteAction: boolean = sourceButtons.some(
|
|
1913
1935
|
(
|
|
1914
1936
|
action:
|
|
1915
1937
|
| BulkActionButtonSchema<TBaseModel>
|
|
1916
1938
|
| ModalTableBulkDefaultActions,
|
|
1917
1939
|
) => {
|
|
1918
|
-
|
|
1919
|
-
|
|
1940
|
+
if (action === ModalTableBulkDefaultActions.Delete) {
|
|
1941
|
+
return true;
|
|
1942
|
+
}
|
|
1920
1943
|
if (
|
|
1921
|
-
action ===
|
|
1922
|
-
|
|
1944
|
+
typeof action === "object" &&
|
|
1945
|
+
action !== null &&
|
|
1946
|
+
"title" in action &&
|
|
1947
|
+
(action as BulkActionButtonSchema<TBaseModel>).title ===
|
|
1948
|
+
"Delete"
|
|
1923
1949
|
) {
|
|
1924
|
-
return
|
|
1950
|
+
return true;
|
|
1925
1951
|
}
|
|
1926
|
-
return
|
|
1952
|
+
return false;
|
|
1927
1953
|
},
|
|
1928
|
-
)
|
|
1929
|
-
|
|
1954
|
+
);
|
|
1955
|
+
if (userCanDelete && !alreadyHasDeleteAction) {
|
|
1956
|
+
sourceButtons.push(ModalTableBulkDefaultActions.Delete);
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
return {
|
|
1960
|
+
buttons: sourceButtons.map(
|
|
1961
|
+
(
|
|
1962
|
+
action:
|
|
1963
|
+
| BulkActionButtonSchema<TBaseModel>
|
|
1964
|
+
| ModalTableBulkDefaultActions,
|
|
1965
|
+
) => {
|
|
1966
|
+
if (
|
|
1967
|
+
action === ModalTableBulkDefaultActions.Delete &&
|
|
1968
|
+
userCanDelete
|
|
1969
|
+
) {
|
|
1970
|
+
return getDeleteBulkAction();
|
|
1971
|
+
}
|
|
1972
|
+
return action;
|
|
1973
|
+
},
|
|
1974
|
+
) as Array<BulkActionButtonSchema<TBaseModel>>,
|
|
1975
|
+
};
|
|
1976
|
+
})()}
|
|
1930
1977
|
onBulkActionEnd={async () => {
|
|
1931
1978
|
setBulkSelectedItems([]);
|
|
1932
1979
|
await fetchItems();
|
|
@@ -178,7 +178,7 @@ const TelemetryRetentionConfigForm: FunctionComponent<ComponentProps> = (
|
|
|
178
178
|
<FieldLabelElement title={label} description={description} />
|
|
179
179
|
<Input
|
|
180
180
|
type={InputType.NUMBER}
|
|
181
|
-
placeholder="
|
|
181
|
+
placeholder="Use default retention"
|
|
182
182
|
value={numberToString(
|
|
183
183
|
(config[pillar] as { default?: number | null } | undefined)
|
|
184
184
|
?.default,
|
|
@@ -198,13 +198,13 @@ const TelemetryRetentionConfigForm: FunctionComponent<ComponentProps> = (
|
|
|
198
198
|
Logs
|
|
199
199
|
</h3>
|
|
200
200
|
<p className="text-xs text-gray-500 dark:text-slate-400 mb-3">
|
|
201
|
-
Retention in days for log records. Per-severity values
|
|
202
|
-
logs default; leave blank to
|
|
201
|
+
Retention in days for log records. Per-severity values take precedence
|
|
202
|
+
over the logs default; leave any field blank to fall back.
|
|
203
203
|
</p>
|
|
204
204
|
{renderPillarDefault(
|
|
205
205
|
"logs",
|
|
206
206
|
"Logs default (days)",
|
|
207
|
-
"Applies to log
|
|
207
|
+
"Applies to every log record unless its severity has a specific override below.",
|
|
208
208
|
)}
|
|
209
209
|
<div className="border-t border-gray-100 dark:border-slate-800 pt-3 mt-2">
|
|
210
210
|
<p className="text-xs font-medium text-gray-700 dark:text-slate-300 mb-2">
|
|
@@ -217,7 +217,7 @@ const TelemetryRetentionConfigForm: FunctionComponent<ComponentProps> = (
|
|
|
217
217
|
<FieldLabelElement title={severity} />
|
|
218
218
|
<Input
|
|
219
219
|
type={InputType.NUMBER}
|
|
220
|
-
placeholder="
|
|
220
|
+
placeholder="Use logs default"
|
|
221
221
|
value={numberToString(config.logs?.bySeverity?.[severity])}
|
|
222
222
|
onChange={(raw: string) => {
|
|
223
223
|
setLogSeverityValue(severity, parsePositiveOrNull(raw));
|
|
@@ -235,13 +235,13 @@ const TelemetryRetentionConfigForm: FunctionComponent<ComponentProps> = (
|
|
|
235
235
|
Traces
|
|
236
236
|
</h3>
|
|
237
237
|
<p className="text-xs text-gray-500 dark:text-slate-400 mb-3">
|
|
238
|
-
Retention in days for spans
|
|
239
|
-
Per-status values
|
|
238
|
+
Retention in days for spans and the exceptions captured on them.
|
|
239
|
+
Per-status values take precedence over the traces default.
|
|
240
240
|
</p>
|
|
241
241
|
{renderPillarDefault(
|
|
242
242
|
"traces",
|
|
243
243
|
"Traces default (days)",
|
|
244
|
-
"Applies to
|
|
244
|
+
"Applies to every span unless its status has a specific override below.",
|
|
245
245
|
)}
|
|
246
246
|
<div className="border-t border-gray-100 dark:border-slate-800 pt-3 mt-2">
|
|
247
247
|
<p className="text-xs font-medium text-gray-700 dark:text-slate-300 mb-2">
|
|
@@ -255,7 +255,7 @@ const TelemetryRetentionConfigForm: FunctionComponent<ComponentProps> = (
|
|
|
255
255
|
<FieldLabelElement title={entry.label} />
|
|
256
256
|
<Input
|
|
257
257
|
type={InputType.NUMBER}
|
|
258
|
-
placeholder="
|
|
258
|
+
placeholder="Use traces default"
|
|
259
259
|
value={numberToString(
|
|
260
260
|
config.traces?.byStatus?.[entry.status],
|
|
261
261
|
)}
|
|
@@ -284,7 +284,7 @@ const TelemetryRetentionConfigForm: FunctionComponent<ComponentProps> = (
|
|
|
284
284
|
{renderPillarDefault(
|
|
285
285
|
"metrics",
|
|
286
286
|
"Metrics default (days)",
|
|
287
|
-
"Applies to all metric points. Leave blank to
|
|
287
|
+
"Applies to all metric points. Leave blank to use the default retention.",
|
|
288
288
|
)}
|
|
289
289
|
</div>
|
|
290
290
|
|
|
@@ -298,7 +298,7 @@ const TelemetryRetentionConfigForm: FunctionComponent<ComponentProps> = (
|
|
|
298
298
|
{renderPillarDefault(
|
|
299
299
|
"profiles",
|
|
300
300
|
"Profiles default (days)",
|
|
301
|
-
"Applies to all profile samples. Leave blank to
|
|
301
|
+
"Applies to all profile samples. Leave blank to use the default retention.",
|
|
302
302
|
)}
|
|
303
303
|
</div>
|
|
304
304
|
</div>
|
|
@@ -13,91 +13,209 @@ const SPAN_STATUS_LABEL: Record<SpanStatus, string> = {
|
|
|
13
13
|
[SpanStatus.Error]: "Error",
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
const LOG_SEVERITY_ORDER: Array<LogSeverity> = [
|
|
17
|
+
LogSeverity.Fatal,
|
|
18
|
+
LogSeverity.Error,
|
|
19
|
+
LogSeverity.Warning,
|
|
20
|
+
LogSeverity.Information,
|
|
21
|
+
LogSeverity.Debug,
|
|
22
|
+
LogSeverity.Trace,
|
|
23
|
+
LogSeverity.Unspecified,
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const SPAN_STATUS_ORDER: Array<SpanStatus> = [
|
|
27
|
+
SpanStatus.Error,
|
|
28
|
+
SpanStatus.Ok,
|
|
29
|
+
SpanStatus.Unset,
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const formatDays: (days: number) => string = (days: number): string => {
|
|
33
|
+
return days === 1 ? "1 day" : `${days} days`;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const pickPositive: (value: number | null | undefined) => number | null = (
|
|
37
|
+
value: number | null | undefined,
|
|
38
|
+
): number | null => {
|
|
39
|
+
return typeof value === "number" && value > 0 ? value : null;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
interface PillarOverride {
|
|
43
|
+
label: string;
|
|
44
|
+
days: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface PillarRender {
|
|
48
|
+
title: string;
|
|
49
|
+
hint: string;
|
|
50
|
+
defaultDays: number | null;
|
|
51
|
+
overrides: Array<PillarOverride>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const PillarCard: FunctionComponent<{ pillar: PillarRender }> = (props: {
|
|
55
|
+
pillar: PillarRender;
|
|
56
|
+
}): ReactElement => {
|
|
57
|
+
const { title, hint, defaultDays, overrides } = props.pillar;
|
|
58
|
+
const hasDefault: boolean = defaultDays !== null;
|
|
59
|
+
const hasOverrides: boolean = overrides.length > 0;
|
|
60
|
+
const isCustomized: boolean = hasDefault || hasOverrides;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div className="rounded-lg border border-gray-200 dark:border-slate-700 bg-white dark:bg-slate-900 p-4">
|
|
64
|
+
<div className="flex items-start justify-between gap-3">
|
|
65
|
+
<div className="min-w-0">
|
|
66
|
+
<div className="flex items-center gap-2">
|
|
67
|
+
<h4 className="text-sm font-semibold text-gray-900 dark:text-slate-100">
|
|
68
|
+
{title}
|
|
69
|
+
</h4>
|
|
70
|
+
<span
|
|
71
|
+
className={
|
|
72
|
+
isCustomized
|
|
73
|
+
? "inline-flex items-center rounded-full bg-indigo-50 dark:bg-indigo-950/40 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-indigo-700 dark:text-indigo-300 border border-indigo-100 dark:border-indigo-900"
|
|
74
|
+
: "inline-flex items-center rounded-full bg-gray-100 dark:bg-slate-800 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-gray-500 dark:text-slate-400 border border-gray-200 dark:border-slate-700"
|
|
75
|
+
}
|
|
76
|
+
>
|
|
77
|
+
{isCustomized ? "Custom" : "Default"}
|
|
78
|
+
</span>
|
|
79
|
+
</div>
|
|
80
|
+
<p className="mt-1 text-xs text-gray-500 dark:text-slate-400">
|
|
81
|
+
{hint}
|
|
82
|
+
</p>
|
|
83
|
+
</div>
|
|
84
|
+
<div className="text-right whitespace-nowrap shrink-0">
|
|
85
|
+
{hasDefault ? (
|
|
86
|
+
<>
|
|
87
|
+
<div className="text-lg font-semibold text-gray-900 dark:text-slate-100 leading-tight">
|
|
88
|
+
{defaultDays}{" "}
|
|
89
|
+
<span className="text-sm font-normal text-gray-500 dark:text-slate-400">
|
|
90
|
+
{(defaultDays as number) === 1 ? "day" : "days"}
|
|
91
|
+
</span>
|
|
92
|
+
</div>
|
|
93
|
+
<div className="text-[10px] uppercase tracking-wide text-gray-400 dark:text-slate-500">
|
|
94
|
+
Default
|
|
95
|
+
</div>
|
|
96
|
+
</>
|
|
97
|
+
) : (
|
|
98
|
+
<div className="text-xs italic text-gray-400 dark:text-slate-500">
|
|
99
|
+
Uses default
|
|
100
|
+
<br />
|
|
101
|
+
retention
|
|
102
|
+
</div>
|
|
103
|
+
)}
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
{hasOverrides ? (
|
|
107
|
+
<div className="mt-3 border-t border-gray-100 dark:border-slate-800 pt-3">
|
|
108
|
+
<p className="text-[10px] font-semibold uppercase tracking-wide text-gray-400 dark:text-slate-500 mb-2">
|
|
109
|
+
Specific overrides
|
|
110
|
+
</p>
|
|
111
|
+
<div className="flex flex-wrap gap-1.5">
|
|
112
|
+
{overrides.map((o: PillarOverride) => {
|
|
113
|
+
return (
|
|
114
|
+
<span
|
|
115
|
+
key={o.label}
|
|
116
|
+
className="inline-flex items-center gap-1.5 rounded-full border border-indigo-100 dark:border-indigo-900 bg-indigo-50 dark:bg-indigo-950/40 px-2.5 py-0.5 text-xs font-medium text-indigo-700 dark:text-indigo-300"
|
|
117
|
+
>
|
|
118
|
+
<span>{o.label}</span>
|
|
119
|
+
<span
|
|
120
|
+
aria-hidden="true"
|
|
121
|
+
className="text-indigo-300 dark:text-indigo-700"
|
|
122
|
+
>
|
|
123
|
+
·
|
|
124
|
+
</span>
|
|
125
|
+
<span className="font-normal">{formatDays(o.days)}</span>
|
|
126
|
+
</span>
|
|
127
|
+
);
|
|
128
|
+
})}
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
) : null}
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const sortOverridesByDaysDesc: (
|
|
137
|
+
list: Array<PillarOverride>,
|
|
138
|
+
) => Array<PillarOverride> = (
|
|
139
|
+
list: Array<PillarOverride>,
|
|
140
|
+
): Array<PillarOverride> => {
|
|
141
|
+
return [...list].sort((a: PillarOverride, b: PillarOverride) => {
|
|
142
|
+
return b.days - a.days;
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
|
|
16
146
|
const TelemetryRetentionConfigSummary: FunctionComponent<ComponentProps> = (
|
|
17
147
|
props: ComponentProps,
|
|
18
148
|
): ReactElement => {
|
|
19
149
|
const config: TelemetryRetentionConfig | null | undefined = props.config;
|
|
20
150
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
})}
|
|
72
|
-
</ul>
|
|
73
|
-
) : null}
|
|
74
|
-
</div>
|
|
75
|
-
);
|
|
76
|
-
};
|
|
151
|
+
const logsOverrides: Array<PillarOverride> = LOG_SEVERITY_ORDER.flatMap(
|
|
152
|
+
(severity: LogSeverity): Array<PillarOverride> => {
|
|
153
|
+
const days: number | null = pickPositive(
|
|
154
|
+
config?.logs?.bySeverity?.[severity],
|
|
155
|
+
);
|
|
156
|
+
return days === null ? [] : [{ label: severity, days: days }];
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const tracesOverrides: Array<PillarOverride> = SPAN_STATUS_ORDER.flatMap(
|
|
161
|
+
(status: SpanStatus): Array<PillarOverride> => {
|
|
162
|
+
const days: number | null = pickPositive(
|
|
163
|
+
config?.traces?.byStatus?.[status],
|
|
164
|
+
);
|
|
165
|
+
return days === null
|
|
166
|
+
? []
|
|
167
|
+
: [{ label: SPAN_STATUS_LABEL[status], days: days }];
|
|
168
|
+
},
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const pillars: Array<PillarRender> = [
|
|
172
|
+
{
|
|
173
|
+
title: "Logs",
|
|
174
|
+
hint: "Log records, with optional per-severity overrides.",
|
|
175
|
+
defaultDays: pickPositive(config?.logs?.default),
|
|
176
|
+
overrides: sortOverridesByDaysDesc(logsOverrides),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
title: "Traces",
|
|
180
|
+
hint: "Spans and exceptions, with optional per-status overrides.",
|
|
181
|
+
defaultDays: pickPositive(config?.traces?.default),
|
|
182
|
+
overrides: sortOverridesByDaysDesc(tracesOverrides),
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
title: "Metrics",
|
|
186
|
+
hint: "Metric data points and aggregates.",
|
|
187
|
+
defaultDays: pickPositive(config?.metrics?.default),
|
|
188
|
+
overrides: [],
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
title: "Profiles",
|
|
192
|
+
hint: "Profile samples and stack traces.",
|
|
193
|
+
defaultDays: pickPositive(config?.profiles?.default),
|
|
194
|
+
overrides: [],
|
|
195
|
+
},
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
const anyConfigured: boolean = pillars.some((p: PillarRender) => {
|
|
199
|
+
return p.defaultDays !== null || p.overrides.length > 0;
|
|
200
|
+
});
|
|
77
201
|
|
|
78
202
|
return (
|
|
79
|
-
<div>
|
|
80
|
-
{
|
|
81
|
-
"
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return { label: SPAN_STATUS_LABEL[status] || statusKey, days };
|
|
96
|
-
},
|
|
97
|
-
),
|
|
98
|
-
)}
|
|
99
|
-
{renderPillar("Metrics", config.metrics?.default, [])}
|
|
100
|
-
{renderPillar("Profiles", config.profiles?.default, [])}
|
|
203
|
+
<div className="space-y-3">
|
|
204
|
+
{!anyConfigured ? (
|
|
205
|
+
<div className="rounded-md border border-dashed border-gray-200 dark:border-slate-700 bg-gray-50 dark:bg-slate-900/40 px-4 py-3">
|
|
206
|
+
<p className="text-sm font-medium text-gray-700 dark:text-slate-200">
|
|
207
|
+
No overrides set.
|
|
208
|
+
</p>
|
|
209
|
+
<p className="text-xs text-gray-500 dark:text-slate-400 mt-0.5">
|
|
210
|
+
Every telemetry type uses the default retention shown above.
|
|
211
|
+
</p>
|
|
212
|
+
</div>
|
|
213
|
+
) : null}
|
|
214
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
215
|
+
{pillars.map((pillar: PillarRender) => {
|
|
216
|
+
return <PillarCard key={pillar.title} pillar={pillar} />;
|
|
217
|
+
})}
|
|
218
|
+
</div>
|
|
101
219
|
</div>
|
|
102
220
|
);
|
|
103
221
|
};
|
|
@@ -21,6 +21,7 @@ export interface TelemetryTimeRangePickerProps {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const PRESET_OPTIONS: Array<{ range: TimeRange; label: string }> = [
|
|
24
|
+
{ range: TimeRange.PAST_FIVE_MINS, label: "Past 5 Minutes" },
|
|
24
25
|
{ range: TimeRange.PAST_THIRTY_MINS, label: "Past 30 Minutes" },
|
|
25
26
|
{ range: TimeRange.PAST_ONE_HOUR, label: "Past 1 Hour" },
|
|
26
27
|
{ range: TimeRange.PAST_TWO_HOURS, label: "Past 2 Hours" },
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
EntityFilterModelType,
|
|
10
10
|
} from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
|
|
11
11
|
import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
|
|
12
|
+
import { getViewModeArgument } from "./DashboardListSharedArgs";
|
|
12
13
|
|
|
13
14
|
const DisplaySection: ComponentArgumentSection = {
|
|
14
15
|
name: "Display Options",
|
|
@@ -67,6 +68,10 @@ export default class DashboardAlertListComponentUtil extends DashboardBaseCompon
|
|
|
67
68
|
section: DisplaySection,
|
|
68
69
|
});
|
|
69
70
|
|
|
71
|
+
componentArguments.push(
|
|
72
|
+
getViewModeArgument<DashboardAlertListComponent>(DisplaySection),
|
|
73
|
+
);
|
|
74
|
+
|
|
70
75
|
componentArguments.push({
|
|
71
76
|
name: "Lifecycle State",
|
|
72
77
|
description: "Quick filter by lifecycle state",
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
EntityFilterModelType,
|
|
10
10
|
} from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
|
|
11
11
|
import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
|
|
12
|
+
import { getViewModeArgument } from "./DashboardListSharedArgs";
|
|
12
13
|
|
|
13
14
|
const DisplaySection: ComponentArgumentSection = {
|
|
14
15
|
name: "Display Options",
|
|
@@ -67,6 +68,12 @@ export default class DashboardDockerContainerListComponentUtil extends Dashboard
|
|
|
67
68
|
section: DisplaySection,
|
|
68
69
|
});
|
|
69
70
|
|
|
71
|
+
args.push(
|
|
72
|
+
getViewModeArgument<DashboardDockerContainerListComponent>(
|
|
73
|
+
DisplaySection,
|
|
74
|
+
),
|
|
75
|
+
);
|
|
76
|
+
|
|
70
77
|
args.push({
|
|
71
78
|
name: "Hosts",
|
|
72
79
|
description: "Show only containers from the selected hosts",
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ComponentInputType,
|
|
9
9
|
} from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
|
|
10
10
|
import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
|
|
11
|
+
import { getViewModeArgument } from "./DashboardListSharedArgs";
|
|
11
12
|
|
|
12
13
|
const DisplaySection: ComponentArgumentSection = {
|
|
13
14
|
name: "Display Options",
|
|
@@ -64,6 +65,10 @@ export default class DashboardDockerHostListComponentUtil extends DashboardBaseC
|
|
|
64
65
|
section: DisplaySection,
|
|
65
66
|
});
|
|
66
67
|
|
|
68
|
+
args.push(
|
|
69
|
+
getViewModeArgument<DashboardDockerHostListComponent>(DisplaySection),
|
|
70
|
+
);
|
|
71
|
+
|
|
67
72
|
args.push({
|
|
68
73
|
name: "Connection Status",
|
|
69
74
|
description: "Quick filter by OTel collector status",
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
EntityFilterModelType,
|
|
10
10
|
} from "../../../Types/Dashboard/DashboardComponents/ComponentArgument";
|
|
11
11
|
import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
|
|
12
|
+
import { getViewModeArgument } from "./DashboardListSharedArgs";
|
|
12
13
|
|
|
13
14
|
const DisplaySection: ComponentArgumentSection = {
|
|
14
15
|
name: "Display Options",
|
|
@@ -66,6 +67,10 @@ export default class DashboardDockerImageListComponentUtil extends DashboardBase
|
|
|
66
67
|
section: DisplaySection,
|
|
67
68
|
});
|
|
68
69
|
|
|
70
|
+
args.push(
|
|
71
|
+
getViewModeArgument<DashboardDockerImageListComponent>(DisplaySection),
|
|
72
|
+
);
|
|
73
|
+
|
|
69
74
|
args.push({
|
|
70
75
|
name: "Hosts",
|
|
71
76
|
description: "Show only images from the selected hosts",
|