Spaces:
Running
Running
📋 客户端 IP 地址日志指南
✅ 已完成的功能
现在 Flask 应用已经配置为在日志中记录客户端的真实 IP 地址。
🔍 日志格式
Flask 应用日志
[2025-10-16 18:58:23] INFO in app: [203.0.113.1] GET /api/health | UA: Mozilla/5.0 (Windows NT 10.0)
^^^^^^^^^^^^
客户端真实 IP
日志包含:
- 时间戳
- 日志级别
- 客户端 IP 地址
- HTTP 方法和路径
- User-Agent(浏览器信息)
Gunicorn 访问日志
[16/Oct/2025:18:58:23 +0000] Client: 203.0.113.1 (Remote: 172.17.0.1) GET /api/health Status: 200 Size: 123 bytes Time: 5234 μs UA: "Mozilla/5.0..."
^^^^^^^^^^^^
真实客户端 IP
日志包含:
- 时间戳
- 客户端真实 IP(从 X-Forwarded-For 获取)
- 远程地址(可能是代理服务器)
- 请求信息
- 响应状态码和大小
- 处理时间
- User-Agent
🎯 IP 获取逻辑
应用会按以下优先级检查 HTTP 头部来获取真实 IP:
- X-Forwarded-For - 最常见的代理头部
- X-Real-IP - Nginx 等使用
- CF-Connecting-IP - Cloudflare 使用
- True-Client-IP - 某些 CDN 使用
- X-Client-IP - 其他代理使用
- request.remote_addr - 直连时的 IP
代码实现
def get_client_ip():
"""获取客户端真实 IP 地址"""
headers_to_check = [
'X-Forwarded-For',
'X-Real-IP',
'CF-Connecting-IP',
'True-Client-IP',
'X-Client-IP',
]
for header in headers_to_check:
ip = request.headers.get(header)
if ip:
# X-Forwarded-For 可能包含多个 IP,取第一个
return ip.split(',')[0].strip()
return request.remote_addr or 'Unknown'
📁 日志文件位置
本地开发环境
- 控制台输出: 实时显示
- 文件日志:
logs/app.log(自动滚动,保留10个备份)
Hugging Face Spaces
- 控制台输出: Space 页面的 "Logs" 标签
- 文件日志: 不持久化(容器重启后丢失)
🔍 查看日志
查看实时日志(本地)
# 启动应用(控制台输出)
python3.12 app.py
# 或使用 Gunicorn
gunicorn -c gunicorn_config.py app:app
# 实时监控日志文件
tail -f logs/app.log
查看历史日志
# 查看最近 100 条日志
tail -n 100 logs/app.log
# 搜索特定 IP 的访问记录
grep "203.0.113.1" logs/app.log
# 统计各 IP 的访问次数
grep -oP '\[\K[0-9.]+(?=\])' logs/app.log | sort | uniq -c | sort -rn
Hugging Face Spaces
- 进入你的 Space 页面
- 点击 "Logs" 标签
- 查看实时日志输出
- 可以搜索特定 IP 或时间段
📊 日志分析示例
统计最活跃的 IP 地址
# 提取所有 IP 并统计
grep -oP '\[\K[0-9.]+(?=\])' logs/app.log | sort | uniq -c | sort -rn | head -10
输出示例:
245 203.0.113.1
156 198.51.100.1
89 192.0.2.1
45 203.0.113.50
查看特定 IP 的访问历史
grep "\[203.0.113.1\]" logs/app.log
输出示例:
[2025-10-16 18:58:23] INFO in app: [203.0.113.1] GET /api/health | UA: Mozilla/5.0
[2025-10-16 18:58:24] INFO in app: [203.0.113.1] GET /api/book/info | UA: Mozilla/5.0
[2025-10-16 18:58:25] INFO in app: [203.0.113.1] POST /api/search | UA: Mozilla/5.0
分析访问时间分布
# 按小时统计访问量
grep -oP '\[.*?\s+\K\d{2}' logs/app.log | sort | uniq -c
统计不同浏览器的使用情况
grep "UA:" logs/app.log | grep -oP 'UA: \K[^/]+' | sort | uniq -c | sort -rn
🧪 测试 IP 记录
运行测试脚本
# 确保应用正在运行
python3.12 app.py
# 在另一个终端运行测试
python3.12 test_ip_logging.py
手动测试
# 普通请求
curl http://localhost:7860/api/health
# 模拟代理请求(带 X-Forwarded-For)
curl -H "X-Forwarded-For: 203.0.113.1" http://localhost:7860/api/health
# 查看日志中记录的 IP
tail logs/app.log
🔒 隐私和安全
IP 地址处理
- IP 地址仅用于日志记录和调试
- 不会永久存储在数据库中
- 日志文件会自动滚动(最多保留10个备份)
隐私保护建议
如果需要遵守 GDPR 等隐私法规:
匿名化 IP: 可以只记录 IP 的前缀
# 例如:203.0.113.1 -> 203.0.113.0 ip_parts = ip.split('.') anonymized_ip = '.'.join(ip_parts[:3]) + '.0'定期清理日志: 设置日志保留期限
# 在 gunicorn_config.py 中 max_log_age_days = 30 # 保留30天限制日志访问: 确保只有授权人员可以访问日志
📈 日志性能影响
性能考虑
- IP 获取:几乎无性能影响(只是读取 HTTP 头部)
- 日志写入:异步处理,不影响请求响应时间
- 文件大小:每个日志文件最大 10MB,自动滚动
优化建议
如果日志量很大:
减少日志级别(只记录重要信息)
app.logger.setLevel(logging.WARNING) # 只记录警告和错误只记录 API 请求(跳过静态资源)
# 已在 before_request 中实现 if request.path.startswith('/api/'): app.logger.info(...)使用日志聚合服务(如 ELK、Datadog)
🛠️ 自定义日志格式
修改 Flask 日志格式
编辑 app.py 中的 setup_logging() 函数:
file_handler.setFormatter(logging.Formatter(
'[%(asctime)s] [%(levelname)s] [IP:%(client_ip)s] %(message)s'
))
修改 Gunicorn 日志格式
编辑 gunicorn_config.py 中的 access_log_format:
access_log_format = (
'%(h)s - %({X-Forwarded-For}i)s '
'[%(t)s] "%(r)s" %(s)s %(b)s '
'"%(f)s" "%(a)s"'
)
📚 相关文档
🎉 总结
现在您的 Flask 应用已经可以:
✅ 记录客户端真实 IP 地址
✅ 支持多种代理环境(Hugging Face Spaces、Cloudflare 等)
✅ 提供详细的访问日志
✅ 支持日志分析和统计
查看日志的快速命令:
# 实时监控
tail -f logs/app.log
# 搜索特定 IP
grep "203.0.113.1" logs/app.log
# 统计访问量
grep -c "GET /api/" logs/app.log
最后更新: 2025-10-16
相关文件: app.py, gunicorn_config.py, test_ip_logging.py