Vorläufig fertiger server

Dieser Commit ist enthalten in:
2025-06-19 13:17:24 +02:00
Ursprung c30d974d57
Commit f82131b5f9
19 geänderte Dateien mit 1595 neuen und 583 gelöschten Zeilen

Datei anzeigen

@@ -6,6 +6,7 @@ import os
import requests
from datetime import datetime, timedelta
import logging
from utils.partition_helper import ensure_partition_exists, check_table_exists
monitoring_bp = Blueprint('monitoring', __name__)
logger = logging.getLogger(__name__)
@@ -33,18 +34,33 @@ def login_required(f):
@monitoring_bp.route('/live-dashboard')
@login_required
def live_dashboard():
"""Live Dashboard showing active customer sessions"""
"""Live Dashboard showing active customer sessions and analytics"""
try:
conn = get_db_connection()
cur = conn.cursor(cursor_factory=RealDictCursor)
# Check if license_heartbeats table exists
if not check_table_exists(conn, 'license_heartbeats'):
logger.warning("license_heartbeats table does not exist")
# Return empty data
return render_template('monitoring/live_dashboard.html',
active_sessions=[],
stats={'active_licenses': 0, 'active_devices': 0, 'total_heartbeats': 0},
validation_timeline=[],
live_stats=[0, 0, 0, 0],
validation_rates=[],
recent_anomalies=[],
top_licenses=[])
# Ensure current month partition exists
ensure_partition_exists(conn, 'license_heartbeats', datetime.now())
# Get active customer sessions (last 5 minutes)
cur.execute("""
SELECT
l.id,
l.license_key,
c.company_name,
c.contact_person,
c.name as company_name,
lh.hardware_id,
lh.ip_address,
lh.timestamp as last_activity,
@@ -71,7 +87,7 @@ def live_dashboard():
""")
stats = cur.fetchone()
# Get validations per minute
# Get validations per minute (for both charts)
cur.execute("""
SELECT
DATE_TRUNC('minute', timestamp) as minute,
@@ -84,13 +100,81 @@ def live_dashboard():
""")
validation_timeline = cur.fetchall()
# Get live statistics for analytics cards
cur.execute("""
SELECT
COUNT(DISTINCT license_id) as active_licenses,
COUNT(*) as total_validations,
COUNT(DISTINCT hardware_id) as unique_devices,
COUNT(DISTINCT ip_address) as unique_ips
FROM license_heartbeats
WHERE timestamp > NOW() - INTERVAL '5 minutes'
""")
live_stats_data = cur.fetchone()
live_stats = [
live_stats_data['active_licenses'] or 0,
live_stats_data['total_validations'] or 0,
live_stats_data['unique_devices'] or 0,
live_stats_data['unique_ips'] or 0
]
# Get validation rates for analytics chart (last 30 minutes)
cur.execute("""
SELECT
DATE_TRUNC('minute', timestamp) as minute,
COUNT(*) as count
FROM license_heartbeats
WHERE timestamp > NOW() - INTERVAL '30 minutes'
GROUP BY minute
ORDER BY minute DESC
LIMIT 30
""")
validation_rates = [(row['minute'].isoformat(), row['count']) for row in cur.fetchall()]
# Get recent anomalies
cur.execute("""
SELECT
ad.*,
l.license_key,
c.name as customer_name
FROM anomaly_detections ad
LEFT JOIN licenses l ON l.id = ad.license_id
LEFT JOIN customers c ON c.id = l.customer_id
WHERE ad.detected_at > NOW() - INTERVAL '24 hours'
ORDER BY ad.detected_at DESC
LIMIT 10
""")
recent_anomalies = cur.fetchall()
# Get top active licenses
cur.execute("""
SELECT
l.license_key,
c.name as customer_name,
COUNT(DISTINCT lh.hardware_id) as device_count,
COUNT(*) as validation_count,
MAX(lh.timestamp) as last_seen
FROM license_heartbeats lh
JOIN licenses l ON l.id = lh.license_id
JOIN customers c ON c.id = l.customer_id
WHERE lh.timestamp > NOW() - INTERVAL '15 minutes'
GROUP BY l.license_key, c.name
ORDER BY validation_count DESC
LIMIT 10
""")
top_licenses = cur.fetchall()
cur.close()
conn.close()
return render_template('monitoring/live_dashboard.html',
active_sessions=active_sessions,
stats=stats,
validation_timeline=validation_timeline)
validation_timeline=validation_timeline,
live_stats=live_stats,
validation_rates=validation_rates,
recent_anomalies=recent_anomalies,
top_licenses=top_licenses)
except Exception as e:
logger.error(f"Error in live dashboard: {str(e)}")
@@ -173,7 +257,7 @@ def alerts():
SELECT
ad.*,
l.license_key,
c.company_name
c.name as company_name
FROM anomaly_detections ad
LEFT JOIN licenses l ON l.id = ad.license_id
LEFT JOIN customers c ON c.id = l.customer_id
@@ -191,9 +275,91 @@ def alerts():
@monitoring_bp.route('/analytics')
@login_required
def analytics():
"""Detailed analytics page"""
# This will integrate with the existing analytics service
return render_template('monitoring/analytics.html')
"""Combined analytics and license server status page"""
try:
conn = get_db_connection()
cur = conn.cursor(cursor_factory=RealDictCursor)
# Get live statistics for the top cards
cur.execute("""
SELECT
COUNT(DISTINCT license_id) as active_licenses,
COUNT(*) as total_validations,
COUNT(DISTINCT hardware_id) as unique_devices,
COUNT(DISTINCT ip_address) as unique_ips
FROM license_heartbeats
WHERE timestamp > NOW() - INTERVAL '5 minutes'
""")
live_stats = cur.fetchone()
live_stats = [
live_stats['active_licenses'] or 0,
live_stats['total_validations'] or 0,
live_stats['unique_devices'] or 0,
live_stats['unique_ips'] or 0
]
# Get validation rates for chart
cur.execute("""
SELECT
DATE_TRUNC('minute', timestamp) as minute,
COUNT(*) as count
FROM license_heartbeats
WHERE timestamp > NOW() - INTERVAL '30 minutes'
GROUP BY minute
ORDER BY minute DESC
LIMIT 30
""")
validation_rates = [(row['minute'].isoformat(), row['count']) for row in cur.fetchall()]
# Get recent anomalies
cur.execute("""
SELECT
ad.*,
l.license_key,
c.name as customer_name
FROM anomaly_detections ad
LEFT JOIN licenses l ON l.id = ad.license_id
LEFT JOIN customers c ON c.id = l.customer_id
WHERE ad.detected_at > NOW() - INTERVAL '24 hours'
ORDER BY ad.detected_at DESC
LIMIT 10
""")
recent_anomalies = cur.fetchall()
# Get top active licenses
cur.execute("""
SELECT
l.license_key,
c.name as customer_name,
COUNT(DISTINCT lh.hardware_id) as device_count,
COUNT(*) as validation_count,
MAX(lh.timestamp) as last_seen
FROM license_heartbeats lh
JOIN licenses l ON l.id = lh.license_id
JOIN customers c ON c.id = l.customer_id
WHERE lh.timestamp > NOW() - INTERVAL '15 minutes'
GROUP BY l.license_key, c.name
ORDER BY validation_count DESC
LIMIT 10
""")
top_licenses = cur.fetchall()
cur.close()
conn.close()
return render_template('monitoring/analytics.html',
live_stats=live_stats,
validation_rates=validation_rates,
recent_anomalies=recent_anomalies,
top_licenses=top_licenses)
except Exception as e:
logger.error(f"Error in analytics: {str(e)}")
return render_template('monitoring/analytics.html',
live_stats=[0, 0, 0, 0],
validation_rates=[],
recent_anomalies=[],
top_licenses=[])
# API endpoints for live data
@monitoring_bp.route('/api/live-stats')
@@ -235,7 +401,7 @@ def api_active_sessions():
cur.execute("""
SELECT
l.license_key,
c.company_name,
c.name as company_name,
lh.hardware_id,
lh.ip_address,
lh.timestamp as last_activity,