feat: add logging and SMTP error handling

Logging:
- Add structured logging with timestamps
- Log successful and failed login attempts
- Log new orders and order completions
- Log email sending success/failures

SMTP Error Handling:
- Add try/except block around SMTP operations
- Catch authentication errors, SMTP exceptions, and general errors
- Log all email failures with detailed error messages
- Ensure orders are saved even if email fails

This allows monitoring of critical operations and troubleshooting
email delivery issues through systemd journal.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-06 08:11:40 +01:00
parent 630595bce9
commit a8b26a25da

View File

@@ -14,6 +14,7 @@ import secrets
import smtplib
import time
import threading
import logging
from uuid import uuid4
from email.message import EmailMessage
from functools import wraps
@@ -31,6 +32,14 @@ DB_PATH = BASE_DIR / "hellas.db"
UPLOAD_DIR = BASE_DIR / "static" / "uploads"
ALLOWED_EXT = {".png", ".jpg", ".jpeg", ".webp", ".gif"}
# Logging konfigurieren
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)
# Optionaler Prefix (z. B. /wawi), wenn die App hinter einem SubPfad läuft.
URL_PREFIX = os.environ.get("URL_PREFIX", "").strip().rstrip("/")
STATIC_URL_PATH = f"{URL_PREFIX}/static" if URL_PREFIX else "/static"
@@ -490,8 +499,10 @@ def login():
).fetchone()
if row and check_password_hash(row["password_hash"], password):
session["user"] = user
logger.info(f"Erfolgreicher Login: {user}")
nxt = request.args.get("next") or url_for("bp.index")
return redirect(nxt)
logger.warning(f"Fehlgeschlagener Login-Versuch: {user}")
return render_template("login.html", error=True)
return render_template("login.html", error=False)
@@ -653,6 +664,7 @@ def order():
),
)
db.commit()
logger.info(f"Neue Bestellung: {data.get('artikel')} ({data.get('groesse')}) x{data.get('menge')} von {data.get('name')}")
to_addr = os.environ.get("ORDER_TO", "bjoern@welker.me")
smtp_host = os.environ.get("SMTP_HOST")
@@ -683,10 +695,19 @@ def order():
msg.set_content(body)
def _send():
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls()
server.login(smtp_user, smtp_pass)
server.send_message(msg, to_addrs=recipients)
"""Sendet Bestellungs-Email asynchron mit Error Handling."""
try:
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls()
server.login(smtp_user, smtp_pass)
server.send_message(msg, to_addrs=recipients)
logger.info(f"Bestellungs-Email erfolgreich versendet an {', '.join(recipients)}")
except smtplib.SMTPAuthenticationError as e:
logger.error(f"SMTP-Authentifizierung fehlgeschlagen: {e}")
except smtplib.SMTPException as e:
logger.error(f"SMTP-Fehler beim Email-Versand: {e}")
except Exception as e:
logger.error(f"Unerwarteter Fehler beim Email-Versand: {e}", exc_info=True)
threading.Thread(target=_send, daemon=True).start()
@@ -758,6 +779,7 @@ def complete_order(order_id: int):
(user, now_iso(), order_id),
)
db.commit()
logger.info(f"Bestellung #{order_id} abgeschlossen von {user}")
return redirect(url_for("bp.orders"))