diff --git a/srv/tesm/VERSION b/srv/tesm/VERSION index af0b7dd..238d6e8 100644 --- a/srv/tesm/VERSION +++ b/srv/tesm/VERSION @@ -1 +1 @@ -1.0.6 +1.0.7 diff --git a/srv/tesm/app.py b/srv/tesm/app.py index 4b1b1d3..3cd869e 100644 --- a/srv/tesm/app.py +++ b/srv/tesm/app.py @@ -1904,18 +1904,39 @@ def _format_log_size(num_bytes): _LOG_HISTORY_FILE_RE = re.compile(r"^live\.log\.([1-9][0-9]*)$") +_LOG_HISTORY_DATE_FMT = "%d.%m.%Y %H:%M" def _live_log_history_files(): - """Ältere, von logrotate rotierte Kopien des Live-Logs (live.log.1 = - zuletzt rotiert, .2 der Lauf davor, usw. -- copytruncate ohne compress, - siehe _write_logrotate_config, daher reine Textdateien ohne .gz), - sortiert von neu (1) nach alt.""" + """Alle über die Verlauf-Seite auswählbaren Stände des Live-Logs -- + generation 0 ist die aktuelle, noch laufende live.log selbst, 1 die + zuletzt rotierte Kopie, 2 der Lauf davor usw. (copytruncate ohne + compress, siehe _write_logrotate_config, daher reine Textdateien ohne + .gz), sortiert von neu (0) nach alt. + + Jede Kopie deckt den Zeitraum zwischen ZWEI Rotationen ab: ihr eigenes + mtime ist der Zeitpunkt, an dem ihr Inhalt eingefroren wurde (Ende des + Zeitraums), das mtime der NÄCHSTälteren Generation der Beginn -- ein + reines rename() bei jeder weiteren Rotation ändert mtime nicht, jede + Generation behält also dauerhaft den Zeitpunkt ihrer eigenen + Entstehung. Für die aktuelle live.log gibt es kein eigenes "Ende", + dort wird stattdessen "laufend" angezeigt.""" results = [] + try: + if os.path.isfile(TESM_LIVE_LOG_PATH): + mtime = os.path.getmtime(TESM_LIVE_LOG_PATH) + size = os.path.getsize(TESM_LIVE_LOG_PATH) + results.append({ + "filename": "live.log", "generation": 0, + "mtime": mtime, "size_str": _format_log_size(size), + }) + except OSError: + pass + try: entries = os.listdir(TESM_LOG_DIR) except OSError: - return results + entries = [] for entry in entries: m = _LOG_HISTORY_FILE_RE.match(entry) if not m: @@ -1929,20 +1950,30 @@ def _live_log_history_files(): except OSError: continue results.append({ - "filename": entry, - "generation": int(m.group(1)), - "mtime_str": datetime.fromtimestamp(mtime).strftime("%d.%m.%Y %H:%M"), - "size_str": _format_log_size(size), + "filename": entry, "generation": int(m.group(1)), + "mtime": mtime, "size_str": _format_log_size(size), }) results.sort(key=lambda r: r["generation"]) + + for i, entry in enumerate(results): + older = results[i + 1] if i + 1 < len(results) else None + start_str = datetime.fromtimestamp(older["mtime"]).strftime(_LOG_HISTORY_DATE_FMT) if older else None + if entry["generation"] == 0: + end_str = "laufend" + else: + end_str = datetime.fromtimestamp(entry["mtime"]).strftime(_LOG_HISTORY_DATE_FMT) + entry["range_label"] = f"{start_str or '?'} – {end_str}" return results def _resolve_log_history_file(filename): """Validiert einen vom Client übergebenen Dateinamen (?file=...) gegen - die tatsächlich vorhandenen rotierten Live-Log-Kopien in TESM_LOG_DIR -- - verhindert Path-Traversal bzw. beliebiges Datei-Lesen über den - Query-Parameter. Gibt den vollen Pfad oder None zurück.""" + die tatsächlich vorhandene aktuelle live.log bzw. rotierte Kopien davon + in TESM_LOG_DIR -- verhindert Path-Traversal bzw. beliebiges + Datei-Lesen über den Query-Parameter. Gibt den vollen Pfad oder None + zurück.""" + if filename == "live.log": + return TESM_LIVE_LOG_PATH if os.path.isfile(TESM_LIVE_LOG_PATH) else None if not filename or not _LOG_HISTORY_FILE_RE.match(filename): return None full_path = os.path.join(TESM_LOG_DIR, filename) @@ -5901,7 +5932,8 @@ def logs_history(): selected_name = requested if selected_path else None if not selected_path and files: selected_name = files[0]["filename"] - selected_path = os.path.join(TESM_LOG_DIR, selected_name) + selected_path = _resolve_log_history_file(selected_name) + selected_file = next((f for f in files if f["filename"] == selected_name), None) log_content = None total_lines = None @@ -5913,7 +5945,7 @@ def logs_history(): log_content = f"Fehler beim Lesen des Logs: {e}" return render_template( - "logs_history.html", files=files, selected_name=selected_name, + "logs_history.html", files=files, selected_name=selected_name, selected_file=selected_file, log_content=log_content, total_lines=total_lines, tail_lines=LIVE_LOG_TAIL_LINES, ) diff --git a/srv/tesm/templates/logs_history.html b/srv/tesm/templates/logs_history.html index 19149d1..9f2c2a5 100644 --- a/srv/tesm/templates/logs_history.html +++ b/srv/tesm/templates/logs_history.html @@ -1,14 +1,14 @@ {% extends "base.html" %} {% set active_page = "logs" %} {% block page_title %}Verlauf{% endblock %} -{% block page_sub %}
{% endblock %} +{% block page_sub %}{% endblock %} {% block content %}