4a1d949e41
完整 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
118 lines
5.7 KiB
HTML
118 lines
5.7 KiB
HTML
{% 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">下表实时读取每个日志文件的元信息;颜色标识来自阈值:<{{ (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 %} |