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.
Metadata
Release files for fastapi-sqlalchemy-monitor 1.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fastapi_sqlalchemy_monitor-1.1.3.tar.gz | 81.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fastapi_sqlalchemy_monitor-1.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 89.4 kB
Release files / fastapi_sqlalchemy_monitor-1.1.3.tar.gz
| Download URL | fastapi_sqlalchemy_monitor-1.1.3.tar.gz |
|---|---|
| Size | 81.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
57ff256c9c97854868f4a6c248f807b17293109f5b31384075bf5a78161ae878
|
|
BLAKE2b-256 checksum How to use checksums |
a5d12232212aeaaf99c934415b993a3a8ae0419fa2bac4178adf7cf40938826a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.4
|
Release files / fastapi_sqlalchemy_monitor-1.1.3-py3-none-any.whl
| Download URL | fastapi_sqlalchemy_monitor-1.1.3-py3-none-any.whl |
|---|---|
| Size | 7.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dbf64a76a84406fd4399f28a4413b1e9bf41ecce3a80134f24317e86d4e5cb90
|
|
BLAKE2b-256 checksum How to use checksums |
e19a3ccdbec8b03ae54cf3af45797a19f266d0d97c5adcaff492176c49c30e7d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.4
|