local_service.py
1 import logging 2 import time 3 from typing import Dict 4 5 from litestar import Request 6 from litestar import Response 7 from litestar.di import Provide 8 from litestar.logging import LoggingConfig 9 10 from evidently.errors import EvidentlyError 11 from evidently.legacy.ui.api.projects import create_projects_api 12 from evidently.legacy.ui.api.projects import projects_api_dependencies 13 from evidently.legacy.ui.api.service import service_api 14 from evidently.legacy.ui.api.static import assets_router 15 from evidently.legacy.ui.components.base import AppBuilder 16 from evidently.legacy.ui.components.base import ComponentContext 17 from evidently.legacy.ui.components.base import ServiceComponent 18 from evidently.legacy.ui.components.security import NoSecurityComponent 19 from evidently.legacy.ui.components.security import SecurityComponent 20 from evidently.legacy.ui.components.storage import LocalStorageComponent 21 from evidently.legacy.ui.components.storage import StorageComponent 22 from evidently.legacy.ui.components.telemetry import TelemetryComponent 23 from evidently.legacy.ui.config import AppConfig 24 from evidently.legacy.ui.config import ConfigContext 25 from evidently.legacy.ui.errors import EvidentlyServiceError 26 27 28 def evidently_service_exception_handler(_: Request, exc: EvidentlyServiceError) -> Response: 29 return exc.to_response() 30 31 32 def evidently_exception_handler(_: Request, exc: EvidentlyError) -> Response: 33 return Response(content={"detail": exc.get_message()}, status_code=500) 34 35 36 class LocalServiceComponent(ServiceComponent): 37 debug: bool = False 38 39 def get_api_route_handlers(self, ctx: ComponentContext): 40 guard = ctx.get_component(SecurityComponent).get_auth_guard() 41 return [create_projects_api(guard), service_api()] 42 43 def get_dependencies(self, ctx: ComponentContext) -> Dict[str, Provide]: 44 deps = super().get_dependencies(ctx) 45 deps.update(projects_api_dependencies) 46 return deps 47 48 def get_route_handlers(self, ctx: ComponentContext): 49 return [assets_router()] 50 51 def apply(self, ctx: ComponentContext, builder: AppBuilder): 52 super().apply(ctx, builder) 53 assert isinstance(ctx, ConfigContext) 54 builder.exception_handlers[EvidentlyServiceError] = evidently_service_exception_handler 55 builder.exception_handlers[EvidentlyError] = evidently_exception_handler 56 builder.kwargs["debug"] = self.debug 57 if self.debug: 58 log_config = create_logging() 59 builder.kwargs["logging_config"] = LoggingConfig(**log_config) 60 61 62 def create_logging() -> dict: 63 logging.Formatter.converter = time.gmtime 64 return { 65 "version": 1, 66 "log_exceptions": "always", 67 "disable_existing_loggers": False, 68 "formatters": { 69 "default": { 70 "()": "logging.Formatter", 71 "format": "%(asctime)s %(levelname)-8s %(name)-15s %(message)s", 72 "datefmt": "%Y-%m-%dT%H:%M:%SZ", 73 }, 74 "access": { 75 "()": "logging.Formatter", 76 "format": "%(asctime)s %(levelname)-8s %(name)-15s %(message)s", 77 "datefmt": "%Y-%m-%dT%H:%M:%SZ", 78 }, 79 "standard": { 80 "()": "logging.Formatter", 81 "format": "%(asctime)s %(levelname)-8s %(name)-15s %(message)s", 82 "datefmt": "%Y-%m-%dT%H:%M:%SZ", 83 }, 84 }, 85 "handlers": { 86 "default": { 87 "formatter": "default", 88 "class": "logging.StreamHandler", 89 "stream": "ext://sys.stdout", 90 }, 91 "access": { 92 "formatter": "access", 93 "class": "logging.StreamHandler", 94 "stream": "ext://sys.stdout", 95 }, 96 }, 97 "loggers": { 98 "litestar": {"handlers": ["default"]}, 99 "uvicorn": {"handlers": ["default"], "level": "INFO", "propagate": False}, 100 "uvicorn.error": {"level": "INFO"}, 101 "uvicorn.access": {"handlers": ["access"], "level": "INFO", "propagate": False}, 102 }, 103 } 104 105 106 class LocalConfig(AppConfig): 107 security: SecurityComponent = NoSecurityComponent() 108 service: ServiceComponent = LocalServiceComponent() 109 storage: StorageComponent = LocalStorageComponent() 110 telemetry: TelemetryComponent = TelemetryComponent()