50 lines
1.5 KiB
Python
50 lines
1.5 KiB
Python
"""
|
|
SQLAlchemy-backed logging handler.
|
|
|
|
Writes app.* log records to the app_logs table so the web viewer
|
|
can query, filter, and purge them without touching the log file.
|
|
|
|
Safety rules:
|
|
- Never raises — all errors are silently swallowed to avoid crashing the app
|
|
- Reentrancy guard prevents infinite recursion (SQLAlchemy emits its own logs)
|
|
- Skips sqlalchemy.* and werkzeug loggers to avoid noise / recursion
|
|
"""
|
|
|
|
import logging
|
|
import traceback
|
|
from datetime import datetime
|
|
|
|
|
|
_SKIP_PREFIXES = ('sqlalchemy', 'werkzeug', 'urllib3', 'plaid_handler')
|
|
|
|
|
|
class DBLogHandler(logging.Handler):
|
|
_inside_emit = False
|
|
|
|
def emit(self, record):
|
|
if DBLogHandler._inside_emit:
|
|
return
|
|
if any(record.name.startswith(p) for p in _SKIP_PREFIXES):
|
|
return
|
|
DBLogHandler._inside_emit = True
|
|
try:
|
|
from app.extensions import db
|
|
from app.models.app_log import AppLog
|
|
|
|
msg = record.getMessage()
|
|
if record.exc_info:
|
|
msg += '\n' + ''.join(traceback.format_exception(*record.exc_info)).rstrip()
|
|
|
|
entry = AppLog(
|
|
timestamp=datetime.utcfromtimestamp(record.created),
|
|
level=record.levelname,
|
|
module=record.name,
|
|
message=msg,
|
|
)
|
|
db.session.add(entry)
|
|
db.session.commit()
|
|
except Exception:
|
|
pass
|
|
finally:
|
|
DBLogHandler._inside_emit = False
|