tempora/web/app.py
2025-04-13 21:15:50 +03:00

140 lines
4.1 KiB
Python

import os
from flask import Flask, render_template
import psycopg2
from datetime import datetime
import docker
app = Flask(__name__)
docker_client = docker.from_env()
DB_CONFIG = {
'host': os.getenv("HOST"),
'port': os.getenv("PORT"),
'database': os.getenv("DBNAME"),
'user': os.getenv("USER"),
'password': os.getenv("PASSWORD")
}
def parse_log_line(line):
"""Парсит строку лога в формате: [timestamp] сообщение"""
try:
line = line.strip()
if line.startswith('[') and ']' in line:
return line
return f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {line}"
except:
return line
def get_parser_status():
"""Получает статус парсеров из Docker"""
try:
containers = docker_client.containers.list(all=True)
status = {
'tg-node-0': False,
'tg-node-1': False,
'total': 0,
'active': 0,
'errors': 0
}
for container in containers:
if container.name == 'tg-node-0':
status['tg-node-0'] = container.status == 'running'
elif container.name == 'tg-node-1':
status['tg-node-1'] = container.status == 'running'
status['active'] = sum([status['tg-node-0'], status['tg-node-1']])
status['errors'] = 2 - status['active'] # Просто для примера
status['total'] = 2
return status
except Exception as e:
print(f"Error getting docker status: {e}")
return None
def get_leaks_stats():
"""Получает статистику по утечкам из базы данных"""
try:
conn = psycopg2.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM leaks")
total_leaks = cursor.fetchone()[0]
cursor.execute("""
SELECT DATE(created_at) as day, COUNT(*)
FROM leaks
WHERE created_at >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY day
ORDER BY day
""")
leaks_by_day = cursor.fetchall()
cursor.execute("""
SELECT resource_name, COUNT(*)
FROM leaks
GROUP BY resource_name
ORDER BY COUNT(*) DESC
LIMIT 3
""")
leaks_by_source = cursor.fetchall()
cursor.execute("""
SELECT resource_name, message, created_at
FROM leaks
ORDER BY created_at DESC
LIMIT 10
""")
recent_leaks = cursor.fetchall()
return {
'total_leaks': total_leaks,
'leaks_by_day': leaks_by_day,
'leaks_by_source': leaks_by_source,
'recent_leaks': recent_leaks
}
except Exception as e:
print(f"Database error: {e}")
return None
finally:
if 'conn' in locals():
conn.close()
@app.route("/")
def index():
parser_status = get_parser_status()
leaks_stats = get_leaks_stats()
if not leaks_stats:
leaks_stats = {
'total_leaks': 150,
'leaks_by_day': [(datetime.now().date(), 5)],
'leaks_by_source': [('Telegram', 80), ('Форум', 50), ('Даркнет', 20)],
'recent_leaks': [('Telegram', 'Новая утечка данных', datetime.now())]
}
return render_template(
"index.html",
parser_status=parser_status,
leaks_stats=leaks_stats
)
@app.route("/logs")
def logs():
log_path = '/app/tg_nodes.log'
try:
with open(log_path, 'r', encoding='utf-8') as f:
lines = f.readlines()[-100:]
parsed_logs = [parse_log_line(line) for line in lines if line.strip()]
except FileNotFoundError:
parsed_logs = ["[ERROR] Лог-файл не найден"]
except Exception as e:
parsed_logs = [f"[ERROR] Ошибка чтения лог-файла: {str(e)}"]
return render_template("logs.html", logs=parsed_logs)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)