diff --git a/templates/index.html b/templates/index.html
index bd72d5d..1fcf188 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -2148,6 +2148,9 @@ async function setupMultiView() {
});
console.log(`setupMultiView: Multi-view setup completed for ${state.selectedContainers.length} containers`);
+
+ // Обновляем счетчики для multi view
+ await updateMultiViewCounters();
}
function createMultiViewPanel(service) {
@@ -2181,6 +2184,8 @@ function createMultiViewPanel(service) {
function openMultiViewWs(service) {
const containerId = service.id;
console.log(`openMultiViewWs: Starting WebSocket setup for ${service.name} (${containerId})`);
+ console.log(`openMultiViewWs: Current multiViewMode: ${state.multiViewMode}`);
+ console.log(`openMultiViewWs: Selected containers: ${state.selectedContainers.join(', ')}`);
// Закрываем существующее соединение
closeWs(containerId);
@@ -2379,6 +2384,9 @@ async function sendSnapshot(id){
function openWs(svc, panel){
const id = svc.id;
+ console.log(`openWs: Called for ${svc.name} (${id}) in multiViewMode: ${state.multiViewMode}`);
+ console.log(`openWs: Selected containers: ${state.selectedContainers.join(', ')}`);
+
const logEl = panel.querySelector('.log');
const wrapEl = panel.querySelector('.logwrap');
@@ -2494,15 +2502,41 @@ function handleLine(id, line){
const multiViewLog = document.querySelector(`.multi-view-log[data-container-id="${id}"]`);
if (multiViewLog) {
if (shouldShow) {
+ // Применяем ограничение tail lines в multi view
+ const tailLines = parseInt(els.tail.value) || 50;
+
+ // Добавляем новую строку
multiViewLog.insertAdjacentHTML('beforeend', html);
+
+ // Ограничиваем количество отображаемых строк
+ const logLines = Array.from(multiViewLog.querySelectorAll('.line'));
+ if (logLines.length > tailLines) {
+ // Удаляем лишние строки с начала
+ const linesToRemove = logLines.length - tailLines;
+ console.log(`handleLine: Trimming ${linesToRemove} lines from container ${id} (tail: ${tailLines})`);
+
+ // Удаляем первые N строк
+ logLines.slice(0, linesToRemove).forEach(line => {
+ line.remove();
+ });
+ }
+
if (els.autoscroll && els.autoscroll.checked) {
multiViewLog.scrollTop = multiViewLog.scrollHeight;
}
- console.log(`handleLine: Updated multi-view for container ${id}, log element found: true`);
+ console.log(`handleLine: Updated multi-view for container ${id}, log element found: true, tail lines: ${tailLines}`);
}
} else {
console.error(`handleLine: Multi-view log element not found for container ${id}`);
}
+
+ // Обновляем счетчики в multi view периодически (каждые 10 строк)
+ if (!state.multiViewCounterUpdateTimer) {
+ state.multiViewCounterUpdateTimer = setTimeout(() => {
+ updateMultiViewCounters();
+ state.multiViewCounterUpdateTimer = null;
+ }, 1000); // Обновляем каждую секунду
+ }
}
}
@@ -2794,6 +2828,61 @@ async function updateCounters(containerId) {
}
}
+// Функция для обновления счетчиков в multi view (суммирует статистику всех контейнеров)
+async function updateMultiViewCounters() {
+ if (!state.multiViewMode || state.selectedContainers.length === 0) {
+ return;
+ }
+
+ try {
+ console.log('Updating multi-view counters for containers:', state.selectedContainers);
+
+ // Суммируем статистику всех выбранных контейнеров
+ let totalDebug = 0;
+ let totalInfo = 0;
+ let totalWarn = 0;
+ let totalError = 0;
+
+ // Получаем статистику для каждого контейнера
+ for (const containerId of state.selectedContainers) {
+ try {
+ const response = await fetch(`/api/logs/stats/${containerId}`);
+ if (response.ok) {
+ const stats = await response.json();
+ totalDebug += stats.debug || 0;
+ totalInfo += stats.info || 0;
+ totalWarn += stats.warn || 0;
+ totalError += stats.error || 0;
+ }
+ } catch (error) {
+ console.error(`Error fetching stats for container ${containerId}:`, error);
+ }
+ }
+
+ // Обновляем счетчики в интерфейсе
+ const cdbg = document.querySelector('.cdbg');
+ const cinfo = document.querySelector('.cinfo');
+ const cwarn = document.querySelector('.cwarn');
+ const cerr = document.querySelector('.cerr');
+
+ if (cdbg) cdbg.textContent = totalDebug;
+ if (cinfo) cinfo.textContent = totalInfo;
+ if (cwarn) cwarn.textContent = totalWarn;
+ if (cerr) cerr.textContent = totalError;
+
+ console.log('Multi-view counters updated:', { totalDebug, totalInfo, totalWarn, totalError });
+
+ // Обновляем видимость счетчиков
+ updateCounterVisibility();
+
+ // Добавляем обработчики для счетчиков
+ addCounterClickHandlers();
+
+ } catch (error) {
+ console.error('Error updating multi-view counters:', error);
+ }
+}
+
// Функция для обновления видимости счетчиков
function updateCounterVisibility() {
const debugBtn = document.querySelector('.debug-btn');
@@ -2821,10 +2910,8 @@ async function refreshLogsAndCounters() {
// Обновляем мультипросмотр
console.log('Refreshing multi-view for containers:', state.selectedContainers);
- // Обновляем счетчики для всех выбранных контейнеров
- for (const containerId of state.selectedContainers) {
- await updateCounters(containerId);
- }
+ // Обновляем счетчики для всех выбранных контейнеров (суммируем статистику)
+ await updateMultiViewCounters();
// Перезапускаем WebSocket соединения для всех выбранных контейнеров
state.selectedContainers.forEach(containerId => {
@@ -3203,10 +3290,20 @@ if (els.tail) {
Object.keys(state.open).forEach(id=>{
const svc = state.services.find(s=> s.id===id);
if (!svc) return;
- const panel = els.grid.querySelector(`.panel[data-cid="${id}"]`);
- if (!panel) return;
- state.open[id].logEl.textContent='';
- closeWs(id); openWs(svc, panel);
+
+ // В multi view режиме используем openMultiViewWs
+ if (state.multiViewMode && state.selectedContainers.includes(id)) {
+ console.log(`Refresh: Using openMultiViewWs for ${svc.name} in multi view mode`);
+ closeWs(id);
+ openMultiViewWs(svc);
+ } else {
+ // В обычном режиме используем openWs
+ const panel = els.grid.querySelector(`.panel[data-cid="${id}"]`);
+ if (!panel) return;
+ state.open[id].logEl.textContent='';
+ closeWs(id);
+ openWs(svc, panel);
+ }
});
// Обновляем современный интерфейс
@@ -3407,6 +3504,64 @@ window.addEventListener('keydown', async (e)=>{
const containerId = e.target.getAttribute('data-container-id');
toggleContainerSelection(containerId);
}
+
+ // Обработчик изменения tail lines
+ if (e.target.id === 'tail') {
+ console.log('Tail lines changed to:', e.target.value);
+ if (state.multiViewMode) {
+ // В multi view применяем новое ограничение к уже отображаемым логам
+ const tailLines = parseInt(e.target.value) || 50;
+ console.log(`Applying tail lines limit ${tailLines} to ${state.selectedContainers.length} containers:`, state.selectedContainers);
+
+ // Проверяем все элементы multi-view-log на странице
+ const allMultiViewLogs = document.querySelectorAll('.multi-view-log');
+ console.log(`Found ${allMultiViewLogs.length} multi-view-log elements on page:`, Array.from(allMultiViewLogs).map(el => el.getAttribute('data-container-id')));
+
+ state.selectedContainers.forEach(containerId => {
+ console.log(`Processing container ${containerId}...`);
+
+ // Ищем элемент несколькими способами
+ let multiViewLog = document.querySelector(`.multi-view-log[data-container-id="${containerId}"]`);
+
+ if (!multiViewLog) {
+ console.warn(`Container ${containerId} not found with data-container-id, trying alternative search...`);
+ // Попробуем найти по другому селектору
+ multiViewLog = document.querySelector(`[data-container-id="${containerId}"]`);
+ }
+
+ if (multiViewLog) {
+ console.log(`Found multi-view-log for container ${containerId}, current lines:`, multiViewLog.querySelectorAll('.line').length);
+
+ // Получаем все строки логов
+ const logLines = Array.from(multiViewLog.querySelectorAll('.line'));
+ console.log(`Container ${containerId}: ${logLines.length} log lines found`);
+
+ if (logLines.length > tailLines) {
+ // Удаляем лишние строки с начала
+ const linesToRemove = logLines.length - tailLines;
+ console.log(`Removing ${linesToRemove} lines from container ${containerId}`);
+
+ // Удаляем первые N строк
+ logLines.slice(0, linesToRemove).forEach(line => {
+ line.remove();
+ });
+
+ const remainingLines = multiViewLog.querySelectorAll('.line').length;
+ console.log(`Container ${containerId} now has ${remainingLines} lines after trimming`);
+ } else {
+ console.log(`Container ${containerId} has ${logLines.length} lines, no trimming needed (limit: ${tailLines})`);
+ }
+ } else {
+ console.error(`Multi-view log element not found for container ${containerId}`);
+ console.error(`Available multi-view-log elements:`, Array.from(document.querySelectorAll('.multi-view-log')).map(el => ({
+ containerId: el.getAttribute('data-container-id'),
+ className: el.className,
+ parent: el.parentElement?.className
+ })));
+ }
+ });
+ }
+ }
});
// Добавляем обработчики кликов на label чекбоксов