Files
squid-manager/templates/ops_logs.html
T
Hermes Agent 4a1d949e41 feat: 完整 Squid Web Manager 平台 - P0-P3 全功能
完整 Web 管理平台,涵盖:

P0 生产加固:
- 会话超时(空闲+绝对) + CSRF 防护 + 登录失败限流
- HTTPS/TLS 证书管理(自签生成/上传/删除/过期提醒)
- SSL Bump (HTTPS 透明代理) 可视化配置
- 配置文件 diff 预览 + 二次确认才写入
- 服务控制二次确认 + 操作期间按钮锁定

P1 运维能力:
- 日志轮转管理(logrotate) + 日志状态监控
- 告警规则(5xx/命中率/磁盘/客户端流量)
- 多 Squid 实例管理 + 一键切换
- squidclient mgr 实时性能指标
- 流量异常检测(突增/大文件/高频小包/新客户端)

P2 日志分析增强:
- 日志持久化到 SQLite + 历史时间范围查询
- 导出 CSV/JSON(日志/KPI/异常/审计)
- GeoIP 地图(Leaflet + ip-api.com 离线可选 GeoLite2)
- 每客户端 24h 趋势图
- 自定义 Squid logformat 解析器

P3 体验锦上添花:
- 暗/亮主题切换(cookie 持久化)
- WebSSH 终端(xterm.js + paramiko)
- 完整审计日志 + 用户管理

技术栈: Flask 3.0 + SQLAlchemy 2.0 + SQLite + Chart.js + Leaflet
总代码量: ~16500 行 (15 Python 模块 + 34 模板 + CSS)
路由数: 73
2026-07-15 10:19:21 +08:00

118 lines
5.7 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}日志状态 - Squid Manager{% endblock %}
{% block content %}
<div class="page-header">
<h1>📂 日志状态</h1>
<div class="page-actions">
<span class="meta-text">合计: <strong>{{ total_human }}</strong> · {{ entries | length }} 个文件</span>
</div>
</div>
<div class="card">
<h3 class="card-title">📘 日志轮转原理</h3>
<p class="card-desc">Squid 默认会把请求/缓存/存储事件持续写入 <code>access.log</code> / <code>cache.log</code> / <code>store.log</code>,不会自动截断或归档,长期运行会让磁盘塞满。
常见的做法是结合 <strong>logrotate</strong><code>squid -k rotate</code> 信号:</p>
<ol>
<li><strong>logrotate</strong> 周期性地把当前日志改名 (<code>access.log.1</code>, <code>access.log.2.gz</code> …),并创建新的空日志文件;</li>
<li>logrotate 在 <code>postrotate</code> 钩子里执行 <code>squid -k rotate</code>,让 Squid 关闭旧 fd 并重新打开日志,避免日志写到被改名的旧文件里;</li>
<li>老化的日志按 <code>rotate N</code> 自动清理/压缩,既能保留审计又不会撑爆磁盘。</li>
</ol>
<p class="meta-text">下表实时读取每个日志文件的元信息;颜色标识来自阈值:&lt;{{ (warn_bytes / 1024 / 1024) | int }} MB 正常,≥{{ (warn_bytes / 1024 / 1024) | int }} MB 黄色,≥{{ (crit_bytes / 1024 / 1024 / 1024) | round(1) }} GB 红色。</p>
</div>
<div class="card">
{% if entries %}
<table class="data-table">
<thead>
<tr>
<th>日志文件</th>
<th>大小</th>
<th>状态</th>
<th>最后修改</th>
<th>年龄</th>
<th>可写</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for e in entries %}
<tr>
<td>
<code>{{ e.path }}</code>
{% if e.error %}<div class="meta-text">⚠ {{ e.error }}</div>{% endif %}
</td>
<td>{{ e.size_human }} <span class="meta-text">({{ '{:,}'.format(e.size_bytes) }} B)</span></td>
<td>
{% if not e.exists %}
<span class="badge badge-gray">● 不存在</span>
{% elif e.size_bytes >= crit_bytes %}
<span class="badge badge-red">● 过大 (≥ {{ (crit_bytes / 1024 / 1024 / 1024) | round(1) }} GB)</span>
{% elif e.size_bytes >= warn_bytes %}
<span class="badge badge-yellow">● 偏大 (≥ {{ (warn_bytes / 1024 / 1024) | int }} MB)</span>
{% else %}
<span class="badge badge-green">● 正常</span>
{% endif %}
</td>
<td class="time-cell">{{ e.mtime_human or '-' }}</td>
<td>{% if e.age_days is not none %}{{ e.age_days }} 天{% else %}-{% endif %}</td>
<td>
{% if e.is_writable %}
<span class="badge badge-green"></span>
{% else %}
<span class="badge badge-red"></span>
{% endif %}
</td>
<td>
<form method="post" action="{{ url_for('ops_logs_rotate') }}" style="display:inline;"
onsubmit="return confirm('确认立即轮转日志?\\n将向 Squid 发送 rotate 信号并由 logrotate 接管新文件。');">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-small btn-primary"
{% if not logrotate_available %}disabled title="logrotate 不可用"{% endif %}>
🔁 立即轮转
</button>
</form>
{% set parent_dir = e.path.rsplit('/', 1)[0] if '/' in e.path else '.' %}
<span class="meta-text">📁 {{ parent_dir }}</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="card-empty">
<div class="empty-icon">📂</div>
<p>未在「<a href="{{ url_for('config_paths') }}">路径设置</a>」里配置任何日志路径。</p>
</div>
{% endif %}
</div>
<div class="card">
<h3 class="card-title">🔧 工具状态</h3>
<table class="data-table">
<tbody>
<tr><th style="width: 200px;">logrotate 可执行</th>
<td>{% if logrotate_available %}<span class="badge badge-green">可用</span>
{% else %}<span class="badge badge-red">未找到</span>
<span class="meta-text">请安装 logrotate 包 (apt: logrotate)</span>{% endif %}
</td>
</tr>
<tr><th>Squid 二进制</th><td><code>{{ binary }}</code></td></tr>
<tr><th>日志轮转配置</th>
<td>
<a href="{{ url_for('ops_logrotate') }}" class="btn btn-small btn-secondary">🔁 前往日志轮转</a>
<span class="meta-text">安装 logrotate.d/squid 后会按计划自动轮转</span>
</td>
</tr>
</tbody>
</table>
</div>
<div class="card">
<h3 class="card-title">️ 提示</h3>
<ul>
<li><strong>立即轮转</strong>按钮只发送 <code>squid -k rotate</code> 信号,本身不重命名文件 — 需要 logrotate 配置协同工作。</li>
<li>如果日志路径是网络挂载 (NFS/SMB),「可写」列反映的是当前进程对文件的写权限,可能与 Squid 实际权限不同。</li>
<li>建议把 <code>access.log</code> 的轮转阈值设为单文件大约 100–500 MB,避免后续 <code>logrotate</code> 重命名瞬间触发磁盘峰值。</li>
</ul>
</div>
{% endblock %}