Add sentry, datadog and structured logging
This commit is contained in:
parent
ef769e40b6
commit
6c07d47b1b
@ -4,7 +4,7 @@ from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""Application settings following 12-factor app principles."""
|
||||
env: str = Field(default='DEV', alias="ENV")
|
||||
|
||||
# Server settings
|
||||
host: str = Field(default="0.0.0.0", alias="HOST")
|
||||
@ -5,7 +5,7 @@ from sqlalchemy import MetaData, create_engine
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker
|
||||
|
||||
from app.core.config import settings
|
||||
from app.config import settings
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
42
app/logging.py
Normal file
42
app/logging.py
Normal file
@ -0,0 +1,42 @@
|
||||
"""Logging configuration with structured logging."""
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import structlog
|
||||
|
||||
from app.config import settings
|
||||
|
||||
|
||||
def configure_logging() -> None:
|
||||
"""Configure structured logging."""
|
||||
|
||||
structlog.configure(
|
||||
processors=[
|
||||
structlog.stdlib.filter_by_level,
|
||||
structlog.stdlib.add_logger_name,
|
||||
structlog.stdlib.add_log_level,
|
||||
structlog.stdlib.PositionalArgumentsFormatter(),
|
||||
structlog.processors.TimeStamper(fmt="iso"),
|
||||
structlog.processors.StackInfoRenderer(),
|
||||
structlog.processors.format_exc_info,
|
||||
structlog.processors.UnicodeDecoder(),
|
||||
structlog.processors.JSONRenderer(
|
||||
) if not settings.debug else structlog.dev.ConsoleRenderer(),
|
||||
],
|
||||
context_class=dict,
|
||||
logger_factory=structlog.stdlib.LoggerFactory(),
|
||||
wrapper_class=structlog.stdlib.BoundLogger,
|
||||
cache_logger_on_first_use=True,
|
||||
)
|
||||
|
||||
# Configure standard logging
|
||||
logging.basicConfig(
|
||||
format="%(message)s",
|
||||
stream=sys.stdout,
|
||||
level=getattr(logging, settings.log_level.upper()),
|
||||
)
|
||||
|
||||
|
||||
def get_logger(name: str) -> structlog.BoundLogger:
|
||||
"""Get a configured logger instance."""
|
||||
return structlog.get_logger(name) # type:ignore[no-any-return]
|
||||
36
app/middleware.py
Normal file
36
app/middleware.py
Normal file
@ -0,0 +1,36 @@
|
||||
from typing import Callable
|
||||
|
||||
from fastapi import Request, Response
|
||||
from slowapi import Limiter, _rate_limit_exceeded_handler
|
||||
from slowapi.errors import RateLimitExceeded
|
||||
from slowapi.middleware import SlowAPIMiddleware
|
||||
from slowapi.util import get_remote_address
|
||||
|
||||
from app.config import settings
|
||||
from app.logging import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
# Rate limiter
|
||||
limiter = Limiter(key_func=get_remote_address)
|
||||
|
||||
|
||||
async def logging_middleware(request: Request, call_next: Callable) -> Response:
|
||||
"""Log all requests and responses."""
|
||||
logger.debug(
|
||||
"Request received",
|
||||
method=request.method,
|
||||
url=str(request.url),
|
||||
client_ip=get_remote_address(request)
|
||||
)
|
||||
|
||||
response = await call_next(request)
|
||||
|
||||
logger.debug(
|
||||
"Response sent",
|
||||
status_code=response.status_code,
|
||||
method=request.method,
|
||||
url=str(request.url)
|
||||
)
|
||||
|
||||
return response
|
||||
@ -1,7 +1,7 @@
|
||||
"""Health check endpoints."""
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.core.database import DatabaseService
|
||||
from app.database import DatabaseService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
31
main.py
31
main.py
@ -1,17 +1,38 @@
|
||||
"""
|
||||
Main entry point for the Loan Operations API.
|
||||
"""
|
||||
import uvicorn
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
import sentry_sdk
|
||||
from ddtrace import patch_all
|
||||
from fastapi import APIRouter, FastAPI
|
||||
from sentry_sdk.integrations.fastapi import FastApiIntegration
|
||||
|
||||
from app.core.config import settings
|
||||
from app.config import settings
|
||||
from app.logging import configure_logging, get_logger
|
||||
from app.middleware import logging_middleware
|
||||
from app.resources import health
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
"""Create and configure the FastAPI application."""
|
||||
|
||||
# Configure monitoring
|
||||
if settings.sentry_dsn:
|
||||
sentry_sdk.init(
|
||||
dsn=settings.sentry_dsn,
|
||||
integrations=[FastApiIntegration()],
|
||||
traces_sample_rate=1.0,
|
||||
environment=settings.dd_env,
|
||||
)
|
||||
|
||||
if settings.dd_service:
|
||||
# Configure Datadog tracing
|
||||
patch_all()
|
||||
|
||||
# Configure logging
|
||||
configure_logging()
|
||||
logger = get_logger(__name__)
|
||||
|
||||
# Create FastAPI app
|
||||
app = FastAPI(
|
||||
title="Loan Operations API",
|
||||
description="SBA Loan Operations API",
|
||||
@ -29,6 +50,8 @@ def create_app() -> FastAPI:
|
||||
def main() -> None:
|
||||
"""Run the application."""
|
||||
|
||||
import uvicorn
|
||||
|
||||
uvicorn.run(
|
||||
app,
|
||||
host=settings.host,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user