cleanup for logfiles, added log for info and error, better logviewer in admin panel
This commit is contained in:
parent
ebad9607a2
commit
633a30180c
129
app.py
129
app.py
@ -2,10 +2,39 @@
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
import shutil
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from flask import Flask, render_template, redirect, url_for, send_from_directory, request, jsonify
|
||||
|
||||
# ── Cleanup Log-Files ────────────────────────────────────────────────────────────────
|
||||
def cleanup_old_log_dirs(max_age_days=90):
|
||||
"""Löscht Monatsordner in logs/, die älter als max_age_days sind"""
|
||||
if not os.path.exists(LOG_DIR):
|
||||
return
|
||||
|
||||
cutoff_date = datetime.now() - timedelta(days=max_age_days)
|
||||
cutoff_str = cutoff_date.strftime('%Y-%m')
|
||||
|
||||
for subdir in os.listdir(LOG_DIR):
|
||||
subdir_path = os.path.join(LOG_DIR, subdir)
|
||||
if os.path.isdir(subdir_path):
|
||||
try:
|
||||
# subdir ist z. B. "2025-11"
|
||||
subdir_date = datetime.strptime(subdir, '%Y-%m')
|
||||
if subdir_date < cutoff_date:
|
||||
logger.info(f"Lösche alten Log-Ordner: {subdir_path}")
|
||||
shutil.rmtree(subdir_path)
|
||||
except ValueError:
|
||||
# Ungültiges Datumsformat → überspringen
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Löschen von {subdir_path}: {e}")
|
||||
|
||||
# Beim Start aufrufen
|
||||
cleanup_old_log_dirs(90)
|
||||
logger.info("Alte Log-Ordner bereinigt")
|
||||
|
||||
# ── Bluetooth ────────────────────────────────────────────────────────────────
|
||||
from mkconnect.mouldking.MouldKing import MouldKing
|
||||
from mkconnect.tracer.TracerConsole import TracerConsole
|
||||
@ -22,36 +51,45 @@ os.makedirs(app.config['CONFIG_DIR'], exist_ok=True)
|
||||
LOG_DIR = 'logs'
|
||||
os.makedirs(LOG_DIR, exist_ok=True)
|
||||
|
||||
# Täglich neuer Ordner (z. B. logs/2026-02)
|
||||
# Täglicher Unterordner
|
||||
today = datetime.now().strftime('%Y-%m')
|
||||
current_log_subdir = os.path.join(LOG_DIR, today)
|
||||
os.makedirs(current_log_subdir, exist_ok=True)
|
||||
|
||||
# Log-Datei: z. B. logs/2026-02/12.log
|
||||
log_filename = os.path.join(current_log_subdir, datetime.now().strftime('%d.log'))
|
||||
# Basis-Dateiname (ohne Endung)
|
||||
base_filename = os.path.join(current_log_subdir, datetime.now().strftime('%d'))
|
||||
|
||||
# Logging konfigurieren
|
||||
# Handler für INFO+
|
||||
info_handler = logging.FileHandler(f"{base_filename}-info.log")
|
||||
info_handler.setLevel(logging.INFO)
|
||||
info_handler.setFormatter(logging.Formatter(
|
||||
'%(asctime)s | %(levelname)-8s | %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
))
|
||||
|
||||
# Handler für WARNING+ (inkl. ERROR, CRITICAL)
|
||||
error_handler = logging.FileHandler(f"{base_filename}-error.log")
|
||||
error_handler.setLevel(logging.WARNING)
|
||||
error_handler.setFormatter(logging.Formatter(
|
||||
'%(asctime)s | %(levelname)-8s | %(message)s\n%(pathname)s:%(lineno)d\n',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
))
|
||||
|
||||
# Logger konfigurieren
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.INFO)
|
||||
logger.setLevel(logging.DEBUG) # DEBUG, damit alles durchkommt
|
||||
|
||||
# Handler: schreibt in die tagesaktuelle Datei
|
||||
handler = logging.FileHandler(log_filename)
|
||||
handler.setLevel(logging.INFO)
|
||||
logger.handlers.clear() # Alte Handler entfernen
|
||||
logger.addHandler(info_handler)
|
||||
logger.addHandler(error_handler)
|
||||
|
||||
# Format
|
||||
formatter = logging.Formatter('%(asctime)s | %(levelname)-8s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
|
||||
handler.setFormatter(formatter)
|
||||
# Optional: Auch in Konsole
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(logging.INFO)
|
||||
console.setFormatter(info_handler.formatter)
|
||||
logger.addHandler(console)
|
||||
|
||||
# Alten Handler entfernen (falls schon gesetzt)
|
||||
logger.handlers.clear()
|
||||
logger.addHandler(handler)
|
||||
|
||||
# Optional: Auch in Konsole loggen (für Entwicklung)
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setFormatter(formatter)
|
||||
logger.addHandler(console_handler)
|
||||
|
||||
logger.info("Logging neu initialisiert – Tages-Log: " + log_filename)
|
||||
logger.info("Logging getrennt initialisiert: info.log + error.log")
|
||||
|
||||
|
||||
# Bluetooth-Komponenten (einmalig initialisieren)
|
||||
@ -252,15 +290,38 @@ def admin_delete_config(filename):
|
||||
|
||||
|
||||
@app.route('/admin/logs')
|
||||
def admin_logs():
|
||||
log_path = 'app.log'
|
||||
if os.path.exists(log_path):
|
||||
with open(log_path, 'r', encoding='utf-8') as f:
|
||||
logs = f.read()
|
||||
else:
|
||||
logs = "Keine Logs vorhanden."
|
||||
@app.route('/admin/logs/<date>')
|
||||
def admin_logs(date=None):
|
||||
if date is None:
|
||||
date = datetime.now().strftime('%d')
|
||||
|
||||
return render_template('admin_logs.html', logs=logs)
|
||||
today = datetime.now().strftime('%Y-%m')
|
||||
log_dir = os.path.join(LOG_DIR, today)
|
||||
|
||||
if not os.path.exists(log_dir):
|
||||
return render_template('admin_logs.html', logs="Keine Logs für diesen Tag.", date=date, dates=[])
|
||||
|
||||
# Verfügbare Tage (alle .log-Dateien im Monatsordner)
|
||||
dates = sorted([
|
||||
f.split('-')[0] for f in os.listdir(log_dir)
|
||||
if f.endswith('-info.log') or f.endswith('-error.log')
|
||||
], reverse=True)
|
||||
|
||||
# Logs des gewählten Tages laden
|
||||
info_path = os.path.join(log_dir, f"{date}-info.log")
|
||||
error_path = os.path.join(log_dir, f"{date}-error.log")
|
||||
|
||||
logs = []
|
||||
if os.path.exists(info_path):
|
||||
with open(info_path, 'r', encoding='utf-8') as f:
|
||||
logs.append("=== INFO-LOG ===\n" + f.read())
|
||||
if os.path.exists(error_path):
|
||||
with open(error_path, 'r', encoding='utf-8') as f:
|
||||
logs.append("=== ERROR-LOG ===\n" + f.read())
|
||||
|
||||
log_content = "\n\n".join(logs) if logs else "Keine Logs für diesen Tag."
|
||||
|
||||
return render_template('admin_logs.html', logs=log_content, date=date, dates=dates)
|
||||
|
||||
|
||||
@app.route('/configs/<path:filename>')
|
||||
@ -452,3 +513,11 @@ def api_reconnect():
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||
|
||||
def daily_cleanup():
|
||||
while True:
|
||||
cleanup_old_log_dirs(90)
|
||||
time.sleep(86400) # 24 Stunden
|
||||
|
||||
cleanup_thread = threading.Thread(target=daily_cleanup, daemon=True)
|
||||
cleanup_thread.start()
|
||||
@ -1,17 +1,24 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Logs – MK Control{% endblock %}
|
||||
{% block title %}Logs – {{ date }}. {{ today[:4] }}-{{ today[5:] }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<h1>Log-Datei (app.log)</h1>
|
||||
<h1>Logs – {{ date }}. {{ today[:4] }}-{{ today[5:] }}</h1>
|
||||
|
||||
<pre class="bg-dark text-light p-4 rounded" style="max-height: 70vh; overflow-y: auto; font-size: 0.9rem;">
|
||||
<div class="mb-4">
|
||||
<label for="date-select" class="form-label">Tag auswählen:</label>
|
||||
<select id="date-select" class="form-select w-auto d-inline-block" onchange="window.location.href='/admin/logs/' + this.value">
|
||||
{% for d in dates %}
|
||||
<option value="{{ d }}" {% if d == date %}selected{% endif %}>{{ d }}.</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<pre class="bg-dark text-light p-4 rounded" style="max-height: 70vh; overflow-y: auto; font-size: 0.95rem; white-space: pre-wrap;">
|
||||
{{ logs | safe }}
|
||||
</pre>
|
||||
|
||||
<div class="mt-4">
|
||||
<a href="{{ url_for('admin') }}" class="btn btn-secondary">Zurück zum Admin</a>
|
||||
</div>
|
||||
<a href="{{ url_for('admin') }}" class="btn btn-secondary mt-3">Zurück zum Admin</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user