mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-18 20:29:44 -05:00
b4486a627f
- Webhook models: remove duplicate index definitions so db.create_all() no longer raises 'index already exists' (columns already have index=True) - ImportService: fix circular import by late-importing ClientService, ProjectService, TimeTrackingService in __init__ - reports: fix F823 by renaming unpack variable _ to _entry_count to avoid shadowing gettext _ in export_task_excel() - Code quality: add .flake8 with extend-ignore so flake8 CI passes; simplify pyproject.toml isort config (drop unsupported options) - Format: run black and isort on app/ - tests: restore minimal app fixture in test_import_export_models
67 lines
2.2 KiB
Python
67 lines
2.2 KiB
Python
"""
|
|
Optional performance instrumentation: slow-request logging and query-count profiling.
|
|
|
|
Enable via config:
|
|
- PERF_LOG_SLOW_REQUESTS_MS: log when request duration exceeds this many ms (0 = disabled)
|
|
- PERF_QUERY_PROFILE: when true, track DB query count per request and include in slow-request logs
|
|
"""
|
|
|
|
import logging
|
|
|
|
from flask import g, request
|
|
from sqlalchemy import event
|
|
from sqlalchemy.engine import Engine
|
|
|
|
logger = logging.getLogger("timetracker.perf")
|
|
|
|
|
|
def init_performance_logging(app):
|
|
"""
|
|
Register slow-request logging and optional query-count profiling.
|
|
No overhead when PERF_LOG_SLOW_REQUESTS_MS is 0 and PERF_QUERY_PROFILE is False.
|
|
"""
|
|
slow_ms = app.config.get("PERF_LOG_SLOW_REQUESTS_MS", 0) or 0
|
|
query_profile = app.config.get("PERF_QUERY_PROFILE", False)
|
|
|
|
if query_profile:
|
|
|
|
@app.before_request
|
|
def _perf_set_query_count():
|
|
g._perf_query_count = 0
|
|
|
|
@event.listens_for(Engine, "before_cursor_execute")
|
|
def _perf_count_query(conn, cursor, statement, parameters, context, executemany):
|
|
if hasattr(g, "_perf_query_count"):
|
|
g._perf_query_count += 1
|
|
|
|
@app.after_request
|
|
def _perf_log_slow_requests(response):
|
|
if slow_ms <= 0:
|
|
return response
|
|
try:
|
|
start = getattr(g, "_start_time", None)
|
|
if start is None:
|
|
return response
|
|
duration_ms = (__import__("time").time() - start) * 1000
|
|
if duration_ms < slow_ms:
|
|
return response
|
|
query_count = getattr(g, "_perf_query_count", getattr(g, "query_count", None))
|
|
if query_count is not None:
|
|
logger.warning(
|
|
"slow_request path=%s duration_ms=%.0f status=%s query_count=%s",
|
|
request.path,
|
|
duration_ms,
|
|
response.status_code,
|
|
query_count,
|
|
)
|
|
else:
|
|
logger.warning(
|
|
"slow_request path=%s duration_ms=%.0f status=%s",
|
|
request.path,
|
|
duration_ms,
|
|
response.status_code,
|
|
)
|
|
except Exception:
|
|
pass
|
|
return response
|