From 7d4efe7bdaf6f2b42443504d8e4f05a5e593095d Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Thu, 26 Nov 2020 19:17:05 +0100 Subject: [PATCH] Improved service providing and app hosting --- src/sh_edraft/hosting/application_host.py | 9 +++- src/sh_edraft/hosting/application_runtime.py | 14 +++++-- .../hosting/base/application_host_base.py | 5 +++ .../hosting/base/application_runtime_base.py | 7 +++- src/sh_edraft/hosting/hosting_environment.py | 2 +- src/sh_edraft/logging/logger.py | 34 +++++++++++---- .../service/base/service_provider_base.py | 2 +- src/sh_edraft/service/service_provider.py | 2 +- src/tests_dev/program.py | 41 ++++++++++++++++++- 9 files changed, 97 insertions(+), 19 deletions(-) diff --git a/src/sh_edraft/hosting/application_host.py b/src/sh_edraft/hosting/application_host.py index edfa6613..f1342626 100644 --- a/src/sh_edraft/hosting/application_host.py +++ b/src/sh_edraft/hosting/application_host.py @@ -3,6 +3,8 @@ from datetime import datetime from sh_edraft.configuration.configuration import Configuration from sh_edraft.configuration.base.configuration_base import ConfigurationBase +from sh_edraft.hosting.base.environment_base import EnvironmentBase +from sh_edraft.hosting.hosting_environment import HostingEnvironment from sh_edraft.hosting.application_runtime import ApplicationRuntime from sh_edraft.hosting.base.application_host_base import ApplicationHostBase from sh_edraft.service.service_provider import ServiceProvider @@ -17,7 +19,8 @@ class ApplicationHost(ApplicationHostBase): self._args: list[str] = sys.argv self._config = Configuration() - self._app_runtime = ApplicationRuntime(self._config) + self._environment = HostingEnvironment() + self._app_runtime = ApplicationRuntime(self._config, self._environment) self._services = ServiceProvider(self._app_runtime) self._start_time: datetime = datetime.now() @@ -27,6 +30,10 @@ class ApplicationHost(ApplicationHostBase): def name(self) -> str: return self._name + @property + def environment(self) -> EnvironmentBase: + return self._environment + @property def configuration(self) -> ConfigurationBase: return self._config diff --git a/src/sh_edraft/hosting/application_runtime.py b/src/sh_edraft/hosting/application_runtime.py index e94ca901..3252ecbe 100644 --- a/src/sh_edraft/hosting/application_runtime.py +++ b/src/sh_edraft/hosting/application_runtime.py @@ -1,21 +1,27 @@ from datetime import datetime -from sh_edraft.configuration.base import ConfigurationBase +from sh_edraft.configuration.base.configuration_base import ConfigurationBase +from sh_edraft.hosting.base.environment_base import EnvironmentBase from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase class ApplicationRuntime(ApplicationRuntimeBase): - def __init__(self, config: ConfigurationBase): + def __init__(self, config: ConfigurationBase, runtime: EnvironmentBase): ApplicationRuntimeBase.__init__(self) - self._configuration = config + self._app_runtime = runtime + self._app_configuration = config self._start_time: datetime = datetime.now() self._end_time: datetime = datetime.now() + + @property + def environment(self) -> EnvironmentBase: + return self._app_runtime @property def configuration(self) -> ConfigurationBase: - return self._configuration + return self._app_configuration @property def start_time(self) -> datetime: diff --git a/src/sh_edraft/hosting/base/application_host_base.py b/src/sh_edraft/hosting/base/application_host_base.py index 0ed3b6e4..4e6c88e5 100644 --- a/src/sh_edraft/hosting/base/application_host_base.py +++ b/src/sh_edraft/hosting/base/application_host_base.py @@ -1,6 +1,7 @@ from abc import ABC, abstractmethod from sh_edraft.configuration.base.configuration_base import ConfigurationBase +from sh_edraft.hosting.base.environment_base import EnvironmentBase from sh_edraft.service.base.service_provider_base import ServiceProviderBase @@ -13,6 +14,10 @@ class ApplicationHostBase(ABC): @abstractmethod def name(self) -> str: pass + @property + @abstractmethod + def environment(self) -> EnvironmentBase: pass + @property @abstractmethod def configuration(self) -> ConfigurationBase: pass diff --git a/src/sh_edraft/hosting/base/application_runtime_base.py b/src/sh_edraft/hosting/base/application_runtime_base.py index c7d364d6..8d5ec5cc 100644 --- a/src/sh_edraft/hosting/base/application_runtime_base.py +++ b/src/sh_edraft/hosting/base/application_runtime_base.py @@ -1,7 +1,8 @@ from abc import ABC, abstractmethod from datetime import datetime -from sh_edraft.configuration.base import ConfigurationBase +from sh_edraft.configuration.base.configuration_base import ConfigurationBase +from sh_edraft.hosting.base.environment_base import EnvironmentBase class ApplicationRuntimeBase(ABC): @@ -9,6 +10,10 @@ class ApplicationRuntimeBase(ABC): @abstractmethod def __init__(self): pass + @property + @abstractmethod + def environment(self) -> EnvironmentBase: pass + @property @abstractmethod def configuration(self) -> ConfigurationBase: pass diff --git a/src/sh_edraft/hosting/hosting_environment.py b/src/sh_edraft/hosting/hosting_environment.py index 91c011d0..e1ecc15b 100644 --- a/src/sh_edraft/hosting/hosting_environment.py +++ b/src/sh_edraft/hosting/hosting_environment.py @@ -6,7 +6,7 @@ from sh_edraft.hosting.model.environment_name import EnvironmentName class HostingEnvironment(EnvironmentBase): - def __init__(self, name: EnvironmentName = None, crp: str = './'): + def __init__(self, name: EnvironmentName = EnvironmentName.production, crp: str = './'): EnvironmentBase.__init__(self) self._name: Optional[EnvironmentName] = name diff --git a/src/sh_edraft/logging/logger.py b/src/sh_edraft/logging/logger.py index 6305725a..51137ce0 100644 --- a/src/sh_edraft/logging/logger.py +++ b/src/sh_edraft/logging/logger.py @@ -3,7 +3,7 @@ import os import traceback from string import Template -from sh_edraft.hosting.base import ApplicationHostBase +from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase from sh_edraft.logging.base.logger_base import LoggerBase from sh_edraft.logging.model import LoggingSettings from sh_edraft.logging.model.logging_level import LoggingLevel @@ -13,16 +13,16 @@ from sh_edraft.utils.console import Console class Logger(LoggerBase): - def __init__(self, logging_settings: LoggingSettings, time_format: TimeFormatSettings, app_host: ApplicationHostBase): + def __init__(self, logging_settings: LoggingSettings, time_format: TimeFormatSettings, app_runtime: ApplicationRuntimeBase): LoggerBase.__init__(self) + self._app_runtime = app_runtime self._log_settings: LoggingSettings = logging_settings self._time_format_settings: TimeFormatSettings = time_format - self._app_host = app_host self._log = Template(self._log_settings.filename).substitute( - date_time_now=self._app_host.date_time_now.strftime(self._time_format_settings.date_time_format), - start_time=self._app_host.start_time.strftime(self._time_format_settings.date_time_log_format) + date_time_now=self._app_runtime.date_time_now.strftime(self._time_format_settings.date_time_format), + start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format) ) self._path = self._log_settings.path self._level = self._log_settings.level @@ -47,7 +47,7 @@ class Logger(LoggerBase): if not os.path.exists(self._path): os.mkdir(self._path) except Exception as e: - self.fatal(__name__, 'Cannot create log dir', ex=e) + self._fatal_console(__name__, 'Cannot create log dir', ex=e) """ create new log file """ try: @@ -57,16 +57,19 @@ class Logger(LoggerBase): Console.write_line(f'[{__name__}]: Using log file: {path}') f.close() except Exception as e: - self.fatal(__name__, 'Cannot open log file', ex=e) + self._fatal_console(__name__, 'Cannot open log file', ex=e) def _append_log(self, string): try: # open log file and append always + if not os.path.isdir(self._path): + self._fatal_console(__name__, 'Log directory not found') + with open(self._path + self._log, "a+", encoding="utf-8") as f: f.write(string + '\n') f.close() except Exception as e: - self.error(__name__, f'Cannot append log file, message: {string}', ex=e) + self._fatal_console(__name__, f'Cannot append log file, message: {string}', ex=e) def _get_string(self, name: str, level: LoggingLevel, message: str) -> str: log_level = level.name @@ -156,3 +159,18 @@ class Logger(LoggerBase): Console.write_line(output, 'red') exit() + + def _fatal_console(self, name: str, message: str, ex: Exception = None): + output = '' + if ex is not None: + tb = traceback.format_exc() + self.error(name, message) + output = self._get_string(name, LoggingLevel.ERROR, f'{ex} -> {tb}') + else: + output = self._get_string(name, LoggingLevel.ERROR, message) + + # check if message can be shown in console + if self._console.value >= LoggingLevel.FATAL.value: + Console.write_line(output, 'red') + + exit() diff --git a/src/sh_edraft/service/base/service_provider_base.py b/src/sh_edraft/service/base/service_provider_base.py index d9dfa000..58d3a64f 100644 --- a/src/sh_edraft/service/base/service_provider_base.py +++ b/src/sh_edraft/service/base/service_provider_base.py @@ -18,7 +18,7 @@ class ServiceProviderBase(ServiceBase): def add_scoped(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): pass @abstractmethod - def add_singleton(self, service_type: Type[ServiceBase], service: ServiceBase): pass + def add_singleton(self, service_type: Type[ServiceBase], service: Callable[ServiceBase]): pass @abstractmethod def get_service(self, instance_type: Type[ServiceBase]) -> Callable[ServiceBase]: pass diff --git a/src/sh_edraft/service/service_provider.py b/src/sh_edraft/service/service_provider.py index 36548cfe..40173ea0 100644 --- a/src/sh_edraft/service/service_provider.py +++ b/src/sh_edraft/service/service_provider.py @@ -43,7 +43,7 @@ class ServiceProvider(ServiceProviderBase): def add_scoped(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): self._scoped_services[service_type] = service - def add_singleton(self, service_type: Type[ServiceBase], service: ServiceBase): + def add_singleton(self, service_type: Type[ServiceBase], service: Callable[ServiceBase]): for known_service in self._singleton_services: if type(known_service) == type(service_type): raise Exception(f'Service with type {type(service_type)} already exists') diff --git a/src/tests_dev/program.py b/src/tests_dev/program.py index 69d2796b..5c8a6356 100644 --- a/src/tests_dev/program.py +++ b/src/tests_dev/program.py @@ -1,7 +1,14 @@ from typing import Optional +from sh_edraft.configuration.base import ConfigurationBase from sh_edraft.hosting import ApplicationHost from sh_edraft.hosting.base import ApplicationBase +from sh_edraft.hosting.model import EnvironmentName +from sh_edraft.logging import Logger +from sh_edraft.logging.base import LoggerBase +from sh_edraft.logging.model import LoggingSettings +from sh_edraft.service.base import ServiceProviderBase +from sh_edraft.time.model import TimeFormatSettings class Program(ApplicationBase): @@ -11,14 +18,44 @@ class Program(ApplicationBase): self._app_host: Optional[ApplicationHost] = None + self._services: Optional[ServiceProviderBase] = None + self._configuration: Optional[ConfigurationBase] = None + def create_application_host(self): self._app_host = ApplicationHost('CPL_DEV_Test') + self._services = self._app_host.services + self._configuration = self._app_host.configuration + + self._app_host.environment.name = EnvironmentName.development def create_configuration(self): - self._app_host.configuration.create() + self._configuration.create() + + log_settings = LoggingSettings() + log_settings.from_dict({ + "Path": "logs/", + "Filename": "log_$start_time.log", + "ConsoleLogLevel": "TRACE", + "FileLogLevel": "TRACE" + }) + + time_format_settings = TimeFormatSettings() + time_format_settings.from_dict({ + "DateFormat": "%Y-%m-%d", + "TimeFormat": "%H:%M:%S", + "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", + "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" + }) + + self._configuration.add_config_by_type(LoggingSettings, log_settings) + self._configuration.add_config_by_type(TimeFormatSettings, time_format_settings) def create_services(self): - self._app_host.services.create() + self._services.create() + self._services.add_singleton(LoggerBase, Logger) + logger: Logger = self._services.get_service(LoggerBase) + logger.create() + logger.header(self._app_host.name) def main(self): print('RUN')