140 lines
4.1 KiB
Python
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)
|