trust-module-frontend/src/Charts/PrometheusChart.jsx

143 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import React, { useEffect, useState, useRef } from 'react';
import axios from 'axios';
import LineChartComponent from './Components/LineChartComponent';
const MAX_POINTS = 20; // Ограничение точек на графике
const COLORS = ['#3e95cd', '#8e5ea2', '#3cba9f', '#e8c3b9', '#c45850']; // Фиксированные цвета для линий
// Список временных диапазонов и интервалов обновления
const TIME_RANGES = [
{ label: '1 минута', value: 60, interval: 3000 },
{ label: '5 минут', value: 300, interval: 15000 },
{ label: '30 минут', value: 1800, interval: 90000 },
{ label: '1 час', value: 3600, interval: 180000 },
{ label: '3 часа', value: 10800, interval: 540000 },
{ label: '6 часов', value: 21600, interval: 1080000 },
{ label: '12 часов', value: 43200, interval: 2160000 },
{ label: '24 часа', value: 86400, interval: 4320000 },
{ label: '2 дня', value: 172800, interval: 8640000 },
{ label: '7 дней', value: 604800, interval: 30240000 },
{ label: '30 дней', value: 2592000, interval: 129600000 },
{ label: '90 дней', value: 7776000, interval: 388800000 },
{ label: '6 месяцев', value: 15552000, interval: 777600000 },
{ label: '9 месяцев', value: 23328000, interval: 1166400000 },
{ label: '1 год', value: 31536000, interval: 1576800000 },
];
const PrometheusChart = ({ metricName }) => {
const [chartData, setChartData] = useState({});
const [metricType, setMetricType] = useState('');
const [metricDescription, setMetricDescription] = useState('');
const [selectedRange, setSelectedRange] = useState(TIME_RANGES[0]); // По умолчанию 1 минута
const intervalRef = useRef(null);
const fetchData = async () => {
try {
const end = Math.floor(Date.now() / 1000);
const start = end - selectedRange.value;
// Динамический шаг (чем больше диапазон, тем больше шаг)
let step;
if (selectedRange.value <= 3600) step = 5; // 1 час и меньше → 5 сек
else if (selectedRange.value <= 21600) step = 30; // 1-6 часов → 30 сек
else if (selectedRange.value <= 86400) step = 120; // 6-24 часа → 2 минуты
else step = 300; // > 24 часов → 5 минут
console.log(`Запрашиваем данные с шагом ${step} сек`);
const response = await axios.get(`http://192.168.2.39:3000/metrics`, {
params: { metric: metricName, start, end, step },
});
const result = response.data;
let metrics = Array.isArray(result) ? result : result.data || [];
if (!Array.isArray(metrics) || metrics.length === 0) {
console.warn('No metrics data available, filling with empty values.');
metrics = [];
}
// 1. Генерация временных точек с учетом диапазона
const timePoints = [];
for (let t = start; t <= end; t += step) {
const date = new Date(t * 1000);
const formattedTime = selectedRange.value > 86400
? date.toLocaleString([], { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' })
: date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
timePoints.push(formattedTime);
}
// 2. Обработка данных
const updatedData = {};
metrics.forEach(m => {
const date = new Date(m.timestamp);
const formattedTime = selectedRange.value > 86400
? date.toLocaleString([], { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' })
: date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
const key = `${m.instance}-${m.device || m.scrape_job}`;
if (!updatedData[key]) updatedData[key] = {};
updatedData[key][formattedTime] = m.value;
});
// 3. Заполнение пропусков
const chartData = {};
Object.keys(updatedData).forEach(key => {
chartData[key] = timePoints.map(time => ({
time,
value: updatedData[key][time] ?? null,
}));
});
setChartData(chartData);
} catch (error) {
console.error('Ошибка при загрузке метрик:', error);
}
};
useEffect(() => {
fetchData(); // Первоначальная загрузка данных
intervalRef.current = setInterval(() => {
fetchData();
}, selectedRange.interval); // Обновляем с выбранным интервалом
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current); // Очищаем интервал при размонтировании
}
};
}, [metricName, selectedRange]); // Зависимость от metricName и selectedRange
const handleRangeChange = (event) => {
const selectedValue = event.target.value;
const range = TIME_RANGES.find(range => range.value === parseInt(selectedValue, 10));
setSelectedRange(range);
};
if (!Object.keys(chartData).length) return <p>Loading...</p>;
return (
<div>
<div>
<label htmlFor="time-range">Выберите временной диапазон: </label>
<select id="time-range" value={selectedRange.value} onChange={handleRangeChange}>
{TIME_RANGES.map(range => (
<option key={range.value} value={range.value}>{range.label}</option>
))}
</select>
</div>
<LineChartComponent
chartData={chartData}
metricName={metricName}
metricType={metricType}
colors={COLORS}
description={metricDescription}
/>
</div>
);
};
export default PrometheusChart;