Seamlessly track SQLAlchemy performance in FastAPI with plug-and-play monitoring middleware 🔍
Project description
FastAPI SQLAlchemy Monitor
A middleware for FastAPI that monitors SQLAlchemy database queries, providing insights into database usage patterns and helping catch potential performance issues.
Features
- 📊 Track total database query invocations and execution times
- 🔍 Detailed per-query statistics
- ⚡ Async support
- 🎯 Configurable actions for monitoring and alerting
- 🛡️ Built-in protection against N+1 query problems
Installation
pip install fastapi-sqlalchemy-monitor
Quick Start
from fastapi import FastAPI
from sqlalchemy import create_engine
from fastapi_sqlalchemy_monitor import SQLAlchemyMonitor
from fastapi_sqlalchemy_monitor.action import WarnMaxTotalInvocation, PrintStatistics
# Create async engine
engine = create_engine("sqlite:///./test.db")
app = FastAPI()
# Add the middleware with actions
app.add_middleware(
SQLAlchemyMonitor,
engine=engine,
actions=[
WarnMaxTotalInvocation(max_invocations=10), # Warn if too many queries
PrintStatistics() # Print statistics after each request
]
)
Actions
The middleware supports different types of actions that can be triggered based on query statistics.
Built-in Actions
WarnMaxTotalInvocation: Log a warning when query count exceeds thresholdErrorMaxTotalInvocation: Log an error when query count exceeds thresholdRaiseMaxTotalInvocation: Raise an exception when query count exceeds thresholdLogStatistics: Log query statisticsPrintStatistics: Print query statistics
Custom Actions
The middleware provides two interfaces for implementing custom actions:
Action: Simple interface that executes after every requestConditionalAction: Advanced interface that executes only when specific conditions are met
Basic Custom Action
Here's an example of a custom action that records Prometheus metrics:
from prometheus_client import Counter
from fastapi_sqlalchemy_monitor import AlchemyStatistics
from fastapi_sqlalchemy_monitor.action import Action
class PrometheusAction(Action):
def __init__(self):
self.query_counter = Counter(
'sql_queries_total',
'Total number of SQL queries executed'
)
def handle(self, statistics: AlchemyStatistics):
self.query_counter.inc(statistics.total_invocations)
Conditional Action Example
Here's an example of a conditional action that monitors for slow queries:
import logging
from fastapi_sqlalchemy_monitor import AlchemyStatistics
from fastapi_sqlalchemy_monitor.action import ConditionalAction
class SlowQueryMonitor(ConditionalAction):
def __init__(self, threshold_ms: float):
self.threshold_ms = threshold_ms
def _condition(self, statistics: AlchemyStatistics) -> bool:
# Check if any query exceeds the time threshold
return any(
query.total_invocation_time_ms > self.threshold_ms
for query in statistics.query_stats.values()
)
def _handle(self, statistics: AlchemyStatistics):
# Log details of slow queries
for query_stat in statistics.query_stats.values():
if query_stat.total_invocation_time_ms > self.threshold_ms:
logging.warning(
f"Slow query detected ({query_stat.total_invocation_time_ms:.2f}ms): "
f"{query_stat.query}"
)
Using Custom Actions
Here's how to use custom actions:
app.add_middleware(
SQLAlchemyMonitor,
engine=engine,
actions=[
PrometheusAction(),
SlowQueryMonitor(threshold_ms=100)
]
)
Available Statistics
When implementing custom actions, you have access to these statistics properties:
statistics.total_invocations: Total number of queries executedstatistics.total_invocation_time_ms: Total execution time in millisecondsstatistics.query_stats: Dictionary of per-query statistics
Each QueryStatistic in query_stats contains:
query: The SQL query stringtotal_invocations: Number of times this query was executedtotal_invocation_time_ms: Total execution time for this queryinvocation_times_ms: List of individual execution times
Best Practices
- Keep actions focused on a single responsibility
- Use appropriate log levels for different severity conditions
- Consider performance impact of complex evaluations
- Use type hints for better code maintenance
Example with Async SQLAlchemy
from fastapi import FastAPI
from sqlalchemy.ext.asyncio import create_async_engine
from fastapi_sqlalchemy_monitor import SQLAlchemyMonitor
from fastapi_sqlalchemy_monitor.action import PrintStatistics
# Create async engine
engine = create_async_engine("sqlite+aiosqlite:///./test.db")
app = FastAPI()
# Add middleware
app.add_middleware(
SQLAlchemyMonitor,
engine=engine,
actions=[PrintStatistics()]
)
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_sqlalchemy_monitor-1.1.2.tar.gz.
File metadata
- Download URL: fastapi_sqlalchemy_monitor-1.1.2.tar.gz
- Upload date:
- Size: 81.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd2f4b1f5f4be4c7cd652a8e0d1b8982e7bf1a8c6b18f5727e960142c02d35f2
|
|
| MD5 |
26f516b5475de80f8a5bcd16acd36d17
|
|
| BLAKE2b-256 |
20d46228bbb8a894c538cc8278a27a793de98f1ccbbb409212a63cb8c5b6a11c
|
File details
Details for the file fastapi_sqlalchemy_monitor-1.1.2-py3-none-any.whl.
File metadata
- Download URL: fastapi_sqlalchemy_monitor-1.1.2-py3-none-any.whl
- Upload date:
- Size: 7.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2a8ab965882065ecf2a8312a8fdee0831e4327db964b2e1b0d6b04a997ff790
|
|
| MD5 |
84fa351a3bf275c0bd2db8045f03b169
|
|
| BLAKE2b-256 |
7f127a448a512a975e28b1664804d007e5d256a4befcc95a6d08b3ba25bd3fc0
|