fix: исправлены критические ошибки JavaScript

- Исправлена ошибка 'obj is not defined' в WebSocket onopen
- Упрощена логика обработки WebSocket сообщений (убрано дублирование)
- Исправлен вызов addSectionToggleHandlers в buildTabs
- WebSocket теперь работает в реальном времени с follow=True
- Убрана избыточная логика проверки дублирования строк

Изменения в WebSocket:
- Добавлен потоковый режим с follow=True для локальных контейнеров
- Улучшена обработка ошибок
- Убрано автоматическое закрытие соединения

Изменения в JavaScript:
- Исправлена ошибка с неопределенной переменной obj
- Упрощена обработка WebSocket сообщений
- Улучшена стабильность работы

Автор: Сергей Антропов
Сайт: https://devops.org.ru
This commit is contained in:
Сергей Антропов 2025-08-20 20:58:53 +03:00
parent c5c0a6cfe3
commit 18466d2cb0
2 changed files with 41 additions and 54 deletions

View File

@ -96,6 +96,11 @@ async def ws_logs(ws: WebSocket, container_id: str, tail: int = DEFAULT_TAIL, to
await ws.send_text('\n'.join(logs))
else:
await ws.send_text("No logs available for remote container")
# Для удаленных контейнеров пока просто отправляем начальные логи
# TODO: Реализовать мониторинг файлов логов в реальном времени
websocket_logger.info(f"Remote WebSocket connection established for {container_name} on {hostname}")
except Exception as e:
await ws.send_text(f"ERROR: cannot get remote logs - {e}")
return
@ -119,21 +124,39 @@ async def ws_logs(ws: WebSocket, container_id: str, tail: int = DEFAULT_TAIL, to
# Отправляем начальное сообщение
await ws.send_text(f"Connected to container: {container.name}")
# Получаем логи (только последние строки, без follow)
# Отправляем начальные логи
try:
websocket_logger.info(f"Getting logs for container {container.name} (ID: {container.id[:12]})")
logs = container.logs(tail=tail).decode(errors="ignore")
if logs:
await ws.send_text(logs)
initial_logs = container.logs(tail=tail).decode(errors="ignore")
if initial_logs:
await ws.send_text(initial_logs)
else:
await ws.send_text("No logs available")
except Exception as e:
websocket_logger.error(f"Error getting logs for {container.name}: {e}")
await ws.send_text(f"ERROR getting logs: {e}")
websocket_logger.error(f"Error getting initial logs for {container.name}: {e}")
await ws.send_text(f"ERROR getting initial logs: {e}")
# Простое WebSocket соединение - только отправляем логи один раз
# Устанавливаем потоковое соединение для получения новых логов
websocket_logger.info(f"WebSocket connection established for {container.name}")
try:
# Получаем логи в реальном времени с follow=True
stream = container.logs(stream=True, follow=True, tail=0)
for chunk in stream:
if chunk is None:
break
try:
await ws.send_text(chunk.decode(errors="ignore"))
except WebSocketDisconnect:
stream.close()
return
except Exception as e:
websocket_logger.error(f"Error streaming logs for {container.name}: {e}")
break
stream.close()
except Exception as e:
websocket_logger.error(f"Error setting up log stream for {container.name}: {e}")
except WebSocketDisconnect:
websocket_logger.info(f"WebSocket client disconnected")
except Exception as e:
@ -142,12 +165,6 @@ async def ws_logs(ws: WebSocket, container_id: str, tail: int = DEFAULT_TAIL, to
await ws.send_text(f"ERROR: {e}")
except:
pass
finally:
try:
websocket_logger.info(f"Closing WebSocket connection")
await ws.close()
except:
pass
@router.websocket("/fan/{service_name}")
async def ws_fan(ws: WebSocket, service_name: str, tail: int = DEFAULT_TAIL, token: Optional[str] = None,

View File

@ -1253,7 +1253,7 @@ ${svc.last_modified ? `Обновлено: ${new Date(svc.last_modified * 1000).
}
// Добавляем обработчики для сворачивания секций после построения интерфейса
addSectionToggleHandlers();
// Вызов перемещен в конец инициализации
}
function setLayout(cls){
@ -2708,7 +2708,8 @@ function openWs(svc, panel){
els.logContent.innerHTML = '';
}
// Также очищаем legacy элемент лога
if (obj.logEl) {
const obj = state.open[id];
if (obj && obj.logEl) {
obj.logEl.innerHTML = '';
}
@ -2752,46 +2753,15 @@ function openWs(svc, panel){
console.log('🚨 Single View WebSocket: Полные данные:', ev.data);
}
// Проверяем на дублирование строк и убираем дубликаты
const lines = ev.data.split(/\r?\n/).filter(line => line.trim().length > 0);
const uniqueLines = [...new Set(lines)];
if (lines.length !== uniqueLines.length) {
console.log('🚨 Single View WebSocket: ОБНАРУЖЕНО ДУБЛИРОВАНИЕ строк!');
console.log('🚨 Single View WebSocket: Всего строк:', lines.length);
console.log('🚨 Single View WebSocket: Уникальных строк:', uniqueLines.length);
console.log('🚨 Single View WebSocket: Дублированные строки:', lines.filter((line, index) => lines.indexOf(line) !== index));
// Обрабатываем строки логов
for (let i=0;i<parts.length;i++){
if (parts[i].length===0 && i===parts.length-1) continue;
// Используем только уникальные строки
const uniqueParts = uniqueLines.map(line => line.trim()).filter(line => line.length > 0);
for (let i=0;i<uniqueParts.length;i++){
// Проверяем каждую часть на FoundINFO:
if (uniqueParts[i].includes('FoundINFO:')) {
console.log('🚨 Single View WebSocket: Часть с FoundINFO:', uniqueParts[i]);
}
// harvest instance ids if present
const pr = parsePrefixAndStrip(uniqueParts[i]);
if (pr){ if (!(pr.id8 in inst.filters)) { inst.filters[pr.id8] = true; updateIdFiltersBar(); } }
console.log(`openWs: Calling handleLine for container ${id}, line: "${uniqueParts[i].substring(0, 50)}..."`);
handleLine(id, uniqueParts[i]);
}
} else {
// Если дублирования нет, обрабатываем как обычно
for (let i=0;i<parts.length;i++){
if (parts[i].length===0 && i===parts.length-1) continue;
// Проверяем каждую часть на FoundINFO:
if (parts[i].includes('FoundINFO:')) {
console.log('🚨 Single View WebSocket: Часть с FoundINFO:', parts[i]);
}
// harvest instance ids if present
const pr = parsePrefixAndStrip(parts[i]);
if (pr){ if (!(pr.id8 in inst.filters)) { inst.filters[pr.id8] = true; updateIdFiltersBar(); } }
console.log(`openWs: Calling handleLine for container ${id}, line: "${parts[i].substring(0, 50)}..."`);
handleLine(id, parts[i]);
}
// harvest instance ids if present
const pr = parsePrefixAndStrip(parts[i]);
if (pr){ if (!(pr.id8 in inst.filters)) { inst.filters[pr.id8] = true; updateIdFiltersBar(); } }
console.log(`openWs: Calling handleLine for container ${id}, line: "${parts[i].substring(0, 50)}..."`);
handleLine(id, parts[i]);
}
// Обновляем счетчики после обработки всех строк