Improved service providing and app hosting

This commit is contained in:
Sven Heidemann 2020-11-26 19:17:05 +01:00
parent c6d1dce577
commit 7d4efe7bda
9 changed files with 97 additions and 19 deletions

View File

@ -3,6 +3,8 @@ from datetime import datetime
from sh_edraft.configuration.configuration import Configuration from sh_edraft.configuration.configuration import Configuration
from sh_edraft.configuration.base.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.hosting_environment import HostingEnvironment
from sh_edraft.hosting.application_runtime import ApplicationRuntime from sh_edraft.hosting.application_runtime import ApplicationRuntime
from sh_edraft.hosting.base.application_host_base import ApplicationHostBase from sh_edraft.hosting.base.application_host_base import ApplicationHostBase
from sh_edraft.service.service_provider import ServiceProvider from sh_edraft.service.service_provider import ServiceProvider
@ -17,7 +19,8 @@ class ApplicationHost(ApplicationHostBase):
self._args: list[str] = sys.argv self._args: list[str] = sys.argv
self._config = Configuration() 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._services = ServiceProvider(self._app_runtime)
self._start_time: datetime = datetime.now() self._start_time: datetime = datetime.now()
@ -27,6 +30,10 @@ class ApplicationHost(ApplicationHostBase):
def name(self) -> str: def name(self) -> str:
return self._name return self._name
@property
def environment(self) -> EnvironmentBase:
return self._environment
@property @property
def configuration(self) -> ConfigurationBase: def configuration(self) -> ConfigurationBase:
return self._config return self._config

View File

@ -1,21 +1,27 @@
from datetime import datetime 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 from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase
class ApplicationRuntime(ApplicationRuntimeBase): class ApplicationRuntime(ApplicationRuntimeBase):
def __init__(self, config: ConfigurationBase): def __init__(self, config: ConfigurationBase, runtime: EnvironmentBase):
ApplicationRuntimeBase.__init__(self) ApplicationRuntimeBase.__init__(self)
self._configuration = config self._app_runtime = runtime
self._app_configuration = config
self._start_time: datetime = datetime.now() self._start_time: datetime = datetime.now()
self._end_time: datetime = datetime.now() self._end_time: datetime = datetime.now()
@property
def environment(self) -> EnvironmentBase:
return self._app_runtime
@property @property
def configuration(self) -> ConfigurationBase: def configuration(self) -> ConfigurationBase:
return self._configuration return self._app_configuration
@property @property
def start_time(self) -> datetime: def start_time(self) -> datetime:

View File

@ -1,6 +1,7 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from sh_edraft.configuration.base.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.service.base.service_provider_base import ServiceProviderBase from sh_edraft.service.base.service_provider_base import ServiceProviderBase
@ -13,6 +14,10 @@ class ApplicationHostBase(ABC):
@abstractmethod @abstractmethod
def name(self) -> str: pass def name(self) -> str: pass
@property
@abstractmethod
def environment(self) -> EnvironmentBase: pass
@property @property
@abstractmethod @abstractmethod
def configuration(self) -> ConfigurationBase: pass def configuration(self) -> ConfigurationBase: pass

View File

@ -1,7 +1,8 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from datetime import datetime 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): class ApplicationRuntimeBase(ABC):
@ -9,6 +10,10 @@ class ApplicationRuntimeBase(ABC):
@abstractmethod @abstractmethod
def __init__(self): pass def __init__(self): pass
@property
@abstractmethod
def environment(self) -> EnvironmentBase: pass
@property @property
@abstractmethod @abstractmethod
def configuration(self) -> ConfigurationBase: pass def configuration(self) -> ConfigurationBase: pass

View File

@ -6,7 +6,7 @@ from sh_edraft.hosting.model.environment_name import EnvironmentName
class HostingEnvironment(EnvironmentBase): class HostingEnvironment(EnvironmentBase):
def __init__(self, name: EnvironmentName = None, crp: str = './'): def __init__(self, name: EnvironmentName = EnvironmentName.production, crp: str = './'):
EnvironmentBase.__init__(self) EnvironmentBase.__init__(self)
self._name: Optional[EnvironmentName] = name self._name: Optional[EnvironmentName] = name

