add 500 alert
This commit is contained in:
parent
6bd69cd7fb
commit
0d0db1209e
@ -1,6 +1,8 @@
|
||||
import os
|
||||
import uuid
|
||||
import logging
|
||||
import asyncio
|
||||
import traceback
|
||||
from fastapi import FastAPI, Request, HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
@ -16,11 +18,101 @@ from starlette.status import (
|
||||
)
|
||||
from datetime import datetime
|
||||
from config import settings
|
||||
from common_lib.utils.http_client import client
|
||||
|
||||
# Настраиваем логирование
|
||||
logging.basicConfig(level=logging.ERROR)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
FEEDBACK_SERVICE_URL = "http://yobble-feedback-service:8000"
|
||||
ERROR_LOG_ENVIRONMENT = "beta"
|
||||
ERROR_LOG_METHODS = {"GET", "POST", "PUT", "PATCH", "DELETE"}
|
||||
|
||||
|
||||
def _get_service_name() -> str:
|
||||
return (
|
||||
getattr(settings, "SERVICE_NAME", None)
|
||||
or os.getenv("SERVICE_NAME")
|
||||
or "unknown"
|
||||
)
|
||||
|
||||
|
||||
def _parse_uuid(value: str | None) -> str | None:
|
||||
if not value:
|
||||
return None
|
||||
try:
|
||||
return str(uuid.UUID(str(value)))
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
async def _read_request_body(request: Request):
|
||||
try:
|
||||
body = await request.body()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
if not body:
|
||||
return None
|
||||
|
||||
content_type = request.headers.get("content-type", "")
|
||||
if "application/json" in content_type:
|
||||
try:
|
||||
return await request.json()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {
|
||||
"raw": body.decode("utf-8", errors="replace")
|
||||
}
|
||||
|
||||
|
||||
async def _send_internal_error_log(request: Request, exc: Exception, error_id: str) -> None:
|
||||
service_name = _get_service_name()
|
||||
if service_name == "feedback_service":
|
||||
return
|
||||
|
||||
method = request.method.upper()
|
||||
if method not in ERROR_LOG_METHODS:
|
||||
method = "GET"
|
||||
|
||||
current_user = getattr(request.state, "current_user", None)
|
||||
user_id = getattr(current_user, "user_id", None)
|
||||
session_id = getattr(current_user, "session_id", None)
|
||||
|
||||
payload = {
|
||||
"user_id": str(user_id) if user_id else None,
|
||||
"service_name": service_name,
|
||||
"source": "api",
|
||||
"endpoint": request.url.path,
|
||||
"method": method,
|
||||
"http_status": 500,
|
||||
"request_headers": dict(request.headers),
|
||||
"request_body": await _read_request_body(request),
|
||||
"request_query_params": dict(request.query_params),
|
||||
"response_body": {
|
||||
"status": "error",
|
||||
"errors": [{"field": "server", "message": "Internal Server Error"}],
|
||||
},
|
||||
"ip_address": request.client.host if request.client else None,
|
||||
"user_agent": request.headers.get("user-agent"),
|
||||
"session_id": str(session_id) if session_id else _parse_uuid(request.headers.get("x-session-id")),
|
||||
"error_message": str(exc),
|
||||
"error_stack": "".join(traceback.format_exception(type(exc), exc, exc.__traceback__)),
|
||||
"error_code": error_id,
|
||||
"severity": "high",
|
||||
"environment": ERROR_LOG_ENVIRONMENT,
|
||||
"correlation_id": _parse_uuid(request.headers.get("x-request-id")),
|
||||
}
|
||||
|
||||
try:
|
||||
await client.post(
|
||||
f"{FEEDBACK_SERVICE_URL}/internal/error-log",
|
||||
json=payload,
|
||||
)
|
||||
except Exception as log_exc:
|
||||
print("error auto log failed:", log_exc)
|
||||
|
||||
|
||||
def register_error_handlers(app: FastAPI):
|
||||
|
||||
@ -156,6 +248,7 @@ def register_error_handlers(app: FastAPI):
|
||||
)
|
||||
|
||||
print("500 critical error:", full_log_message)
|
||||
asyncio.create_task(_send_internal_error_log(request, exc, error_id))
|
||||
# with open(log_filename, "w", encoding="utf-8") as log_file:
|
||||
# log_file.write(full_log_message)
|
||||
|
||||
|
||||
@ -183,7 +183,9 @@ async def get_current_user(
|
||||
detail="Not authenticated"
|
||||
)
|
||||
|
||||
return await _fetch_current_user(request, token, require_permissions=False, is_web=is_web)
|
||||
current_user = await _fetch_current_user(request, token, require_permissions=False, is_web=is_web)
|
||||
request.state.current_user = current_user
|
||||
return current_user
|
||||
|
||||
|
||||
async def get_current_user_with_permissions(
|
||||
@ -205,7 +207,9 @@ async def get_current_user_with_permissions(
|
||||
detail="Not authenticated"
|
||||
)
|
||||
|
||||
return await _fetch_current_user(request, token, require_permissions=True, is_web=is_web)
|
||||
current_user = await _fetch_current_user(request, token, require_permissions=True, is_web=is_web)
|
||||
request.state.current_user = current_user
|
||||
return current_user
|
||||
|
||||
|
||||
async def get_current_user_or_bot(
|
||||
@ -229,7 +233,9 @@ async def get_current_user_or_bot(
|
||||
)
|
||||
|
||||
is_bot_flag = str(is_bot).lower() in ("true", "1", "yes") if is_bot else False
|
||||
return await _fetch_current_user(request, token, require_permissions=False, is_bot=is_bot_flag, is_web=is_web)
|
||||
current_user = await _fetch_current_user(request, token, require_permissions=False, is_bot=is_bot_flag, is_web=is_web)
|
||||
request.state.current_user = current_user
|
||||
return current_user
|
||||
|
||||
|
||||
def validate_username(value: str,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "common-lib"
|
||||
version = "0.0.57"
|
||||
version = "0.0.58"
|
||||
description = "Библиотека общих компонентов для микросервисов yobble"
|
||||
authors = [{ name = "cheykrym", email = "you@example.com" }]
|
||||
license = "MIT"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user