diff --git a/static/js/app.js b/static/js/app.js index a87eb1d..01b4bf5 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -2758,21 +2758,6 @@ async function loadHistoryResults(historyId) { // 显示结果 displayResults(result.data); - // 加载相关的查询日志 - try { - await loadQueryLogsByHistory(historyId); - // 自动切换到查询日志选项卡以显示关联信息 - const logsTab = document.getElementById('logs-tab'); - if (logsTab) { - // 添加一个小延迟确保结果已经显示 - setTimeout(() => { - logsTab.click(); - }, 500); - } - } catch (logError) { - console.warn('加载历史记录相关查询日志失败:', logError); - } - // 关闭历史记录modal const modal = bootstrap.Modal.getInstance(document.getElementById('queryHistoryModal')); if (modal) { @@ -2781,7 +2766,7 @@ async function loadHistoryResults(historyId) { const queryTypeDesc = (result.data.history_info && result.data.history_info.query_type === 'sharding') ? '分表查询' : '单表查询'; const historyName = (result.data.history_info && result.data.history_info.name) || '未知'; - showAlert('success', `${queryTypeDesc}历史记录结果 "${historyName}" 加载成功,查询日志已关联显示`); + showAlert('success', `${queryTypeDesc}历史记录结果 "${historyName}" 加载成功`); } else { showAlert('danger', result.error || '加载历史记录结果失败'); } @@ -3199,171 +3184,16 @@ function showAlert(type, message) { let allQueryLogs = []; // 存储所有日志 async function refreshQueryLogs() { - try { - const response = await fetch('/api/query-logs?grouped=true&from_db=true'); - const result = await response.json(); - - if (result.success && result.data) { - if (result.grouped) { - displayGroupedQueryLogs(result.data); - } else { - // 兼容旧版本的平铺显示 - allQueryLogs = result.data; - filterLogsByLevel(); - } - } else { - document.getElementById('query-logs').innerHTML = '
无法获取查询日志
'; - } - } catch (error) { - console.error('获取查询日志失败:', error); - document.getElementById('query-logs').innerHTML = '
获取查询日志失败
'; - } + // 这个函数现在不再使用,因为查询日志已经独立到模态框中 + // 如果需要刷新查询日志,请使用 refreshModalQueryLogs() + console.warn('refreshQueryLogs() 已弃用,请使用 refreshModalQueryLogs()'); } -// 显示分组查询日志 +// 显示分组查询日志 - 已弃用 function displayGroupedQueryLogs(groupedLogs) { - const container = document.getElementById('query-logs'); - - if (!groupedLogs || groupedLogs.length === 0) { - container.innerHTML = '
暂无查询日志
'; - return; - } - - let html = ''; - - // 为每个批次生成折叠面板 - groupedLogs.forEach((batchData, index) => { - const [batchId, logs] = batchData; - const isExpanded = index === groupedLogs.length - 1; // 默认展开最新批次 - const collapseId = `batch-${batchId}`; - - // 统计批次信息 - const logCounts = { - INFO: logs.filter(log => log.level === 'INFO').length, - WARNING: logs.filter(log => log.level === 'WARNING').length, - ERROR: logs.filter(log => log.level === 'ERROR').length - }; - - const totalLogs = logs.length; - const firstLog = logs[0]; - const lastLog = logs[logs.length - 1]; - const duration = firstLog && lastLog ? calculateDuration(firstLog.timestamp, lastLog.timestamp) : '0秒'; - - // 确定批次类型和状态 - const hasErrors = logCounts.ERROR > 0; - const hasWarnings = logCounts.WARNING > 0; - const batchStatus = hasErrors ? 'danger' : hasWarnings ? 'warning' : 'success'; - const batchIcon = hasErrors ? 'fas fa-times-circle' : hasWarnings ? 'fas fa-exclamation-triangle' : 'fas fa-check-circle'; - - // 提取查询类型 - const batchTypeMatch = firstLog?.message.match(/开始(\\w+)查询批次/); - const batchType = batchTypeMatch ? batchTypeMatch[1] : '未知'; - - html += ` -
-
-
-
- - ${batchType}查询批次 ${batchId} - ${totalLogs}条日志 -
-
- - ${duration} - -
- ${logCounts.INFO > 0 ? `${logCounts.INFO} INFO` : ''} - ${logCounts.WARNING > 0 ? `${logCounts.WARNING} WARN` : ''} - ${logCounts.ERROR > 0 ? `${logCounts.ERROR} ERROR` : ''} -
- -
-
-
-
-
-
- `; - - // 显示该批次的日志条目 - logs.forEach(log => { - const showInfo = document.getElementById('log-level-info').checked; - const showWarning = document.getElementById('log-level-warning').checked; - const showError = document.getElementById('log-level-error').checked; - - // 应用级别过滤 - let shouldShow = false; - switch(log.level) { - case 'INFO': shouldShow = showInfo; break; - case 'WARNING': shouldShow = showWarning; break; - case 'ERROR': shouldShow = showError; break; - default: shouldShow = true; - } - - if (!shouldShow) return; - - const levelClass = { - 'INFO': 'text-primary', - 'WARNING': 'text-warning', - 'ERROR': 'text-danger', - 'DEBUG': 'text-secondary' - }[log.level] || 'text-dark'; - - const levelIcon = { - 'INFO': 'fas fa-info-circle', - 'WARNING': 'fas fa-exclamation-triangle', - 'ERROR': 'fas fa-times-circle', - 'DEBUG': 'fas fa-bug' - }[log.level] || 'fas fa-circle'; - - // 改进SQL高亮显示 - let message = escapeHtml(log.message); - - // 高亮SQL查询语句 - if (message.includes('执行查询SQL:')) { - message = message.replace(/执行查询SQL: (SELECT.*?);/g, - '执行查询SQL:
$1;'); - } - - // 高亮重要信息 - message = message.replace(/(\\d+\\.\\d{3}秒)/g, '$1'); - message = message.replace(/(返回记录数=\\d+)/g, '$1'); - message = message.replace(/(执行时间=[\\d.]+秒)/g, '$1'); - - html += ` -
-
-
- - - [${log.level}] - -
${message}
-
- ${log.timestamp} -
-
- `; - }); - - html += ` -
-
-
-
- `; - }); - - container.innerHTML = html; - - // 自动滚动到最新批次 - if (groupedLogs.length > 0) { - const latestBatch = container.querySelector('.card:last-child'); - if (latestBatch) { - latestBatch.scrollIntoView({ behavior: 'smooth', block: 'end' }); - } - } + // 这个函数已弃用,查询日志现在使用独立模态框显示 + console.warn('displayGroupedQueryLogs() 已弃用,查询日志现在使用独立模态框显示'); + return; } // 计算持续时间 @@ -3387,6 +3217,27 @@ function calculateDuration(startTime, endTime) { } } +// 格式化日志消息 +function formatLogMessage(message) { + // HTML转义 + let formatted = escapeHtml(message); + + // 高亮SQL查询语句 + if (formatted.includes('执行查询SQL:')) { + formatted = formatted.replace(/执行查询SQL: (SELECT.*?);/g, + '执行查询SQL:
$1;'); + } + + // 高亮重要信息 + formatted = formatted.replace(/([\d.]+秒)/g, '$1'); + formatted = formatted.replace(/(返回记录数=\d+)/g, '$1'); + formatted = formatted.replace(/(执行时间=[\d.]+秒)/g, '$1'); + formatted = formatted.replace(/(分表索引=\d+)/g, '$1'); + formatted = formatted.replace(/(表名=\w+)/g, '$1'); + + return formatted; +} + function filterLogsByLevel() { // 刷新分组日志显示,应用过滤器 refreshQueryLogs(); @@ -3456,6 +3307,228 @@ async function cleanupOldLogs() { } } +// 显示查询日志对话框 +function showQueryLogsDialog() { + // 打开模态框 + const modal = new bootstrap.Modal(document.getElementById('queryLogsModal')); + modal.show(); + + // 加载查询日志 + refreshModalQueryLogs(); +} + +// 刷新模态框中的查询日志 +async function refreshModalQueryLogs() { + try { + const response = await fetch('/api/query-logs?grouped=true&from_db=true'); + const result = await response.json(); + + if (result.success && result.data) { + if (result.grouped) { + displayModalGroupedQueryLogs(result.data); + } else { + // 兼容旧版本的平铺显示 + displayModalQueryLogs(result.data); + } + } else { + document.getElementById('modal-query-logs').innerHTML = '
无法获取查询日志
'; + } + } catch (error) { + console.error('获取查询日志失败:', error); + document.getElementById('modal-query-logs').innerHTML = '
获取查询日志失败
'; + } +} + +// 在模态框中显示分组查询日志 +function displayModalGroupedQueryLogs(groupedLogs) { + const container = document.getElementById('modal-query-logs'); + + if (!groupedLogs || groupedLogs.length === 0) { + container.innerHTML = '
暂无查询日志
'; + return; + } + + let html = ''; + + // 为每个批次生成折叠面板 + groupedLogs.forEach((batchData, index) => { + const [batchId, logs] = batchData; + const isExpanded = index === groupedLogs.length - 1; // 默认展开最新批次 + const collapseId = `modal-batch-${batchId}`; + + // 统计批次信息 + const logCounts = { + INFO: logs.filter(log => log.level === 'INFO').length, + WARNING: logs.filter(log => log.level === 'WARNING').length, + ERROR: logs.filter(log => log.level === 'ERROR').length + }; + + const totalLogs = logs.length; + const firstLog = logs[0]; + const lastLog = logs[logs.length - 1]; + const duration = firstLog && lastLog ? calculateDuration(firstLog.timestamp, lastLog.timestamp) : '0秒'; + + // 确定批次类型和状态 + const hasErrors = logCounts.ERROR > 0; + const hasWarnings = logCounts.WARNING > 0; + const batchStatus = hasErrors ? 'danger' : hasWarnings ? 'warning' : 'success'; + const batchIcon = hasErrors ? 'fas fa-times-circle' : hasWarnings ? 'fas fa-exclamation-triangle' : 'fas fa-check-circle'; + + // 提取查询类型 + const batchTypeMatch = firstLog?.message.match(/开始(\w+)查询批次/); + const batchType = batchTypeMatch ? batchTypeMatch[1] : '未知'; + + // 检查是否有关联的历史记录ID + const historyId = firstLog?.history_id; + const historyBadge = historyId ? + ` + ID:${historyId} + + ` : ''; + + html += ` +
+
+
+
+ + ${batchType}查询批次 ${batchId} + ${totalLogs}条日志 + ${historyBadge} +
+
+ + ${duration} + +
+ ${logCounts.INFO > 0 ? `${logCounts.INFO} INFO` : ''} + ${logCounts.WARNING > 0 ? `${logCounts.WARNING} WARN` : ''} + ${logCounts.ERROR > 0 ? `${logCounts.ERROR} ERROR` : ''} +
+ +
+
+
+
+
+
+ `; + + // 显示该批次的日志条目 + logs.forEach(log => { + const showInfo = document.getElementById('modal-log-level-info').checked; + const showWarning = document.getElementById('modal-log-level-warning').checked; + const showError = document.getElementById('modal-log-level-error').checked; + + const shouldShow = (log.level === 'INFO' && showInfo) || + (log.level === 'WARNING' && showWarning) || + (log.level === 'ERROR' && showError); + + if (shouldShow) { + const levelClass = log.level === 'ERROR' ? 'danger' : + log.level === 'WARNING' ? 'warning' : 'info'; + const levelIcon = log.level === 'ERROR' ? 'fas fa-times-circle' : + log.level === 'WARNING' ? 'fas fa-exclamation-triangle' : 'fas fa-info-circle'; + + // 简化时间戳显示 + const timeOnly = log.timestamp.split(' ')[1] || log.timestamp; + + html += ` +
+
+ + ${log.level} + + + ${timeOnly} + +
+ ${formatLogMessage(log.message)} +
+
+
+ `; + } + }); + + html += ` +
+
+
+
+ `; + }); + + container.innerHTML = html; +} + +// 过滤模态框中的日志级别 +function filterModalLogsByLevel() { + // 刷新分组日志显示,应用过滤器 + refreshModalQueryLogs(); +} + +// 显示平铺的查询日志(兼容性) +function displayModalQueryLogs(logs) { + const container = document.getElementById('modal-query-logs'); + + if (!logs || logs.length === 0) { + container.innerHTML = '
暂无查询日志
'; + return; + } + + const showInfo = document.getElementById('modal-log-level-info').checked; + const showWarning = document.getElementById('modal-log-level-warning').checked; + const showError = document.getElementById('modal-log-level-error').checked; + + let html = '
'; + + logs.forEach(log => { + const shouldShow = (log.level === 'INFO' && showInfo) || + (log.level === 'WARNING' && showWarning) || + (log.level === 'ERROR' && showError); + + if (shouldShow) { + const levelClass = log.level === 'ERROR' ? 'danger' : + log.level === 'WARNING' ? 'warning' : 'info'; + const levelIcon = log.level === 'ERROR' ? 'fas fa-times-circle' : + log.level === 'WARNING' ? 'fas fa-exclamation-triangle' : 'fas fa-info-circle'; + + html += ` +
+
+ + ${log.level} + + ${log.timestamp} +
${formatLogMessage(log.message)}
+
+
+ `; + } + }); + + html += '
'; + container.innerHTML = html; +} + +// 从查询日志模态框中加载历史记录 +function loadHistoryFromLogs(historyId) { + // 先关闭查询日志模态框 + const logsModal = bootstrap.Modal.getInstance(document.getElementById('queryLogsModal')); + if (logsModal) { + logsModal.hide(); + } + + // 延迟一下再加载历史记录,确保模态框已关闭 + setTimeout(() => { + loadHistoryResults(historyId); + }, 300); +} + // 根据历史记录ID获取相关查询日志 async function loadQueryLogsByHistory(historyId) { try { diff --git a/templates/db_compare.html b/templates/db_compare.html index 58b0cb1..de3ce57 100644 --- a/templates/db_compare.html +++ b/templates/db_compare.html @@ -327,12 +327,17 @@
-
+
-
+
+ +
+
@@ -615,11 +620,6 @@ 比较总结 -
- - -
-
-
-
查询执行日志
-
- - -
-
- - -
-
- - -
-
-
- - - -
-
-
- -
-
@@ -727,6 +692,56 @@ + + +