This commit is contained in:
48
utils/common_result.py
Normal file
48
utils/common_result.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from graphql.error import GraphQLError
|
||||
|
||||
# Импорт Author отложен для избежания циклических импортов
|
||||
from orm.community import Community
|
||||
from orm.draft import Draft
|
||||
from orm.reaction import Reaction
|
||||
from orm.shout import Shout
|
||||
from orm.topic import Topic
|
||||
from utils.logger import root_logger as logger
|
||||
|
||||
|
||||
def handle_error(operation: str, error: Exception) -> GraphQLError:
|
||||
"""Обрабатывает ошибки в резолверах"""
|
||||
logger.error(f"Ошибка при {operation}: {error}")
|
||||
return GraphQLError(f"Не удалось {operation}: {error}")
|
||||
|
||||
|
||||
@dataclass
|
||||
class CommonResult:
|
||||
"""Общий результат для GraphQL запросов"""
|
||||
|
||||
error: str | None = None
|
||||
drafts: list[Draft] | None = None # Draft objects
|
||||
draft: Draft | None = None # Draft object
|
||||
slugs: list[str] | None = None
|
||||
shout: Shout | None = None
|
||||
shouts: list[Shout] | None = None
|
||||
author: Any | None = None # Author type resolved at runtime
|
||||
authors: list[Any] | None = None # Author type resolved at runtime
|
||||
reaction: Reaction | None = None
|
||||
reactions: list[Reaction] | None = None
|
||||
topic: Topic | None = None
|
||||
topics: list[Topic] | None = None
|
||||
community: Community | None = None
|
||||
communities: list[Community] | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class AuthorFollowsResult:
|
||||
"""Результат для get_author_follows запроса"""
|
||||
|
||||
topics: list[Any] | None = None # Topic dicts
|
||||
authors: list[Any] | None = None # Author dicts
|
||||
communities: list[Any] | None = None # Community dicts
|
||||
error: str | None = None
|
||||
@@ -4,7 +4,7 @@ JSON encoders and utilities
|
||||
|
||||
import json
|
||||
from datetime import date, datetime
|
||||
from typing import Any, Union
|
||||
from typing import Any
|
||||
|
||||
import orjson
|
||||
|
||||
@@ -23,7 +23,7 @@ def default_json_encoder(obj: Any) -> Any:
|
||||
TypeError: Если объект не может быть сериализован
|
||||
"""
|
||||
# Обработка datetime
|
||||
if isinstance(obj, (datetime, date)):
|
||||
if isinstance(obj, (datetime | date)):
|
||||
return obj.isoformat()
|
||||
|
||||
serialized = False
|
||||
@@ -75,7 +75,7 @@ def orjson_dumps(obj: Any, **kwargs: Any) -> bytes:
|
||||
return orjson.dumps(obj, default=default_json_encoder, **kwargs)
|
||||
|
||||
|
||||
def orjson_loads(data: Union[str, bytes]) -> Any:
|
||||
def orjson_loads(data: str | bytes) -> Any:
|
||||
"""
|
||||
Десериализация объекта с помощью orjson.
|
||||
|
||||
|
||||
22
utils/exception.py
Normal file
22
utils/exception.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import logging
|
||||
from collections.abc import Awaitable
|
||||
from typing import Callable
|
||||
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse, Response
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
||||
class ExceptionHandlerMiddleware(BaseHTTPMiddleware):
|
||||
async def dispatch(self, request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Response:
|
||||
try:
|
||||
return await call_next(request)
|
||||
except Exception:
|
||||
logger.exception("Unhandled exception occurred")
|
||||
return JSONResponse(
|
||||
{"detail": "An error occurred. Please try again later."},
|
||||
status_code=500,
|
||||
)
|
||||
@@ -2,7 +2,7 @@ import re
|
||||
from urllib.parse import quote_plus
|
||||
|
||||
from auth.orm import Author
|
||||
from services.db import local_session
|
||||
from storage.db import local_session
|
||||
|
||||
|
||||
def replace_translit(src: str | None) -> str:
|
||||
|
||||
30
utils/sentry.py
Normal file
30
utils/sentry.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import logging
|
||||
|
||||
import sentry_sdk
|
||||
from sentry_sdk.integrations.ariadne import AriadneIntegration
|
||||
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
|
||||
from sentry_sdk.integrations.starlette import StarletteIntegration
|
||||
|
||||
from settings import GLITCHTIP_DSN
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
# Настройка логирования для отправки логов в Sentry
|
||||
sentry_logging_handler = sentry_sdk.integrations.logging.SentryHandler(level=logging.WARNING)
|
||||
logger.addHandler(sentry_logging_handler)
|
||||
logger.setLevel(logging.DEBUG) # Более подробное логирование
|
||||
|
||||
|
||||
def start_sentry() -> None:
|
||||
try:
|
||||
logger.info("[utils.sentry] Sentry init started...")
|
||||
sentry_sdk.init(
|
||||
dsn=GLITCHTIP_DSN,
|
||||
traces_sample_rate=1.0, # Захват 100% транзакций
|
||||
profiles_sample_rate=1.0, # Профилирование 100% транзакций
|
||||
enable_tracing=True,
|
||||
integrations=[StarletteIntegration(), AriadneIntegration(), SqlalchemyIntegration()],
|
||||
send_default_pii=True, # Отправка информации о пользователе (PII)
|
||||
)
|
||||
logger.info("[utils.sentry] Sentry initialized successfully.")
|
||||
except (sentry_sdk.utils.BadDsn, ImportError, ValueError, TypeError) as _e:
|
||||
logger.warning("[utils.sentry] Failed to initialize Sentry", exc_info=True)
|
||||
Reference in New Issue
Block a user