当前位置: 首页 > news >正文

从零构建生产级日志分析系统:Flask + Docker + Nginx 完整实战

又到周末了,使用 claude 做点东西的心思又来了!那就找找工作中的痛点问题。
我们有个Java+Tomcat的 老项目,平时查日志只能去服务器上用命令来看,一点也不方便(后面新做的项目,很多框架里都自带了日志功能。还有的项目是用的 ElasticSearch)。
那就趁着周末,动手做一个吧!

我有一个Tomcat日志文件,平时用命令行查起来很不方便,想着可以做一个可视化的系统

如果不用ElasticSearch,自己用AI写一个可视化的,你觉得靠谱吗

我服务器是CentOS,上面有docker,最新日志是
/home/tomcatlog/jkwh_app_out.log,今天之前的日志会自动按日期生成目录,归纳到/home/tomcatlog/backuplog
下,如/logs_20251017/jkwh_app_out.log.1

和CHATGPT几轮沟通后,一个基本的方案就出来了!

🧩 一、你当前日志结构说明

当前正在写入的实时日志  └── backuplog/├── logs_20251017/jkwh_app_out.log.1├── logs_20251016/jkwh_app_out.log.1├── logs_20251015/jkwh_app_out.log.1└── ... (按日期归档) ```✅ 非常标准,实时日志 + 历史归档。---## 🧠 二、目标系统设计我们做一个 Docker 应用,支持两个功能:| 模块     | 功能描述                                                   | |
:----- | :----------------------------------------------------- | |
实时日志监控 | 通过 WebSocket 实时读取 `/home/tomcatlog/jkwh_app_out.log`   | |
历史日志浏览 | 自动列出 `/home/tomcatlog/backuplog` 下的日期目录,点击即可加载对应日志文件内容 |---## ⚙️ 三、目录映射设计容器内目录映射:| 主机路径                               | 容器内路径                   | 作用   
| | :--------------------------------- | :---------------------- |
:----- | | `/home/tomcatlog/jkwh_app_out.log` |
`/app/logs/current.log` | 实时日志   | | `/home/tomcatlog/backuplog`      
| `/app/backuplog`        | 历史日志目录 |---## 🧩 四、项目结构(完整方案)```log-visualizer/  ├─ app.py                # Flask + SocketIO 后端 
├─ templates/  │   └─ index.html        # 前端页面  ├─ requirements.txt 
└─ Dockerfile ```---### 🧾 requirements.txt```flask flask-socketio watchdog ```---### ⚙️ app.py```python from flask import Flask, render_template, jsonify,
send_file, request from flask_socketio import SocketIO import os,
time, threadingapp = Flask(__name__) socketio = SocketIO(app,
cors_allowed_origins="*")CURRENT_LOG = "/app/logs/current.log" BACKUP_DIR = "/app/backuplog"def tail_current_log():"""持续读取实时日志"""if not os.path.exists(CURRENT_LOG):print(f"Log file not found: {CURRENT_LOG}")returnwith open(CURRENT_LOG, "r", encoding="utf-8", errors="ignore") as f:f.seek(0, os.SEEK_END)while True:line = f.readline()if line:socketio.emit("log_line", {"data": line})else:time.sleep(0.2)@app.route("/") def index():return render_template("index.html")@app.route("/api/backups") def list_backups():"""列出所有日期目录"""dirs = sorted(os.listdir(BACKUP_DIR), reverse=True)return jsonify([d for d in dirs if d.startswith("logs_")])@app.route("/api/view_log") def view_log():"""查看指定日期的日志"""date_dir = request.args.get("date")log_path = os.path.join(BACKUP_DIR, date_dir, "jkwh_app_out.log.1")if not os.path.exists(log_path):return "Log not found", 404return send_file(log_path, mimetype="text/plain")if __name__ == "__main__":threading.Thread(target=tail_current_log, daemon=True).start()socketio.run(app, host="0.0.0.0", port=8080) ```---### 💻 templates/index.html```html <!DOCTYPE html> <html> <head>   <meta charset="utf-8">  
<title>Tomcat 日志监控系统</title>   <script
src="https://cdn.socket.io/4.3.2/socket.io.min.js"></script>   <style>body { font-family: monospace; background: #111; color: #ddd; margin: 0; }#log { height: 80vh; overflow-y: scroll; padding: 10px; white-space: pre-wrap; background: #000; }.toolbar { background: #222; padding: 10px; }select { padding: 5px; }   </style> </head> <body>   <div class="toolbar"><label>查看历史日志:</label><select id="dateSelect"></select><button onclick="loadHistory()">加载</button>   </div>   <pre id="log"></pre>   <script>const log = document.getElementById("log");const socket = io();socket.on("log_line", msg => {log.textContent += msg.data;log.scrollTop = log.scrollHeight;});async function loadHistory() {const date = document.getElementById("dateSelect").value;const res = await fetch("/api/view_log?date=" + date);log.textContent = await res.text();}async function loadDates() {const res = await fetch("/api/backups");const dates = await res.json();const sel = document.getElementById("dateSelect");dates.forEach(d => {const opt = document.createElement("option");opt.value = d; opt.textContent = d;sel.appendChild(opt);});}loadDates();   </script> </body> </html> ```---### 🐳 Dockerfile```dockerfile FROM python:3.10-slim WORKDIR /app COPY . . RUN pip
install -r requirements.txt EXPOSE 8080 CMD ["python", "app.py"] ```---## 🚀 五、部署命令```bash cd /opt/log-visualizer docker build -t log-viewer . docker run
-d \   --name log-viewer \   -p 8080:8080 \   -v /home/tomcatlog/jkwh_app_out.log:/app/logs/current.log \   -v
/home/tomcatlog/backuplog:/app/backuplog \   --restart always \  
log-viewer ```---## 🌐 六、访问系统浏览器访问:```http://<服务器IP>:8080 ```✅ 页面上自动显示实时日志 ✅ 可以选择历史日期查看归档日志内容

md 文件直接让 claude 去读取!于是就有了本文!

本文将带你从零构建一个功能完整的 Web 日志分析系统,支持实时监控、高级搜索、上下文查看、数据导出等专业功能。

技术栈: Python Flask + SocketIO + Docker + Nginx + JavaScript

适用场景: Tomcat 日志、应用日志、系统日志等各类文本日志分析


🎯 项目需求分析

业务需求

  1. 实时监控 - 类似 tail -f,自动推送最新日志
  2. 历史查询 - 查询归档日志,支持按日期检索
  3. 高级搜索 - 关键词、正则、日志级别、时间范围过滤
  4. 上下文查看 - 点击日志行,查看前后 15 行上下文
  5. 数据导出 - 导出搜索结果为 TXT/CSV
  6. 快速过滤 - 一键提取异常、IP、SQL、敏感信息
  7. 双版本 - 标准版(简洁)+ 专业版(功能全)

非功能需求

  1. 安全性 - IP 白名单访问控制
  2. 性能 - 支持大文件(GB 级)日志分析
  3. 易部署 - Docker 一键部署
  4. 可扩展 - 支持 Nginx 反向代理、子路径部署

🏗️ 系统架构设计

整体架构

┌─────────────┐      ┌──────────────┐      ┌─────────────┐
│   浏览器     │──────│  Nginx 反向   │──────│   Docker    │
│             │ HTTP │    代理       │ 8080 │  Container  │
└─────────────┘      └──────────────┘      └─────────────┘│┌───────┴────────┐│  Flask App     ││  + SocketIO    │└───────┬────────┘│┌───────┴────────┐│  日志文件       ││  (只读挂载)     │└────────────────┘

技术选型理由

组件 技术选型 理由
后端框架 Flask 轻量级、易扩展、文档完善
实时推送 Flask-SocketIO 支持 WebSocket,实时性好
前端 原生 JS 无需打包构建,部署简单
容器化 Docker 环境隔离,一键部署
反向代理 Nginx 高性能、支持 HTTPS、负载均衡

💻 核心功能实现

1. 实时日志推送(WebSocket)

后端实现
from flask_socketio import SocketIOapp = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading')def tail_current_log():"""后台线程:监控日志文件变化,实时推送"""with open(CURRENT_LOG, 'r', encoding='utf-8', errors='ignore') as f:f.seek(0, 2)  # 移动到文件末尾while True:line = f.readline()if line:parsed = parse_log_line(line)socketio.emit('log_line', {'data': line.rstrip('\n'),'parsed': parsed})else:time.sleep(0.1)# 启动后台线程
threading.Thread(target=tail_current_log, daemon=True).start()
前端实现
const socket = io(APP_PREFIX || '/');socket.on("log_line", msg => {if (currentMode === 'realtime') {appendLogLine(msg.parsed, msg.data);if (autoScroll) {log.scrollTop = log.scrollHeight;  // 自动滚动到底部}}
});

关键技术点:

  • f.seek(0, 2) 移动到文件末尾,只读取新增内容
  • daemon=True 设置为守护线程,主程序退出时自动关闭
  • 前端自动滚动到底部,保持 tail -f 体验

2. 高级搜索功能

支持的搜索条件
def search_in_file(file_path, keyword=None, level=None,start_time=None, end_time=None,regex=False, max_lines=1000, context_lines=0):"""多条件组合搜索"""results = []with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:for idx, line in enume
http://www.dtcms.com/a/500463.html

相关文章:

  • 济南市建设局网站查房产信息鞍山人才网站
  • 网站流量被用完了wordpress页面创建失败
  • 企业seo整站优化方案石家庄网站推广方案
  • 中学生做的网站有哪些方面企业号码查询系统
  • feed流推模式和拉模式学习
  • 颜色搭配的网站采集伪原创wordpress
  • 北京建设局网站首页河北省建设银行网站
  • 网站建设 300元电子商务网站建设 试题
  • 网站建设改版攻略51CTO学院个人网站开发视频
  • tkinter显示不出中文?
  • wordpress建壁纸站苏州网站建设上往建站
  • 温江做网站公司wordpress菜单选项
  • 网络层数、参数量、数据集大小的关系
  • 启迪网站建设招聘做自己的视频网站
  • STM32G474单片机开发入门(十六)CCM SRAM详解及实战
  • 安徽省建设厅网站首页集约化网站建设方案
  • seo对企业网站运营有何意义做网站的中标公司
  • 太原网站优化步骤做网站优化推广多少钱
  • 以学校为目标做网站策划书浙江中联建设集团有限公司网站
  • 在线文档网站源码北京网站代运营公司
  • 西安网站建设运维乌海做网站的公司
  • 低资源NLP数据处理:少样本/零样本场景下数据增强与迁移学习结合方案
  • 【C++】:深入理解vector(2):vector深度剖析及模拟实现
  • 网站的友情连接怎么做广西建设执业资格注册中心官网
  • 力扣94.二叉树的中序遍历(递归and迭代法)(java)
  • 做网站ps建立多大的画布开发外贸客户的免费平台
  • 郑州企业网站排行兰州东方商易文化传播有限责任公司
  • 襄阳建设路21号创意园网站西安高端模板建站
  • HTTP 请求:GET 与 POST 的核心区别
  • 饰品类网站建设定位红酒网站模板