From 0cc0b7f0bc67aa780563ad7849c08f70f95df4d1 Mon Sep 17 00:00:00 2001 From: grucshetskyaleksei Date: Wed, 27 Sep 2023 00:38:28 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B9?= =?UTF-8?q?=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fastapi_app/.env.example | 15 ++-- src/fastapi_app/lib/app/app.py | 4 +- src/fastapi_app/lib/app/settings.py | 43 ++++------ .../lib/app/split_settings/__init__.py | 12 +++ src/fastapi_app/lib/app/split_settings/api.py | 15 ++++ .../lib/app/split_settings/logger.py | 79 +++++++++++++++++++ .../lib/app/split_settings/postgres.py | 21 +++++ .../lib/app/split_settings/project.py | 19 +++++ .../lib/app/split_settings/utils.py | 4 + 9 files changed, 177 insertions(+), 35 deletions(-) create mode 100644 src/fastapi_app/lib/app/split_settings/__init__.py create mode 100644 src/fastapi_app/lib/app/split_settings/api.py create mode 100644 src/fastapi_app/lib/app/split_settings/logger.py create mode 100644 src/fastapi_app/lib/app/split_settings/postgres.py create mode 100644 src/fastapi_app/lib/app/split_settings/project.py create mode 100644 src/fastapi_app/lib/app/split_settings/utils.py diff --git a/src/fastapi_app/.env.example b/src/fastapi_app/.env.example index d557292..59d34a6 100644 --- a/src/fastapi_app/.env.example +++ b/src/fastapi_app/.env.example @@ -1,10 +1,11 @@ -DB_HOST=db -DB_PORT=5432 -DB_USER=user -DB_PASSWORD=Qwe123 -DB_NAME=api_db +POSTGRES_HOST=db +POSTGRES_PORT=5432 +POSTGRES_USER=user +POSTGRES_PASSWORD=Qwe123 +POSTGRES_NAME=api_db -SERVER_HOST=0.0.0.0 -SERVER_PORT=8000 +NGINX_PORT=80 +API_HOST=0.0.0.0 +API_PORT=8000 JWT_SECRET_KEY=v9LctjUWwol4XbvczPiLFMDtZ8aal7mm diff --git a/src/fastapi_app/lib/app/app.py b/src/fastapi_app/lib/app/app.py index 95e904b..afb337c 100644 --- a/src/fastapi_app/lib/app/app.py +++ b/src/fastapi_app/lib/app/app.py @@ -4,9 +4,9 @@ import logging.config as logging_config import fastapi import lib.api.v1.endpoints as api_v1_endpoints +import lib.app.settings as app_settings from .logger import LOGGING -from .settings import get_settings logging_config.dictConfig(LOGGING) logger = logging.getLogger(__name__) @@ -14,7 +14,7 @@ logger = logging.getLogger(__name__) class Application: def __init__(self) -> None: - self.settings = get_settings() + self.settings = app_settings.settings self.logger = logging.getLogger(__name__) self.producer = None diff --git a/src/fastapi_app/lib/app/settings.py b/src/fastapi_app/lib/app/settings.py index 46d1cbd..3004b27 100644 --- a/src/fastapi_app/lib/app/settings.py +++ b/src/fastapi_app/lib/app/settings.py @@ -1,35 +1,26 @@ -import functools +import logging.config as logging_config import pydantic import pydantic_settings - -class DbSettings(pydantic_settings.BaseSettings): - host: str = pydantic.Field("127.0.0.1", validation_alias="db_host") - port: int = pydantic.Field(5432, validation_alias="db_port") - user: str = pydantic.Field(..., validation_alias="db_user") - password: str = pydantic.Field(..., validation_alias="db_password") - name: str = pydantic.Field("db_name", validation_alias="db_name") - - -class ApiSettings(pydantic_settings.BaseSettings): - host: str = pydantic.Field("0.0.0.0", validation_alias="server_host") - port: int = pydantic.Field(8000, validation_alias="server_port") +import lib.app.split_settings as app_split_settings class Settings(pydantic_settings.BaseSettings): - debug: str = pydantic.Field("false", validation_alias="debug") - db: DbSettings = pydantic.Field(default_factory=lambda: DbSettings()) - api: ApiSettings = pydantic.Field(default_factory=lambda: ApiSettings()) - - jwt_secret_key: str = pydantic.Field(..., validation_alias="jwt_secret_key") - - @pydantic.field_validator("debug") - @classmethod - def validate_debug(cls, v: str) -> bool: - return v.lower() == "true" + api: app_split_settings.ApiSettings = pydantic.Field(default_factory=lambda: app_split_settings.ApiSettings()) + postgres: app_split_settings.PostgresSettings = pydantic.Field( + default_factory=lambda: app_split_settings.PostgresSettings() + ) + logger: app_split_settings.LoggingSettings = pydantic.Field( + default_factory=lambda: app_split_settings.LoggingSettings() + ) + project: app_split_settings.ProjectSettings = pydantic.Field( + default_factory=lambda: app_split_settings.ProjectSettings() + ) -@functools.lru_cache -def get_settings() -> Settings: - return Settings() +settings = Settings() # todo Вынести в инициализацию + +logging_config.dictConfig( + app_split_settings.get_logging_config(**settings.logger.model_dump()) +) diff --git a/src/fastapi_app/lib/app/split_settings/__init__.py b/src/fastapi_app/lib/app/split_settings/__init__.py new file mode 100644 index 0000000..4d3b87b --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/__init__.py @@ -0,0 +1,12 @@ +from .api import * +from .logger import * +from .postgres import * +from .project import * + +__all__ = [ + "ApiSettings", + "LoggingSettings", + "PostgresSettings", + "ProjectSettings", + "get_logging_config", +] diff --git a/src/fastapi_app/lib/app/split_settings/api.py b/src/fastapi_app/lib/app/split_settings/api.py new file mode 100644 index 0000000..3638d34 --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/api.py @@ -0,0 +1,15 @@ +import pydantic_settings + +import lib.app.split_settings.utils as app_split_settings_utils + + +class ApiSettings(pydantic_settings.BaseSettings): + model_config = pydantic_settings.SettingsConfigDict( + env_file=app_split_settings_utils.ENV_PATH, + env_prefix="API_", + env_file_encoding="utf-8", + extra="ignore", + ) + + host: str = "0.0.0.0" + port: int = 8000 diff --git a/src/fastapi_app/lib/app/split_settings/logger.py b/src/fastapi_app/lib/app/split_settings/logger.py new file mode 100644 index 0000000..49fbeff --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/logger.py @@ -0,0 +1,79 @@ +import pydantic_settings + +import lib.app.split_settings.utils as app_split_settings_utils + + +class LoggingSettings(pydantic_settings.BaseSettings): + model_config = pydantic_settings.SettingsConfigDict( + env_file=app_split_settings_utils.ENV_PATH, env_file_encoding="utf-8", extra="ignore" + ) + + log_format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + log_default_endpoints: list[str] = [ + "console", + ] + + log_level_endpoints: str = "INFO" + log_level_loggers: str = "INFO" + log_level_root: str = "INFO" + + +def get_logging_config( + log_format: str, + log_default_endpoints: list[str], + log_level_endpoints: str, + log_level_loggers: str, + log_level_root: str, +): + return { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "verbose": {"format": log_format}, + "default": { + "()": "uvicorn.logging.DefaultFormatter", + "fmt": "%(levelprefix)s %(message)s", + "use_colors": None, + }, + "access": { + "()": "uvicorn.logging.AccessFormatter", + "fmt": "%(levelprefix)s %(client_addr)s - '%(request_line)s' %(status_code)s", + }, + }, + "endpoints": { + "console": { + "level": log_level_endpoints, + "class": "logging.StreamHandler", + "formatter": "verbose", + }, + "default": { + "formatter": "default", + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + }, + "access": { + "formatter": "access", + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + }, + }, + "loggers": { + "": { + "endpoints": log_default_endpoints, + "level": log_level_loggers, + }, + "uvicorn.error": { + "level": log_level_loggers, + }, + "uvicorn.access": { + "endpoints": ["access"], + "level": log_level_loggers, + "propagate": False, + }, + }, + "root": { + "level": log_level_root, + "formatter": "verbose", + "endpoints": log_default_endpoints, + }, + } diff --git a/src/fastapi_app/lib/app/split_settings/postgres.py b/src/fastapi_app/lib/app/split_settings/postgres.py new file mode 100644 index 0000000..62452f6 --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/postgres.py @@ -0,0 +1,21 @@ +import pydantic +import pydantic_settings + +import lib.app.split_settings.utils as app_split_settings_utils + + +class PostgresSettings(pydantic_settings.BaseSettings): + model_config = pydantic_settings.SettingsConfigDict( + env_file=app_split_settings_utils.ENV_PATH, + env_prefix="POSTGRES_", + env_file_encoding="utf-8", + extra="ignore", + ) + + name: str = "database_name" + host: str = "localhost" + port: int = 5432 + user: str = "app" + password: pydantic.SecretStr = pydantic.Field( + default=..., validation_alias=pydantic.AliasChoices("password", "postgres_password") + ) diff --git a/src/fastapi_app/lib/app/split_settings/project.py b/src/fastapi_app/lib/app/split_settings/project.py new file mode 100644 index 0000000..6102809 --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/project.py @@ -0,0 +1,19 @@ +import pydantic +import pydantic_settings + +import lib.app.split_settings.utils as app_split_settings_utils + + +class ProjectSettings(pydantic_settings.BaseSettings): + model_config = pydantic_settings.SettingsConfigDict( + env_file=app_split_settings_utils.ENV_PATH, + env_file_encoding="utf-8", + extra="ignore", + ) + + debug: str = "false" + jwt_secret_key: pydantic.SecretStr = pydantic.Field(default=..., validation_alias="jwt_secret_key") + + @pydantic.field_validator("debug") + def validate_debug(cls, v: str) -> bool: + return v.lower() == "true" diff --git a/src/fastapi_app/lib/app/split_settings/utils.py b/src/fastapi_app/lib/app/split_settings/utils.py new file mode 100644 index 0000000..459631e --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/utils.py @@ -0,0 +1,4 @@ +import pathlib + +BASE_PATH = pathlib.Path(__file__).parent.parent.parent.parent.resolve() +ENV_PATH = BASE_PATH / ".env"