FastAPI RouteLogger не может обработать параметры пути, выдавая KeyError для динамических маршрутов.Python

Программы на Python
Ответить
Anonymous
 FastAPI RouteLogger не может обработать параметры пути, выдавая KeyError для динамических маршрутов.

Сообщение Anonymous »

Я создаю приложение FastAPI с помощью специального RouteLogger, который записывает информацию о маршруте во время запуска. Регистратор работает для статических маршрутов, но не работает при обработке динамических маршрутов с параметрами пути.
Журналы ошибок показывают:
{
"error_type": "KeyError",
"error_message": "'column'",
"context": {
"context": "log_route_info",
"route_path": "/api/general/distribution/{column}",
"route_name": "get_distribution"
}
}
{
"error_type": "KeyError",
"error_message": "'column1'",
"context": {
"context": "log_route_info",
"route_path": "/api/general/crosstab/{column1}/{column2}",
"route_name": "get_crosstab"
}
}
{
"error_type": "KeyError",
"error_message": "'column'",
"context": {
"context": "log_route_info",
"route_path": "/api/general/filters/{column}",
"route_name": "get_filter_values"
}
}

Мои определения маршрутов:
@router.get("/distribution/{column}", response_model=DistributionResponse)
async def get_distribution(
column: str = Path(..., description="Column to analyze"),
filters: Optional[str] = Query(None, description="Optional filters as JSON"),
export_format: Optional[ResultFormat] = Query(None, description="Export format if needed")
) -> DistributionResponse:
# Route implementation

@router.get("/crosstab/{column1}/{column2}", response_model=CrosstabResponse)
async def get_crosstab(
column1: str = Path(..., description="First column to analyze"),
column2: str = Path(..., description="Second column to analyze"),
filters: Optional[str] = Query(None, description="Optional filters as JSON"),
export_format: Optional[ResultFormat] = Query(None, description="Export format if needed")
) -> CrosstabResponse:
# Route implementation

RouteLogger успешно обрабатывает статические маршруты, такие как /api/health/, но не работает с динамическими маршрутами с параметрами пути. Регистратор пытается извлечь информацию о параметрах, но не может правильно обработать параметры пути.
Как изменить RouteLogger для правильной обработки параметров пути FastAPI без выдачи ошибок KeyErrors?
Среда:< /p>
  • Последняя версия FastAPI
  • Python 3.12
  • Windows/Linux
    APILogger, построенный на loguru
Код RouteLogger:
from fastapi import FastAPI, routing, Depends
from fastapi.routing import APIRoute
from typing import Dict, Any, List, Set, Optional, Type, Union, get_type_hints
from enum import Enum
import inspect
import re
from pydantic import BaseModel

from api.core.logging import APILogger
from api.core.config import LOGGING_CONFIG

class RouteLogger:
"""Enhanced route logger with proper parameter extraction."""

def __init__(self):
self.logger = APILogger("RouteLogger", LOGGING_CONFIG)
self.logger.log_info("Route logger initialized")

def __init__(self):
self.logger = APILogger("RouteLogger", LOGGING_CONFIG)
self.logger.log_info("Route logger initialized")

def _get_path_parameters(self, route: APIRoute) -> Dict[str, Any]:
"""Extract path parameters with proper error handling."""
path_params = {}

try:
# Extract path parameter names using regex
param_pattern = r"{([^}]+)}"
path_matches = re.finditer(param_pattern, route.path)

for match in path_matches:
param_name = match.group(1)
param_info = {
'name': param_name,
'required': True,
'kind': 'PATH',
'type': 'str' # Default type for path parameters
}

# Try to get more specific type information from endpoint
if hasattr(route, 'endpoint'):
sig = inspect.signature(route.endpoint)
if param_name in sig.parameters:
param = sig.parameters[param_name]
if param.annotation != inspect.Parameter.empty:
param_info['type'] = str(param.annotation)

path_params[param_name] = param_info

return path_params

except Exception as e:
self.logger.log_error(e, {
"context": "_get_path_parameters",
"route_path": route.path
})
return {}

def _get_endpoint_parameters(self, route: APIRoute) -> List[Dict[str, Any]]:
"""Get endpoint parameters with improved error handling."""
parameters = []

try:
# Get path parameters first
path_params = self._get_path_parameters(route)
parameters.extend(list(path_params.values()))

# Get query parameters from endpoint signature
if hasattr(route, 'endpoint') and route.endpoint:
signature = inspect.signature(route.endpoint)
type_hints = get_type_hints(route.endpoint)

for name, param in signature.parameters.items():
# Skip special parameters and path parameters
if name in {'request', 'background_tasks'} or name in path_params:
continue

param_info = {
'name': name,
'required': param.default == inspect.Parameter.empty,
'kind': str(param.kind),
'type': self._get_parameter_type(param, type_hints.get(name))
}
parameters.append(param_info)

return parameters

except Exception as e:
self.logger.log_error(e, {
"context": "_get_endpoint_parameters",
"route_path": getattr(route, "path", "unknown"),
"route_name": getattr(route, "name", "unknown"),
"parameters_collected": parameters
})
return []

def _get_parameter_type(
self,
param: inspect.Parameter,
type_hint: Optional[Type] = None
) -> str:
"""Get parameter type with proper null handling."""
try:
if type_hint:
if hasattr(type_hint, '__origin__'):
origin = type_hint.__origin__
args = getattr(type_hint, '__args__', [])

if origin is Union and type(None) in args:
non_none_type = next(arg for arg in args if arg is not type(None))
return f"Optional[{self._get_parameter_type(param, non_none_type)}]"

return str(origin.__name__)

return str(type_hint.__name__)

if param.annotation != inspect.Parameter.empty:
return str(param.annotation)

return 'unknown'

except Exception as e:
self.logger.log_error(e, {"context": "_get_parameter_type"})
return 'unknown'

def log_route_info(self, route: APIRoute) -> None:
"""Log route information with proper error handling."""
try:
route_info = {
'path': route.path,
'name': route.name,
'methods': sorted(list(route.methods)) if route.methods else [],
'parameters': self._get_endpoint_parameters(route) or []
}

self.logger.log_info(
f"Registered route: {route.path}",
extra=route_info
)

if route_info['parameters']:
self.logger.log_debug(
f"Route parameters for {route_info['path']}:",
extra={'parameters': route_info['parameters']}
)

except Exception as e:
self.logger.log_error(e, {
"context": "log_route_info",
"route_path": getattr(route, "path", "unknown"),
"route_name": getattr(route, "name", "unknown")
})

def setup_route_logging(self, app: FastAPI) -> None:
"""Set up route logging with proper error handling."""
try:
self.logger.log_info("Setting up route logging")

for route in app.routes:
if isinstance(route, APIRoute):
self.log_route_info(route)

self.logger.log_info("Route logging setup completed")

except Exception as e:
self.logger.log_error(e, {"context": "setup_route_logging"})


Подробнее здесь: https://stackoverflow.com/questions/791 ... r-for-dyna
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»