77 lines
2.9 KiB
Python
77 lines
2.9 KiB
Python
"""Read-only statistics endpoints backed by Redis."""
|
|
import json
|
|
from urllib.parse import unquote, urlsplit, parse_qs
|
|
from flask import render_template, jsonify
|
|
from adlist.services import redis_client
|
|
|
|
|
|
def collect_stats():
|
|
stats_data, target_ips, url_requests, user_agents, client_ips = {}, {}, {}, {}, {}
|
|
for key in redis_client.scan_iter("stats:*"):
|
|
key_str = key.decode()
|
|
value = (redis_client.get(key) or b"0").decode()
|
|
if key_str.startswith("stats:target_ips:"):
|
|
target_ips[key_str.split(":", 2)[2]] = value
|
|
elif key_str.startswith("stats:url_requests:"):
|
|
url_requests[unquote(key_str.split(":", 2)[2])] = value
|
|
elif key_str.startswith("stats:user_agents:"):
|
|
user_agents[unquote(key_str.split(":", 2)[2])] = value
|
|
elif key_str.startswith("stats:client_ips:"):
|
|
client_ips[key_str.split(":", 2)[2]] = value
|
|
else:
|
|
stats_data[key_str] = value
|
|
|
|
recent = []
|
|
for item in redis_client.lrange("recent_converts", 0, 99):
|
|
try:
|
|
row = json.loads(item.decode())
|
|
params = parse_qs(urlsplit(row.get("url", "")).query)
|
|
row["source_url"] = params.get("url", [""])[0]
|
|
row["target_ip"] = params.get("ip", ["127.0.0.1"])[0]
|
|
recent.append(row)
|
|
except (ValueError, TypeError, AttributeError):
|
|
continue
|
|
|
|
total_time = float(redis_client.get("stats:processing_time_total") or 0)
|
|
count_time = int(redis_client.get("stats:processing_time_count") or 0)
|
|
total_size = int(redis_client.get("stats:content_size_total") or 0)
|
|
count_size = int(redis_client.get("stats:content_size_count") or 0)
|
|
detailed = {
|
|
"processing_time_total_sec": total_time,
|
|
"processing_time_count": count_time,
|
|
"processing_time_avg_sec": total_time / count_time if count_time else 0,
|
|
"processing_time_min_sec": float(redis_client.get("stats:processing_time_min") or 0),
|
|
"processing_time_max_sec": float(redis_client.get("stats:processing_time_max") or 0),
|
|
"content_size_total_bytes": total_size,
|
|
"content_size_count": count_size,
|
|
"content_size_avg_bytes": total_size / count_size if count_size else 0,
|
|
}
|
|
return {
|
|
**stats_data,
|
|
"target_ips": target_ips,
|
|
"url_requests": url_requests,
|
|
"user_agents": user_agents,
|
|
"client_ips": client_ips,
|
|
"recent_converts": recent,
|
|
"detailed_stats": detailed,
|
|
}
|
|
|
|
|
|
def stats():
|
|
data = collect_stats()
|
|
return render_template(
|
|
"stats.html",
|
|
stats=data,
|
|
target_ips=data["target_ips"],
|
|
url_requests=data["url_requests"],
|
|
user_agents=data["user_agents"],
|
|
client_ips=data["client_ips"],
|
|
recent=data["recent_converts"],
|
|
detailed=data["detailed_stats"],
|
|
raw_json=json.dumps(data, indent=2),
|
|
)
|
|
|
|
|
|
def stats_json():
|
|
return jsonify(collect_stats())
|