背景
细节可以参考这篇文章: 与copilot 结对编程系列 - log日志重复性检测 - 第1篇 - 总体介绍及效果展示
本文主要将数据库中存储的数据通过网页调用并展示出来, 以下是对详细解释。
web框架选择
当前场景使用 Flask 来展示网页信息.
主要原因如下:
- 轻量级和易于使用:Flask 是一个轻量级的 Web 框架,易于设置和使用。它允许开发者快速构建和部署 Web 应用程序,而不需要复杂的配置。
- 模板渲染:Flask 提供了强大的模板引擎 Jinja2,可以方便地将 Python 数据传递到 HTML 模板中进行渲染。在
result.html
文件中,使用了 Jinja2 模板语法(如{{ log_results | tojson | safe }}
)来将后端数据传递到前端。 - 路由管理:Flask 提供了简单的路由机制,可以轻松地将 URL 映射到特定的函数。在
app.py
文件中,可以定义不同的路由来处理不同的请求,并返回相应的 HTML 页面或数据。 - 数据处理:在
database_query.py
等脚本中,可以使用 Flask 处理从数据库中查询的数据,并将其传递到前端进行展示。Flask 可以与各种数据库(如 SQLite、MySQL、PostgreSQL)无缝集成。 - 扩展性:Flask 拥有丰富的扩展库,可以轻松地添加各种功能,如表单处理、用户认证、文件上传等。开发者可以根据需要选择合适的扩展来增强应用的功能。
- 开发和调试:Flask 提供了内置的开发服务器和调试工具,可以方便地进行本地开发和调试。开发者可以快速迭代和测试代码,提升开发效率。
综上所述,Flask 作为一个轻量级且功能强大的 Web 框架,非常适合用于当前场景中展示网页信息的需求。
具体实现
ui_interface.py
这是一个 Flask 应用程序
它通过前端表单接收用户输入的数据,调用数据库接口进行查询,然后将处理后的结果展示在页面上。以下是详细的步骤:
-
接收前端数据:
- 用户在前端表单中输入数据并提交表单。
- 表单数据通过 POST 请求发送到服务器端的
/query
路由。
-
处理请求:
- 在
/query
路由中,使用request.form
获取表单数据。 - 根据表单数据中的
query_type
字段,选择相应的数据库查询函数。
- 在
-
调用数据库接口:
- 根据
query_type
,调用database_query
模块中的相应函数进行数据库查询。 - 查询函数返回查询结果
log_results
和摘要结果summary_result
。
- 根据
-
处理查询结果:
- 使用
process_json
函数对查询结果进行处理,添加前缀到键名。 - 将处理后的结果存储在 Flask 的
session
中,以便后续使用。
- 使用
-
展示结果:
- 将处理后的查询结果传递给模板引擎
render_template
,渲染result.html
页面。 - 在
result.html
页面中展示查询结果。
- 将处理后的查询结果传递给模板引擎
以下是代码中的关键部分:
@app.route('/query', methods=['POST'])
def query_result():
# 获取表单数据
query_type = request.form['query_type']
log_level = request.form.get('log_level')
log_type = request.form.get('log_type')
limit = request.form.get('limit')
log_procedure = request.form.get('log_procedure')
file_line = request.form.get('file_line')
order_by_field = request.form.get('order')
sct_case_name = request.form.get('sct_case_name')
# 根据 query_type 调用相应的数据库查询函数
query_functions = {
'query_single_sct_case': lambda: ds.query_single_sct_case(sct_case_name),
'query_top_sct_cases': lambda: (ds.query_top_sct_cases(log_level, log_type, limit), {}),
'query_log_types_ranking': lambda: (ds.query_log_types_ranking(log_level), {}),
'query_top_log': lambda: (ds.query_top_log(log_procedure, log_level, log_type, limit, order_by_field), {}),
'query_specific_log': lambda: (ds.query_specific_log(file_line, limit), {}),
'query_logs_by_type': lambda: (ds.query_logs_by_type(log_type, limit), {}),
'query_pet_log_type': lambda: (ds.query_pet_log_type(), {}),
'query_pet_top_log_ranking': lambda: (ds.query_pet_top_log_ranking(log_procedure, log_level, log_type, limit), {})
}
# 执行查询函数
log_results, summary_result = query_functions.get(query_type, lambda: ({}, {}))()
# 处理查询结果
log_results = process_json(log_results)
summary_result = process_json(summary_result) if summary_result else {}
# 将结果存储在 session 中
session['log_results'] = log_results
session['summary_result'] = summary_result
# 渲染结果页面
return render_template('result.html', query_type=query_type, log_results=log_results, summary_result=summary_result)
通过上述步骤,脚本实现了从前端接收数据、调用数据库接口、处理查询结果并展示在页面上的完整流程。
index.html
这个 index.html
文件是一个前端页面,主要用于提供一个查询接口。它的主要功能和作用如下:
-
页面结构和样式:
- 使用 HTML 和 CSS 定义了页面的基本结构和样式。
- 页面包含一个标题、一个表单和一个计时器显示区域。
- 表单包含两个下拉菜单(查询类别和查询类型)和一个动态参数容器。
-
动态表单生成:
- 根据用户选择的查询类别和查询类型,动态生成表单参数。
- 使用 JavaScript 脚本,根据预定义的
queryOptions
和queryParams
对象,动态更新查询类型选项和参数输入字段。
-
JavaScript 脚本:
updateQueryTypeOptions()
:根据选择的查询类别,更新查询类型的下拉菜单选项。
function updateQueryTypeOptions() {
const queryCategory = document.getElementById('query_category').value;
const queryTypeSelect = document.getElementById('query_type');
queryTypeSelect.innerHTML = '';
queryOptions[queryCategory].forEach(option => {
const opt = document.createElement('option');
opt.value = option.value;
opt.textContent = option.text;
queryTypeSelect.appendChild(opt);
});
showParams();
}
showParams()
:根据选择的查询类别和查询类型,动态生成相应的参数输入字段。
function showParams() {
const queryCategory = document.getElementById('query_category').value;
const queryType = document.getElementById('query_type').value;
const paramsContainer = document.getElementById('params_container');
paramsContainer.innerHTML = '';
const params = queryParams[`${queryCategory}_${queryType}`];
if (params) {
params.forEach(param => {
const label = document.createElement('label');
label.setAttribute('for', param.id);
label.textContent = param.label;
paramsContainer.appendChild(label);
if (param.type === 'select') {
const select = document.createElement('select');
select.id = param.id;
select.name = param.name;
param.options.forEach(option => {
const opt = document.createElement('option');
opt.value = option;
opt.textContent = option;
select.appendChild(opt);
});
paramsContainer.appendChild(select);
} else {
const input = document.createElement('input');
input.type = param.type;
input.id = param.id;
input.name = param.name;
if (param.value) {
input.value = param.value;
}
paramsContainer.appendChild(input);
}
});
}
}
startTimer()
:在表单提交时启动一个计时器,显示查询时间,并禁用提交按钮以防止重复提交。
function startTimer() {
const submitButton = document.querySelector('input[type="submit"]');
submitButton.disabled = true;
const timerElement = document.getElementById('timer');
const startTime = Date.now();
setInterval(() => {
const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(1);
timerElement.textContent = 'Query time: ' + elapsedTime + ' seconds';
}, 100);
return true; // Allow form submission
}
window.onload
:页面加载时,默认选择SCT
查询类别并更新查询类型选项。
window.onload = function() {
document.getElementById('query_category').value = 'SCT';
updateQueryTypeOptions();
};
- 与 Flask 的集成:
- 表单的
action
属性指向/query
,使用POST
方法提交数据,这是一个 Flask 路由,用于处理查询请求。 - Flask 后端会接收表单提交的数据,处理查询逻辑,并返回结果。
- 表单的
总结来说,这个文件主要用于提供一个用户界面,让用户选择查询类别和类型,并输入相应的参数,然后提交查询请求到 Flask 后端进行处理。
results.html
这个 result.html
文件是一个 HTML 模板文件,通常用于 Flask 应用中,用来展示查询结果。以下是这个文件的主要作用和功能:
-
页面结构和样式:
- 使用 HTML 和 CSS 定义了页面的结构和样式。
- 包含一个标题 “Query Result”。
- 定义了一些样式规则,使页面看起来更美观,例如背景颜色、字体、表格样式等。
-
数据处理和展示:
- 使用 JavaScript 函数
removePrefixFromKeys
去除数据键中的前缀。 - 使用
generateTable
和generateSingleRowTable
函数生成 HTML 表格,用于展示查询结果。 - 将处理后的数据插入到页面的特定容器中 (
log-results-container
和summary-results-container
)。
- 使用 JavaScript 函数
-
导出功能:
- 提供了一个链接,允许用户将查询结果导出为 Excel 文件。
-
图表展示:
- 如果查询类型是
query_log_types_ranking
或query_pet_log_type
,则会生成一个饼图来展示日志类型的排名。 - 使用 Chart.js 库生成图表,并对图表进行了一些自定义设置,例如颜色、图例等。
- 如果查询类型是
-
模板引擎:
- 使用了 Jinja2 模板引擎的语法(例如
{{ log_results | tojson | safe }}
和{% if query_type == 'query_log_types_ranking' or query_type == 'query_pet_log_type' %}
)来动态渲染数据和条件内容。
- 使用了 Jinja2 模板引擎的语法(例如
这个文件的主要作用是展示查询结果,包括表格和图表,并提供导出功能。它是 Flask 应用的一部分,通过 Flask 渲染并返回给客户端。
最终效果演示
界面查询
提供多个categories, 用于后期扩展
对于特地category, 当前提供了6个查询接口
数据展示
表格数据展示, 提供了占比, 总数, 排名等等信息
提供了可视化图表, 更加直观体现
提供excel一键导出, 便于离线数据分析
最后
后续展望, 当前的脚本还存在诸多问题,后期准备增加功能:
- 周期性运行部署, 监控log日志的趋势
- 历史版本比较, 往不好方向发展, 可以及时知晓
- 更多log日志格式支持
- 邮件通知
等等
有兴趣, 需要源码可以关注我的公众号, 代码的更多细节, 一起交流~~~