View File

@ -3,7 +3,7 @@ import os
import traceback import traceback
from string import Template 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.base.logger_base import LoggerBase
from sh_edraft.logging.model import LoggingSettings from sh_edraft.logging.model import LoggingSettings
from sh_edraft.logging.model.logging_level import LoggingLevel from sh_edraft.logging.model.logging_level import LoggingLevel
@ -13,16 +13,16 @@ from sh_edraft.utils.console import Console
class Logger(LoggerBase): 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) LoggerBase.__init__(self)
self._app_runtime = app_runtime
self._log_settings: LoggingSettings = logging_settings self._log_settings: LoggingSettings = logging_settings
self._time_format_settings: TimeFormatSettings = time_format self._time_format_settings: TimeFormatSettings = time_format
self._app_host = app_host
self._log = Template(self._log_settings.filename).substitute( 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), date_time_now=self._app_runtime.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) start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format)
) )
self._path = self._log_settings.path self._path = self._log_settings.path
self._level = self._log_settings.level self._level = self._log_settings.level
@ -47,7 +47,7 @@ class Logger(LoggerBase):
if not os.path.exists(self._path): if not os.path.exists(self._path):
os.mkdir(self._path) os.mkdir(self._path)
except Exception as e: 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 """ """ create new log file """
try: try:
@ -57,16 +57,19 @@ class Logger(LoggerBase):
Console.write_line(f'[{__name__}]: Using log file: {path}') Console.write_line(f'[{__name__}]: Using log file: {path}')
f.close() f.close()
except Exception as e: 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): def _append_log(self, string):
try: try:
# open log file and append always # 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: with open(self._path + self._log, "a+", encoding="utf-8") as f:
f.write(string + '\n') f.write(string + '\n')
f.close() f.close()
except Exception as e: 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: def _get_string(self, name: str, level: LoggingLevel, message: str) -> str:
log_level = level.name log_level = level.name
@ -156,3 +159,18 @@ class Logger(LoggerBase):
Console.write_line(output, 'red') Console.write_line(output, 'red')
exit() 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()

View File

@ -18,7 +18,7 @@ class ServiceProviderBase(ServiceBase):
def add_scoped(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): pass def add_scoped(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): pass
@abstractmethod @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 @abstractmethod
def get_service(self, instance_type: Type[ServiceBase]) -> Callable[ServiceBase]: pass def get_service(self, instance_type: Type[ServiceBase]) -> Callable[ServiceBase]: pass

View File

@ -43,7 +43,7 @@ class ServiceProvider(ServiceProviderBase):
def add_scoped(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): def add_scoped(self, service_type: Type[ServiceBase], service: Type[ServiceBase]):
self._scoped_services[service_type] = service 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: for known_service in self._singleton_services:
if type(known_service) == type(service_type): if type(known_service) == type(service_type):
raise Exception(f'Service with type {type(service_type)} already exists') raise Exception(f'Service with type {type(service_type)} already exists')

View File

@ -1,7 +1,14 @@
from typing import Optional from typing import Optional
from sh_edraft.configuration.base import ConfigurationBase
from sh_edraft.hosting import ApplicationHost from sh_edraft.hosting import ApplicationHost
from sh_edraft.hosting.base import ApplicationBase 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): class Program(ApplicationBase):
@ -11,14 +18,44 @@ class Program(ApplicationBase):
self._app_host: Optional[ApplicationHost] = None self._app_host: Optional[ApplicationHost] = None
self._services: Optional[ServiceProviderBase] = None
self._configuration: Optional[ConfigurationBase] = None
def create_application_host(self): def create_application_host(self):
self._app_host = ApplicationHost('CPL_DEV_Test') 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): 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): 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): def main(self):
print('RUN') print('RUN')