mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-01 07:12:00 +08:00
feat: s3 ttl validation
This commit is contained in:
parent
5be1eb58b2
commit
24d6a1e7b2
@ -8,7 +8,13 @@ const setRetention = async (
|
|||||||
props: Props,
|
props: Props,
|
||||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post<PayloadProps>(`/settings/ttl`, props);
|
const response = await axios.post<PayloadProps>(
|
||||||
|
`/settings/ttl?duration=${props.totalDuration}&type=${props.type}${
|
||||||
|
props.coldStorage
|
||||||
|
? `&coldStorage=${props.coldStorage};toColdDuration=${props.toColdDuration}`
|
||||||
|
: ''
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
@ -24,9 +24,17 @@ function Retention({
|
|||||||
timeUnitValue: initialTimeUnitValue,
|
timeUnitValue: initialTimeUnitValue,
|
||||||
} = convertHoursValueToRelevantUnit(retentionValue);
|
} = convertHoursValueToRelevantUnit(retentionValue);
|
||||||
const [selectedTimeUnit, setSelectTimeUnit] = useState(initialTimeUnitValue);
|
const [selectedTimeUnit, setSelectTimeUnit] = useState(initialTimeUnitValue);
|
||||||
const [selectedValue, setSelectedValue] = useState<number | null>(
|
const [selectedValue, setSelectedValue] = useState<number | null>(null);
|
||||||
initialValue,
|
|
||||||
);
|
useEffect(() => {
|
||||||
|
setSelectedValue(initialValue);
|
||||||
|
}, [initialValue]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectTimeUnit(initialTimeUnitValue);
|
||||||
|
}, [initialTimeUnitValue]);
|
||||||
|
|
||||||
|
|
||||||
const menuItems = TimeUnits.map((option) => (
|
const menuItems = TimeUnits.map((option) => (
|
||||||
<Option key={option.value} value={option.value}>
|
<Option key={option.value} value={option.value}>
|
||||||
@ -44,6 +52,7 @@ function Retention({
|
|||||||
TimeUnits,
|
TimeUnits,
|
||||||
(timeUnit) => timeUnit.value === selectedTimeUnit,
|
(timeUnit) => timeUnit.value === selectedTimeUnit,
|
||||||
)?.multiplier;
|
)?.multiplier;
|
||||||
|
if (!selectedValue) setRetentionValue(null);
|
||||||
if (selectedValue && inverseMultiplier) {
|
if (selectedValue && inverseMultiplier) {
|
||||||
setRetentionValue(selectedValue * (1 / inverseMultiplier));
|
setRetentionValue(selectedValue * (1 / inverseMultiplier));
|
||||||
}
|
}
|
||||||
@ -89,7 +98,7 @@ function Retention({
|
|||||||
style={{ width: 75 }}
|
style={{ width: 75 }}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
defaultValue={selectedTimeUnit}
|
value={selectedTimeUnit}
|
||||||
onChange={currentSelectedOption}
|
onChange={currentSelectedOption}
|
||||||
style={{ width: 100 }}
|
style={{ width: 100 }}
|
||||||
>
|
>
|
||||||
@ -103,7 +112,7 @@ function Retention({
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface RetentionProps {
|
interface RetentionProps {
|
||||||
retentionValue: number;
|
retentionValue: number | null;
|
||||||
text: string;
|
text: string;
|
||||||
setRetentionValue: React.Dispatch<React.SetStateAction<number | null>>;
|
setRetentionValue: React.Dispatch<React.SetStateAction<number | null>>;
|
||||||
hide: boolean;
|
hide: boolean;
|
||||||
|
@ -36,26 +36,35 @@ function GeneralSettings(): JSX.Element {
|
|||||||
const [availableDisks, setAvailableDisks] = useState<IDiskType | null>(null);
|
const [availableDisks, setAvailableDisks] = useState<IDiskType | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getDisks().then((response) => setAvailableDisks(response));
|
getDisks().then((response) => setAvailableDisks(response.payload));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { payload: currentTTLValues, loading, error, errorMessage } = useFetch<
|
const { payload: currentTTLValues, loading, error, errorMessage } = useFetch<
|
||||||
PayloadProps,
|
PayloadProps,
|
||||||
undefined
|
undefined
|
||||||
>(getRetentionPeriodApi, undefined);
|
>(getRetentionPeriodApi, undefined);
|
||||||
|
|
||||||
const [metricsTotalRetentionPeriod, setMetricsTotalRetentionPeriod] = useState<
|
const [metricsTotalRetentionPeriod, setMetricsTotalRetentionPeriod] = useState<
|
||||||
number | null
|
number | null
|
||||||
>(currentTTLValues?.metrics_ttl_duration_hrs);
|
>(null);
|
||||||
const [metricsS3RetentionPeriod, setMetricsS3RetentionPeriod] = useState<
|
const [metricsS3RetentionPeriod, setMetricsS3RetentionPeriod] = useState<
|
||||||
number | null
|
number | null
|
||||||
>(currentTTLValues?.metrics_move_ttl_duration_hrs);
|
>(null);
|
||||||
const [tracesTotalRetentionPeriod, setTracesTotalRetentionPeriod] = useState<
|
const [tracesTotalRetentionPeriod, setTracesTotalRetentionPeriod] = useState<
|
||||||
number | null
|
number | null
|
||||||
>(currentTTLValues?.traces_ttl_duration_hrs);
|
>(null);
|
||||||
const [tracesS3RetentionPeriod, setTracesS3RetentionPeriod] = useState<
|
const [tracesS3RetentionPeriod, setTracesS3RetentionPeriod] = useState<
|
||||||
number | null
|
number | null
|
||||||
>(currentTTLValues?.traces_move_ttl_duration_hrs);
|
>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentTTLValues) {
|
||||||
|
setMetricsTotalRetentionPeriod(currentTTLValues.metrics_ttl_duration_hrs);
|
||||||
|
setMetricsS3RetentionPeriod(currentTTLValues.metrics_move_ttl_duration_hrs);
|
||||||
|
setTracesTotalRetentionPeriod(currentTTLValues.traces_ttl_duration_hrs);
|
||||||
|
setTracesS3RetentionPeriod(currentTTLValues.traces_move_ttl_duration_hrs);
|
||||||
|
console.log({ currentTTLValues });
|
||||||
|
}
|
||||||
|
}, [currentTTLValues]);
|
||||||
|
|
||||||
const onModalToggleHandler = (): void => {
|
const onModalToggleHandler = (): void => {
|
||||||
setModal((modal) => !modal);
|
setModal((modal) => !modal);
|
||||||
@ -79,52 +88,67 @@ function GeneralSettings(): JSX.Element {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// const retentionRenderConfig = () => { };
|
// const retentionRenderConfig = () => { };
|
||||||
const renderConfig = useMemo(() => {
|
const s3Enabled = useMemo(
|
||||||
const s3Enabled = !!find(
|
() => !!find(availableDisks, (disks: IDiskType) => disks?.type === 's3'),
|
||||||
availableDisks,
|
[availableDisks],
|
||||||
(disks: IDiskType) => disks?.type === 's3',
|
);
|
||||||
);
|
|
||||||
return [
|
const renderConfig = [
|
||||||
{
|
{
|
||||||
name: 'Metrics',
|
name: 'Metrics',
|
||||||
retentionFields: [
|
retentionFields: [
|
||||||
{
|
{
|
||||||
name: 'Total Retention Period',
|
name: 'Total Retention Period',
|
||||||
value: metricsTotalRetentionPeriod,
|
value: metricsTotalRetentionPeriod,
|
||||||
setValue: setMetricsTotalRetentionPeriod,
|
setValue: setMetricsTotalRetentionPeriod,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: `Move to S3\n(should be lower than total retention period)`,
|
name: `Move to S3\n(should be lower than total retention period)`,
|
||||||
value: metricsS3RetentionPeriod,
|
value: metricsS3RetentionPeriod,
|
||||||
setValue: setMetricsS3RetentionPeriod,
|
setValue: setMetricsS3RetentionPeriod,
|
||||||
hide: !s3Enabled,
|
hide: !s3Enabled,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Traces',
|
name: 'Traces',
|
||||||
retentionFields: [
|
retentionFields: [
|
||||||
{
|
{
|
||||||
name: 'Total Retention Period',
|
name: 'Total Retention Period',
|
||||||
value: tracesTotalRetentionPeriod,
|
value: tracesTotalRetentionPeriod,
|
||||||
setValue: setTracesTotalRetentionPeriod,
|
setValue: setTracesTotalRetentionPeriod,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: `Move to S3\n(should be lower than total retention period)`,
|
name: `Move to S3\n(should be lower than total retention period)`,
|
||||||
value: tracesS3RetentionPeriod,
|
value: tracesS3RetentionPeriod,
|
||||||
setValue: setTracesS3RetentionPeriod,
|
setValue: setTracesS3RetentionPeriod,
|
||||||
hide: !s3Enabled,
|
hide: !s3Enabled,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
].map((category): JSX.Element | null => {
|
||||||
}, [
|
if (
|
||||||
availableDisks,
|
Array.isArray(category.retentionFields) &&
|
||||||
metricsS3RetentionPeriod,
|
category.retentionFields.length > 0
|
||||||
metricsTotalRetentionPeriod,
|
) {
|
||||||
tracesS3RetentionPeriod,
|
return (
|
||||||
tracesTotalRetentionPeriod,
|
<Col flex="40%" style={{ minWidth: 475 }} key={category.name}>
|
||||||
]);
|
<Typography.Title level={3}>{category.name}</Typography.Title>
|
||||||
|
|
||||||
|
{category.retentionFields.map((retentionField) => (
|
||||||
|
<Retention
|
||||||
|
key={retentionField.name}
|
||||||
|
text={retentionField.name}
|
||||||
|
retentionValue={retentionField.value}
|
||||||
|
setRetentionValue={retentionField.setValue}
|
||||||
|
hide={!!retentionField.hide}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
const onOkHandler = async (): Promise<void> => {
|
const onOkHandler = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
@ -138,28 +162,46 @@ function GeneralSettings(): JSX.Element {
|
|||||||
// (payload?.metrics_ttl_duration_hrs || 0) < 0
|
// (payload?.metrics_ttl_duration_hrs || 0) < 0
|
||||||
// ? payload?.metrics_ttl_duration_hrs || 0
|
// ? payload?.metrics_ttl_duration_hrs || 0
|
||||||
// : parseInt(retentionPeroidMetrics, 10);
|
// : parseInt(retentionPeroidMetrics, 10);
|
||||||
const apiResponse = await setRetentionApi({
|
const [metricsTTLApiResponse, tracesTTLApiResponse] = await Promise.all([
|
||||||
metrics_ttl_duration_hrs: metricsTotalRetentionPeriod || -1,
|
setRetentionApi({
|
||||||
metrics_move_ttl_duration_hrs: metricsS3RetentionPeriod || -1,
|
type: 'metrics',
|
||||||
traces_move_ttl_duration_hrs: tracesS3RetentionPeriod || -1,
|
totalDuration: `${metricsTotalRetentionPeriod || -1}h`,
|
||||||
traces_ttl_duration_hrs: tracesTotalRetentionPeriod || -1,
|
coldStorage: s3Enabled ? 's3' : null,
|
||||||
|
toColdDuration: `${metricsS3RetentionPeriod || -1}h`,
|
||||||
|
}),
|
||||||
|
setRetentionApi({
|
||||||
|
type: 'traces',
|
||||||
|
totalDuration: `${tracesTotalRetentionPeriod || -1}h`,
|
||||||
|
coldStorage: s3Enabled ? 's3' : null,
|
||||||
|
toColdDuration: `${tracesS3RetentionPeriod || -1}h`,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
[
|
||||||
|
{
|
||||||
|
apiResponse: metricsTTLApiResponse,
|
||||||
|
name: 'metrics',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
apiResponse: tracesTTLApiResponse,
|
||||||
|
name: 'traces',
|
||||||
|
},
|
||||||
|
].forEach(({ apiResponse, name }) => {
|
||||||
|
if (apiResponse.statusCode === 200) {
|
||||||
|
notifications.success({
|
||||||
|
message: 'Success!',
|
||||||
|
placement: 'topRight',
|
||||||
|
description: `Congrats. The retention periods for ${name} has been updated successfully.`,
|
||||||
|
});
|
||||||
|
// checkMetricTraceDefault(retentionTraceValue, retentionMetricsValue);
|
||||||
|
onModalToggleHandler();
|
||||||
|
} else {
|
||||||
|
notifications.error({
|
||||||
|
message: 'Error',
|
||||||
|
description: `There was an issue in changing the retention period for ${name}. Please try again or reach out to support@signoz.io`,
|
||||||
|
placement: 'topRight',
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (apiResponse.statusCode === 200) {
|
|
||||||
notifications.success({
|
|
||||||
message: 'Success!',
|
|
||||||
placement: 'topRight',
|
|
||||||
description: 'Congrats. The retention periods were updated correctly.',
|
|
||||||
});
|
|
||||||
// checkMetricTraceDefault(retentionTraceValue, retentionMetricsValue);
|
|
||||||
onModalToggleHandler();
|
|
||||||
} else {
|
|
||||||
notifications.error({
|
|
||||||
message: 'Error',
|
|
||||||
description:
|
|
||||||
'There was an issue in changing the retention period. Please try again or reach out to support@signoz.io',
|
|
||||||
placement: 'topRight',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setPostApiLoading(false);
|
setPostApiLoading(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error({
|
notifications.error({
|
||||||
@ -169,8 +211,57 @@ function GeneralSettings(): JSX.Element {
|
|||||||
placement: 'topRight',
|
placement: 'topRight',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
setModal(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [isDisabled, errorText] = useMemo(() => {
|
||||||
|
// Various methods to return dynamic error message text.
|
||||||
|
const messages = {
|
||||||
|
compareError: (value: string | number): string =>
|
||||||
|
`Total retention period for ${value} can’t be lower than period after which data is moved to s3`,
|
||||||
|
nullValueError: (value: string | number): string =>
|
||||||
|
`Retention Peroid for ${value} is not set yet. Please set by choosing below`,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Defaults to button not disabled and empty error message text.
|
||||||
|
let isDisabled = false;
|
||||||
|
let errorText = '';
|
||||||
|
|
||||||
|
if (s3Enabled) {
|
||||||
|
if (
|
||||||
|
(metricsTotalRetentionPeriod || metricsS3RetentionPeriod) &&
|
||||||
|
Number(metricsTotalRetentionPeriod) < Number(metricsS3RetentionPeriod)
|
||||||
|
) {
|
||||||
|
isDisabled = true;
|
||||||
|
errorText = messages.compareError('metrics');
|
||||||
|
} else if (
|
||||||
|
(tracesTotalRetentionPeriod || tracesS3RetentionPeriod) &&
|
||||||
|
Number(tracesTotalRetentionPeriod) < Number(tracesS3RetentionPeriod)
|
||||||
|
) {
|
||||||
|
isDisabled = true;
|
||||||
|
errorText = messages.compareError('traces');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!metricsTotalRetentionPeriod || !tracesTotalRetentionPeriod) {
|
||||||
|
isDisabled = true;
|
||||||
|
if (!metricsTotalRetentionPeriod && !tracesTotalRetentionPeriod) {
|
||||||
|
errorText = messages.nullValueError('metrics and traces');
|
||||||
|
} else if (!metricsTotalRetentionPeriod) {
|
||||||
|
errorText = messages.nullValueError('metrics');
|
||||||
|
} else if (!tracesTotalRetentionPeriod) {
|
||||||
|
errorText = messages.nullValueError('traces');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [isDisabled, errorText];
|
||||||
|
}, [
|
||||||
|
metricsS3RetentionPeriod,
|
||||||
|
metricsTotalRetentionPeriod,
|
||||||
|
s3Enabled,
|
||||||
|
tracesS3RetentionPeriod,
|
||||||
|
tracesTotalRetentionPeriod,
|
||||||
|
]);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return <Typography>{errorMessage}</Typography>;
|
return <Typography>{errorMessage}</Typography>;
|
||||||
}
|
}
|
||||||
@ -179,31 +270,6 @@ function GeneralSettings(): JSX.Element {
|
|||||||
return <Spinner tip="Loading.." height="70vh" />;
|
return <Spinner tip="Loading.." height="70vh" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getErrorText = (): string => {
|
|
||||||
const getValue = (value: string): string =>
|
|
||||||
`Retention Peroid for ${value} is not set yet. Please set by choosing below`;
|
|
||||||
|
|
||||||
if (!isDefaultMetrics && !isDefaultTrace) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefaultMetrics && !isDefaultTrace) {
|
|
||||||
return `${getValue('Metrics')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDefaultMetrics && isDefaultTrace) {
|
|
||||||
return `${getValue('Trace')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${getValue('Trace , Metrics')}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isDisabledHandler = (): boolean => {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const errorText = getErrorText();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col xs={24} md={22} xl={20} xxl={18} style={{ margin: 'auto' }}>
|
<Col xs={24} md={22} xl={20} xxl={18} style={{ margin: 'auto' }}>
|
||||||
{Element}
|
{Element}
|
||||||
@ -228,14 +294,14 @@ function GeneralSettings(): JSX.Element {
|
|||||||
/>
|
/>
|
||||||
</ToolTipContainer>
|
</ToolTipContainer>
|
||||||
)}
|
)}
|
||||||
<Row justify="space-around">
|
<Row justify="space-around" style={{ gap: '4%' }}>
|
||||||
{renderConfig.map((category): JSX.Element | null => {
|
{/* {renderConfig.map((category): JSX.Element | null => {
|
||||||
if (
|
if (
|
||||||
Array.isArray(category.retentionFields) &&
|
Array.isArray(category.retentionFields) &&
|
||||||
category.retentionFields.length > 0
|
category.retentionFields.length > 0
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<Col flex="48%" style={{ minWidth: 500 }} key={category.name}>
|
<Col flex="40%" style={{ minWidth: 475 }} key={category.name}>
|
||||||
<Typography.Title level={3}>{category.name}</Typography.Title>
|
<Typography.Title level={3}>{category.name}</Typography.Title>
|
||||||
|
|
||||||
{category.retentionFields.map((retentionField) => (
|
{category.retentionFields.map((retentionField) => (
|
||||||
@ -251,7 +317,8 @@ function GeneralSettings(): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
})}
|
})} */}
|
||||||
|
{renderConfig}
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
@ -272,11 +339,7 @@ function GeneralSettings(): JSX.Element {
|
|||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<ButtonContainer>
|
<ButtonContainer>
|
||||||
<Button
|
<Button onClick={onClickSaveHandler} disabled={isDisabled} type="primary">
|
||||||
onClick={onClickSaveHandler}
|
|
||||||
disabled={isDisabledHandler()}
|
|
||||||
type="primary"
|
|
||||||
>
|
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonContainer>
|
</ButtonContainer>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
export interface Props {
|
export interface Props {
|
||||||
metrics_ttl_duration_hrs: number;
|
type: 'metrics' | 'traces';
|
||||||
metrics_move_ttl_duration_hrs: number;
|
totalDuration: string;
|
||||||
traces_ttl_duration_hrs: number;
|
coldStorage?: 's3' | null;
|
||||||
traces_move_ttl_duration_hrs: number;
|
toColdDuration?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PayloadProps {
|
export interface PayloadProps {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user