diff --git a/src/Charts2/Components/metricsService.jsx b/src/Charts2/Components/metricsService.jsx index 159d3a3..90d9261 100644 --- a/src/Charts2/Components/metricsService.jsx +++ b/src/Charts2/Components/metricsService.jsx @@ -26,8 +26,11 @@ class MetricsService { this.socket.on('connect', () => { console.log('WebSocket connected'); - this.subscriptions.forEach((_, metric) => { - this.socket.emit('subscribe-metric', { metric }); + // Восстанавливаем подписки при переподключении + this.subscriptions.forEach((_, metricKey) => { + const [metric, query] = metricKey.split('?'); + const filters = this.parseFiltersFromKey(metricKey); + this.socket.emit('subscribe-metric', { metric, filters }); }); }); @@ -83,35 +86,53 @@ class MetricsService { }); } - subscribeToMetric(metric, callback, interval = 5000, filters = {}) { + subscribeToMetric(metricKey, callback, interval = 5000, filters = {}) { this.connectWebSocket(); - const alreadySubscribed = this.subscriptions.has(metric); - const callbacks = this.subscriptions.get(metric) || []; + const alreadySubscribed = this.subscriptions.has(metricKey); + const callbacks = this.subscriptions.get(metricKey) || []; callbacks.push(callback); - this.subscriptions.set(metric, callbacks); + this.subscriptions.set(metricKey, callbacks); if (!alreadySubscribed) { - this.socket.emit('subscribe-metric', { metric, interval, filters }); + // Разделяем metricKey на метрику и фильтры + const [metric] = metricKey.split('?'); + this.socket.emit('subscribe-metric', { + metric, + interval, + filters + }); } - return () => this.unsubscribeFromMetric(metric, callback); + return () => this.unsubscribeFromMetric(metricKey, callback); } - unsubscribeFromMetric(metric, callback) { - const callbacks = this.subscriptions.get(metric) || []; + unsubscribeFromMetric(metricKey, callback) { + const callbacks = this.subscriptions.get(metricKey) || []; const filtered = callbacks.filter(cb => cb !== callback); if (filtered.length === 0) { - this.subscriptions.delete(metric); + this.subscriptions.delete(metricKey); if (this.socket && this.socket.connected) { + const [metric] = metricKey.split('?'); this.socket.emit('unsubscribe-metric', { metric }); } } else { - this.subscriptions.set(metric, filtered); + this.subscriptions.set(metricKey, filtered); } } + parseFiltersFromKey(metricKey) { + const parts = metricKey.split('?'); + if (parts.length < 2) return {}; + + return parts[1].split('&').reduce((acc, pair) => { + const [key, value] = pair.split('='); + if (key && value) acc[key] = value; + return acc; + }, {}); + } + cleanupAll() { if (this.socket && this.socket.connected) { this.socket.emit('unsubscribe-all'); @@ -128,4 +149,7 @@ class MetricsService { } } -export const metricsService = new MetricsService(import.meta.env.VITE_BACK_URL); +// Создаем экземпляр сервиса +const metricsService = new MetricsService(import.meta.env.VITE_BACK_URL); + +export default metricsService; \ No newline at end of file diff --git a/src/Charts2/PrometheusChart.jsx b/src/Charts2/PrometheusChart.jsx index 33b711e..5d7fe46 100644 --- a/src/Charts2/PrometheusChart.jsx +++ b/src/Charts2/PrometheusChart.jsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import LineChartComponent from './Components/LineChartComponent'; import DateRangeSelector from './Components/DateRangeSelector'; -import { metricsService } from './Components/metricsService'; +import metricsService from './Components/metricsService'; import { Button, Radio, message, Tag } from 'antd'; import moment from 'moment'; @@ -11,14 +11,10 @@ const PrometheusChart = ({ metricInfo, chartHeight = 560 }) => { filters = {}, title = metricName, description, - context = {} // Добавляем контекст из path + context = {} } = metricInfo || {}; - console.log("⚙️ PrometheusChart -> metricInfo:", metricInfo); - console.log("📌 Контекст -> device:", context.device, "source_id:", context.source_id, "deviceId:", context.deviceId); - - // Получаем полный контекст из родительских элементов - const { device, source_id: module, deviceId, parent } = context; + const { device, source_id: module } = context; const [chartData, setChartData] = useState([]); const [isLoading, setIsLoading] = useState(true); @@ -29,9 +25,11 @@ const PrometheusChart = ({ metricInfo, chartHeight = 560 }) => { const [endDate, setEndDate] = useState(moment().toDate()); const [isLiveUpdating, setIsLiveUpdating] = useState(false); - // Генерация уникального ключа для подписки const getSubscriptionKey = () => { - return `${metricName}_${device || 'all'}_${module || 'all'}_${deviceId || 'all'}`; + const filterParts = []; + if (device) filterParts.push(`device=${device}`); + if (module) filterParts.push(`source_id=${module}`); + return `${metricName}${filterParts.length ? `?${filterParts.join('&')}` : ''}`; }; const formatMetricData = (dataArray) => { @@ -48,25 +46,23 @@ const PrometheusChart = ({ metricInfo, chartHeight = 560 }) => { }; const fetchHistoricalData = async (start, end) => { - setIsLoading(true); - setError(null); + setIsLoading(true); + setError(null); - try { - const extendedFilters = { - ...filters, - ...(device && { device: device.toString() }), // убедитесь, что device строка - ...(source_id && { source_id: source_id.toString() }) - }; + try { + const extendedFilters = { + ...filters, + ...(device && { device: device.toString() }), + ...(module && { source_id: module.toString() }) + }; - console.log('Fetching with filters:', extendedFilters); // для отладки - - const data = await metricsService.fetchMetricsRange( - metricName, - Math.floor(start.getTime() / 1000), - Math.floor(end.getTime() / 1000), - 15, - extendedFilters - ); + const data = await metricsService.fetchMetricsRange( + metricName, + Math.floor(start.getTime() / 1000), + Math.floor(end.getTime() / 1000), + 15, + extendedFilters + ); const formattedData = formatMetricData(data); if (formattedData.length > 0) { @@ -97,24 +93,15 @@ const PrometheusChart = ({ metricInfo, chartHeight = 560 }) => { fetchHistoricalData(start, end).finally(() => setIsLoading(false)); return metricsService.subscribeToMetric( - getSubscriptionKey(), // Уникальный ключ для подписки + getSubscriptionKey(), (newData) => { - const filteredData = newData.filter(item => { - // Строгая проверка всех доступных фильтров - if (device && item.device?.trim() !== device) return false; - if (module && item.source_id !== module) return false; - return true; + const formattedData = formatMetricData(newData); + setChartData(prev => { + const newChartData = [...prev, ...formattedData] + .filter((v, i, a) => a.findIndex(t => t.timestamp === v.timestamp) === i) + .slice(-200); + return newChartData; }); - - if (filteredData.length > 0) { - const formattedData = formatMetricData(filteredData); - setChartData(prev => { - const newChartData = [...prev, ...formattedData] - .filter((v, i, a) => a.findIndex(t => t.timestamp === v.timestamp) === i) - .slice(-200); - return newChartData; - }); - } }, 5000, { @@ -151,17 +138,6 @@ const PrometheusChart = ({ metricInfo, chartHeight = 560 }) => { }; }, [mode, metricName, device, module]); - // Рекурсивно собираем путь для отображения - const getFullPath = () => { - const path = []; - let current = parent; - while (current) { - path.unshift(current.title); - current = current.parent; - } - return path.join(' > '); - }; - const metaInfo = [ metricMeta.instance && `Instance: ${metricMeta.instance}`, metricMeta.job && `Job: ${metricMeta.job}`, @@ -203,14 +179,8 @@ const PrometheusChart = ({ metricInfo, chartHeight = 560 }) => { )} - {/* Отображаем полный путь к метрике */} - {parent && ( -