fastapi-startkit 0.1.1__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/PKG-INFO +2 -2
- fastapi_startkit-0.1.3/fastapi_startkit/application.py +132 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/configuration/Configuration.py +1 -6
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/configuration/providers/ConfigurationProvider.py +0 -3
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/container/container.py +27 -13
- fastapi_startkit-0.1.3/fastapi_startkit/facades/Facade.py +4 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/loader/Loader.py +1 -1
- fastapi_startkit-0.1.3/fastapi_startkit/logging/ChannelFactory.py +20 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/Logger.py +2 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/__init__.py +1 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/channels/BaseChannel.py +60 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/channels/DailyChannel.py +17 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/channels/MultiBaseChannel.py +64 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/channels/SingleChannel.py +14 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/channels/SlackChannel.py +19 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/channels/StackChannel.py +30 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/channels/SyslogChannel.py +14 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/channels/TerminalChannel.py +14 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/channels/__init__.py +8 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/configs/logging.py +20 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/drivers/BaseDriver.py +25 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/drivers/LogSingleDriver.py +84 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/drivers/LogSlackDriver.py +94 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/drivers/LogSyslogDriver.py +48 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/drivers/LogTerminalDriver.py +60 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/drivers/__init__.py +5 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/factory.py +15 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/listeners.py +15 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/managers/LoggingManager.py +11 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/managers/__init__.py +1 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/providers/LoggingProvider.py +36 -0
- fastapi_startkit-0.1.3/fastapi_startkit/logging/providers/__init__.py +1 -0
- fastapi_startkit-0.1.3/fastapi_startkit/providers/Provider.py +21 -0
- fastapi_startkit-0.1.3/fastapi_startkit/providers/__init__.py +3 -0
- fastapi_startkit-0.1.3/fastapi_startkit/tests/configurations/test_config_merge.py +54 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/utils/structures.py +8 -9
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/pyproject.toml +2 -2
- fastapi_startkit-0.1.1/fastapi_startkit/application.py +0 -40
- fastapi_startkit-0.1.1/fastapi_startkit/facades/Facade.py +0 -5
- fastapi_startkit-0.1.1/fastapi_startkit/providers/ConfigurationProvider.py +0 -13
- fastapi_startkit-0.1.1/fastapi_startkit/providers/Provider.py +0 -14
- fastapi_startkit-0.1.1/fastapi_startkit/providers/__init__.py +0 -4
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/__init__.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/configuration/__init__.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/configuration/helpers.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/configuration/providers/__init__.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/container/__init__.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/environment/environment.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/DD.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/ExceptionHandler.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/__init__.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/exceptionite/__init__.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/exceptionite/blocks.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/exceptionite/controllers.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/exceptionite/solutions.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/exceptionite/tabs.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/exceptions.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/handlers/DumpExceptionHandler.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/handlers/HttpExceptionHandler.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/exceptions/handlers/ModelNotFoundHandler.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Auth.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Auth.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Broadcast.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Cache.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Config.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Config.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Dump.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Dump.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Gate.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Gate.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Hash.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Hash.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Loader.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Loader.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Mail.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Mail.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Notification.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Notification.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Queue.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Queue.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/RateLimiter.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/RateLimiter.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Request.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Request.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Response.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Response.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Session.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Session.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Storage.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Storage.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Url.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/Url.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/View.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/View.pyi +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/facades/__init__.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/loader/__init__.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/utils/__init__.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/utils/collections.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/utils/console.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/utils/data/mime.types +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/utils/filesystem.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/utils/http.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/utils/location.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/utils/str.py +0 -0
- {fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/utils/time.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-startkit
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Fastapi_Startkit components
|
|
5
5
|
Author: Bedram Tamang
|
|
6
6
|
Author-email: tmgbedu@gmail.com
|
|
7
7
|
Requires-Python: >=3.12,<4.0
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Type, Callable, Any
|
|
3
|
+
|
|
4
|
+
from fastapi import FastAPI, APIRouter
|
|
5
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
6
|
+
|
|
7
|
+
from .container import Container
|
|
8
|
+
from .environment.environment import LoadEnvironment
|
|
9
|
+
from .configuration.providers import ConfigurationProvider
|
|
10
|
+
|
|
11
|
+
def app() -> 'Container':
|
|
12
|
+
return Container.instance()
|
|
13
|
+
|
|
14
|
+
class Application(Container):
|
|
15
|
+
DEFAULT_PROVIDERS = [
|
|
16
|
+
ConfigurationProvider,
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
def __init__(self, base_path: str = None, providers=None):
|
|
20
|
+
super().__init__()
|
|
21
|
+
|
|
22
|
+
self.base_path: str = base_path
|
|
23
|
+
self.providers = self.DEFAULT_PROVIDERS + (providers or [])
|
|
24
|
+
self.published_resources = {}
|
|
25
|
+
|
|
26
|
+
# Set global singleton
|
|
27
|
+
Container.set_instance(self)
|
|
28
|
+
|
|
29
|
+
# Boot application
|
|
30
|
+
self.load_environment()
|
|
31
|
+
self.configure_paths()
|
|
32
|
+
self.register_providers()
|
|
33
|
+
|
|
34
|
+
self._fastapi = FastAPI()
|
|
35
|
+
self.load_providers()
|
|
36
|
+
|
|
37
|
+
def register_providers(self):
|
|
38
|
+
providers = []
|
|
39
|
+
for provider_data in self.providers:
|
|
40
|
+
config = {}
|
|
41
|
+
if isinstance(provider_data, tuple):
|
|
42
|
+
provider_class, config = provider_data
|
|
43
|
+
else:
|
|
44
|
+
provider_class = provider_data
|
|
45
|
+
|
|
46
|
+
provider = provider_class(self, config=config)
|
|
47
|
+
provider.register()
|
|
48
|
+
providers.append(provider)
|
|
49
|
+
|
|
50
|
+
self.providers = providers
|
|
51
|
+
return self
|
|
52
|
+
|
|
53
|
+
def load_providers(self):
|
|
54
|
+
for provider in self.providers:
|
|
55
|
+
self.resolve(provider.boot)
|
|
56
|
+
return self
|
|
57
|
+
|
|
58
|
+
def use_fastapi(self, fastapi: FastAPI):
|
|
59
|
+
self._fastapi = fastapi
|
|
60
|
+
return self
|
|
61
|
+
|
|
62
|
+
def get(self, path: str, **kwargs) -> Callable:
|
|
63
|
+
return self._fastapi.get(path, **kwargs)
|
|
64
|
+
|
|
65
|
+
def post(self, path: str, **kwargs) -> Callable:
|
|
66
|
+
return self._fastapi.post(path, **kwargs)
|
|
67
|
+
|
|
68
|
+
def put(self, path: str, **kwargs) -> Callable:
|
|
69
|
+
return self._fastapi.put(path, **kwargs)
|
|
70
|
+
|
|
71
|
+
def delete(self, path: str, **kwargs) -> Callable:
|
|
72
|
+
return self._fastapi.delete(path, **kwargs)
|
|
73
|
+
|
|
74
|
+
def patch(self, path: str, **kwargs) -> Callable:
|
|
75
|
+
return self._fastapi.patch(path, **kwargs)
|
|
76
|
+
|
|
77
|
+
def options(self, path: str, **kwargs) -> Callable:
|
|
78
|
+
return self._fastapi.options(path, **kwargs)
|
|
79
|
+
|
|
80
|
+
def head(self, path: str, **kwargs) -> Callable:
|
|
81
|
+
return self._fastapi.head(path, **kwargs)
|
|
82
|
+
|
|
83
|
+
def trace(self, path: str, **kwargs) -> Callable:
|
|
84
|
+
return self._fastapi.trace(path, **kwargs)
|
|
85
|
+
|
|
86
|
+
# Include routers
|
|
87
|
+
def include_router(self, router: APIRouter, **kwargs):
|
|
88
|
+
self._fastapi.include_router(router, **kwargs)
|
|
89
|
+
return self
|
|
90
|
+
|
|
91
|
+
# Add middleware
|
|
92
|
+
def add_middleware(self, middleware_class: Type[BaseHTTPMiddleware], **options):
|
|
93
|
+
self._fastapi.add_middleware(middleware_class, **options)
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
# Add event handlers (startup/shutdown)
|
|
97
|
+
def add_event_handler(self, event_type: str, func: Callable[..., Any]):
|
|
98
|
+
self._fastapi.add_event_handler(event_type, func)
|
|
99
|
+
return self
|
|
100
|
+
|
|
101
|
+
# Mount sub-apps
|
|
102
|
+
def mount(self, path: str, app_instance: FastAPI, **kwargs):
|
|
103
|
+
self._fastapi.mount(path, app_instance, **kwargs)
|
|
104
|
+
return self
|
|
105
|
+
|
|
106
|
+
# Add custom exception handlers
|
|
107
|
+
def add_exception_handler(self, exc_class_or_status_code: Any, handler: Callable[..., Any]):
|
|
108
|
+
self._fastapi.add_exception_handler(exc_class_or_status_code, handler)
|
|
109
|
+
return self
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def fastapi(self) -> FastAPI:
|
|
113
|
+
return self._fastapi
|
|
114
|
+
|
|
115
|
+
def __call__(self, *args, **kwargs):
|
|
116
|
+
return self._fastapi
|
|
117
|
+
|
|
118
|
+
def load_environment(self):
|
|
119
|
+
LoadEnvironment(base_path=self.base_path)
|
|
120
|
+
|
|
121
|
+
def configure_paths(self):
|
|
122
|
+
self.bind('config.location', os.path.join(self.base_path, "config"))
|
|
123
|
+
|
|
124
|
+
def use_config_path(self, path: str = None):
|
|
125
|
+
self.bind('config.location', path)
|
|
126
|
+
|
|
127
|
+
return self
|
|
128
|
+
|
|
129
|
+
def use_storage_path(self, path: str = None):
|
|
130
|
+
self.bind('storage.location', path)
|
|
131
|
+
|
|
132
|
+
return self
|
{fastapi_startkit-0.1.1 → fastapi_startkit-0.1.3}/fastapi_startkit/configuration/Configuration.py
RENAMED
|
@@ -33,11 +33,6 @@ class Configuration:
|
|
|
33
33
|
for name, value in params.items():
|
|
34
34
|
self._config[f"{module_name}.{name.lower()}"] = value
|
|
35
35
|
|
|
36
|
-
# check loaded configuration
|
|
37
|
-
if not self._config.get("application"):
|
|
38
|
-
raise InvalidConfigurationLocation(
|
|
39
|
-
f"Config directory {config_root} does not contain required configuration files."
|
|
40
|
-
)
|
|
41
36
|
|
|
42
37
|
def merge_with(self, path, external_config):
|
|
43
38
|
"""Merge external config at key with project config at same key. It's especially
|
|
@@ -53,7 +48,7 @@ class Configuration:
|
|
|
53
48
|
)
|
|
54
49
|
if isinstance(external_config, str):
|
|
55
50
|
# config is a path and should be loaded
|
|
56
|
-
params = Loader.get_parameters(external_config)
|
|
51
|
+
params = Loader().get_parameters(external_config)
|
|
57
52
|
else:
|
|
58
53
|
params = external_config
|
|
59
54
|
base_config = {name.lower(): value for name, value in params.items()}
|
|
@@ -15,19 +15,33 @@ class Container:
|
|
|
15
15
|
Performs bindings and resolving of objects to and from the container.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
18
|
+
_instance = None
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def set_instance(cls, instance):
|
|
22
|
+
cls._instance = instance
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def instance(cls):
|
|
26
|
+
if cls._instance is None:
|
|
27
|
+
raise RuntimeError("Container not initialized")
|
|
28
|
+
return cls._instance
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def __init__(self):
|
|
32
|
+
if not hasattr(self, 'objects'):
|
|
33
|
+
self.objects = {}
|
|
34
|
+
self.strict = False
|
|
35
|
+
self.override = True
|
|
36
|
+
self.resolve_parameters = {}
|
|
37
|
+
self.remember = False
|
|
38
|
+
self._hooks = {
|
|
39
|
+
"make": {},
|
|
40
|
+
"bind": {},
|
|
41
|
+
"resolve": {},
|
|
42
|
+
}
|
|
43
|
+
self.swaps = {}
|
|
44
|
+
self._remembered = {}
|
|
31
45
|
|
|
32
46
|
def bind(self, name, class_obj):
|
|
33
47
|
"""Bind classes into the container with a key value pair.
|
|
@@ -25,7 +25,7 @@ class Loader:
|
|
|
25
25
|
module_paths = list(map(as_filepath, files_or_directories))
|
|
26
26
|
for module_loader, name, _ in pkgutil.iter_modules(module_paths):
|
|
27
27
|
module = load(
|
|
28
|
-
f"{
|
|
28
|
+
f"{module_loader.path}/{name}.py",
|
|
29
29
|
raise_exception=raise_exception,
|
|
30
30
|
)
|
|
31
31
|
_modules.update({name: module})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from .channels import SingleChannel, DailyChannel, SlackChannel, StackChannel, SyslogChannel, TerminalChannel
|
|
2
|
+
|
|
3
|
+
class ChannelFactory:
|
|
4
|
+
|
|
5
|
+
channels = {
|
|
6
|
+
'single': SingleChannel,
|
|
7
|
+
'daily': DailyChannel,
|
|
8
|
+
'slack': SlackChannel,
|
|
9
|
+
'stack': StackChannel,
|
|
10
|
+
'syslog': SyslogChannel,
|
|
11
|
+
'terminal': TerminalChannel
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def make(cls, channel):
|
|
16
|
+
return cls.channels.get(channel)
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def register(cls, channel_dictionary):
|
|
20
|
+
cls.channels.update(channel_dictionary)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .Logger import Logger
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import pendulum
|
|
2
|
+
from fastapi_startkit.facades import Config
|
|
3
|
+
|
|
4
|
+
class BaseChannel:
|
|
5
|
+
|
|
6
|
+
def get_time(self):
|
|
7
|
+
|
|
8
|
+
return pendulum.now().in_tz(Config.get('logging.channels.timezone', 'UTC'))
|
|
9
|
+
|
|
10
|
+
def emergency(self, message, *args, **kwargs):
|
|
11
|
+
if not self.driver.should_run('emergency', self.max_level):
|
|
12
|
+
return
|
|
13
|
+
|
|
14
|
+
return self.driver.emergency(message, *args, **kwargs)
|
|
15
|
+
|
|
16
|
+
def alert(self, message, *args, **kwargs):
|
|
17
|
+
if not self.driver.should_run('alert', self.max_level):
|
|
18
|
+
return
|
|
19
|
+
|
|
20
|
+
return self.driver.alert(message, *args, **kwargs)
|
|
21
|
+
|
|
22
|
+
def critical(self, message, *args, **kwargs):
|
|
23
|
+
if not self.driver.should_run('critical', self.max_level):
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
return self.driver.critical(message, *args, **kwargs)
|
|
27
|
+
|
|
28
|
+
def error(self, message, *args, **kwargs):
|
|
29
|
+
if not self.driver.should_run('error', self.max_level):
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
return self.driver.error(message, *args, **kwargs)
|
|
33
|
+
|
|
34
|
+
def warning(self, message, *args, **kwargs):
|
|
35
|
+
if not self.driver.should_run('warning', self.max_level):
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
return self.driver.warning(message, *args, **kwargs)
|
|
39
|
+
|
|
40
|
+
def notice(self, message, *args, **kwargs):
|
|
41
|
+
if not self.driver.should_run('notice', self.max_level):
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
return self.driver.notice(message, *args, **kwargs)
|
|
45
|
+
|
|
46
|
+
def info(self, message, *args, **kwargs):
|
|
47
|
+
if not self.driver.should_run('info', self.max_level):
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
return self.driver.info(message, *args, **kwargs)
|
|
51
|
+
|
|
52
|
+
def debug(self, message, *args, **kwargs):
|
|
53
|
+
if not self.driver.should_run('debug', self.max_level):
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
return self.driver.debug(message, *args, **kwargs)
|
|
57
|
+
|
|
58
|
+
def channel(self, channel):
|
|
59
|
+
from ..ChannelFactory import ChannelFactory
|
|
60
|
+
return ChannelFactory().make(channel)()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from ..factory import DriverFactory
|
|
2
|
+
from fastapi_startkit.facades import Config
|
|
3
|
+
from fastapi_startkit.utils.filesystem import make_directory
|
|
4
|
+
import os
|
|
5
|
+
from .BaseChannel import BaseChannel
|
|
6
|
+
|
|
7
|
+
class DailyChannel(BaseChannel):
|
|
8
|
+
|
|
9
|
+
def __init__(self, driver=None, path=None):
|
|
10
|
+
path = path or Config.get('logging.channels.daily.path')
|
|
11
|
+
path = os.path.join(path, self.get_time().to_date_string() + '.log')
|
|
12
|
+
self.max_level = Config.get('logging.channels.daily.level')
|
|
13
|
+
make_directory(path)
|
|
14
|
+
self.driver = DriverFactory.make(driver or Config.get('logging.channels.daily.driver'))(path=path, max_level=self.max_level)
|
|
15
|
+
|
|
16
|
+
def debug(self, message, *args, **kwargs):
|
|
17
|
+
return self.driver.debug(message, *args, **kwargs)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import pendulum
|
|
2
|
+
from fastapi_startkit.facades import Config
|
|
3
|
+
|
|
4
|
+
class MultiBaseChannel:
|
|
5
|
+
|
|
6
|
+
def get_time(self):
|
|
7
|
+
return pendulum.now().in_tz(Config.get('logging.channels.timezone', 'UTC'))
|
|
8
|
+
|
|
9
|
+
def emergency(self, message, *args, **kwargs):
|
|
10
|
+
for channel in self.channels:
|
|
11
|
+
if not channel.driver.should_run('emergency', channel.max_level):
|
|
12
|
+
continue
|
|
13
|
+
|
|
14
|
+
channel.driver.emergency(message, *args, **kwargs)
|
|
15
|
+
|
|
16
|
+
def alert(self, message, *args, **kwargs):
|
|
17
|
+
for channel in self.channels:
|
|
18
|
+
if not channel.driver.should_run('alert', channel.max_level):
|
|
19
|
+
continue
|
|
20
|
+
|
|
21
|
+
channel.driver.alert(message, *args, **kwargs)
|
|
22
|
+
|
|
23
|
+
def critical(self, message, *args, **kwargs):
|
|
24
|
+
for channel in self.channels:
|
|
25
|
+
if not channel.driver.should_run('critical', channel.max_level):
|
|
26
|
+
continue
|
|
27
|
+
|
|
28
|
+
channel.driver.critical(message, *args, **kwargs)
|
|
29
|
+
|
|
30
|
+
def error(self, message, *args, **kwargs):
|
|
31
|
+
for channel in self.channels:
|
|
32
|
+
if not channel.driver.should_run('error', channel.max_level):
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
channel.driver.error(message, *args, **kwargs)
|
|
36
|
+
|
|
37
|
+
def warning(self, message, *args, **kwargs):
|
|
38
|
+
for channel in self.channels:
|
|
39
|
+
if not channel.driver.should_run('warning', channel.max_level):
|
|
40
|
+
continue
|
|
41
|
+
|
|
42
|
+
channel.driver.warning(message, *args, **kwargs)
|
|
43
|
+
|
|
44
|
+
def notice(self, message, *args, **kwargs):
|
|
45
|
+
for channel in self.channels:
|
|
46
|
+
if not channel.driver.should_run('notice', channel.max_level):
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
channel.driver.notice(message, *args, **kwargs)
|
|
50
|
+
|
|
51
|
+
def info(self, message, *args, **kwargs):
|
|
52
|
+
for channel in self.channels:
|
|
53
|
+
if not channel.driver.should_run('info', channel.max_level):
|
|
54
|
+
continue
|
|
55
|
+
|
|
56
|
+
channel.driver.info(message, *args, **kwargs)
|
|
57
|
+
|
|
58
|
+
def debug(self, message, *args, **kwargs):
|
|
59
|
+
for channel in self.channels:
|
|
60
|
+
if not channel.driver.should_run('debug', channel.max_level):
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
channel.driver.debug(message, *args, **kwargs)
|
|
64
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from ..factory import DriverFactory
|
|
2
|
+
from fastapi_startkit.facades import Config
|
|
3
|
+
from fastapi_startkit.utils.filesystem import make_directory
|
|
4
|
+
import os
|
|
5
|
+
import pendulum
|
|
6
|
+
from .BaseChannel import BaseChannel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SingleChannel(BaseChannel):
|
|
10
|
+
def __init__(self, driver=None, path=None):
|
|
11
|
+
path = path or Config.get('logging.channels.single.path')
|
|
12
|
+
make_directory(path)
|
|
13
|
+
self.max_level = Config.get('logging.channels.single.level')
|
|
14
|
+
self.driver = DriverFactory.make(driver or Config.get('logging.channels.single.driver'))(path=path, max_level=self.max_level)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
from ..factory import DriverFactory
|
|
3
|
+
from fastapi_startkit.facades import Config
|
|
4
|
+
import os
|
|
5
|
+
import pendulum
|
|
6
|
+
from .BaseChannel import BaseChannel
|
|
7
|
+
|
|
8
|
+
class SlackChannel(BaseChannel):
|
|
9
|
+
|
|
10
|
+
def __init__(self, driver=None, path=None):
|
|
11
|
+
token = Config.get('logging.channels.slack.token')
|
|
12
|
+
channel = Config.get('logging.channels.slack.channel')
|
|
13
|
+
emoji = Config.get('logging.channels.slack.emoji')
|
|
14
|
+
username = Config.get('logging.channels.slack.username')
|
|
15
|
+
self.max_level = Config.get('logging.channels.slack.level')
|
|
16
|
+
self.driver = DriverFactory.make(driver or Config.get('logging.channels.slack.driver'))(emoji=emoji, username=username, token=token, channel=channel)
|
|
17
|
+
|
|
18
|
+
def debug(self, message, *args, **kwargs):
|
|
19
|
+
return self.driver.debug(message, *args, **kwargs)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from ..factory import DriverFactory
|
|
2
|
+
from fastapi_startkit.facades import Config
|
|
3
|
+
import os
|
|
4
|
+
import pendulum
|
|
5
|
+
from .MultiBaseChannel import MultiBaseChannel
|
|
6
|
+
|
|
7
|
+
class StackChannel(MultiBaseChannel):
|
|
8
|
+
|
|
9
|
+
def __init__(self, channels=[]):
|
|
10
|
+
channels = channels or Config.get('logging.channels.stack.channels')
|
|
11
|
+
from ..ChannelFactory import ChannelFactory
|
|
12
|
+
self.channels = []
|
|
13
|
+
for channel in channels:
|
|
14
|
+
channel = ChannelFactory.make(channel)()
|
|
15
|
+
self.channels.append(channel)
|
|
16
|
+
|
|
17
|
+
def debug(self, message, *args, **kwargs):
|
|
18
|
+
for channel in self.channels:
|
|
19
|
+
if not channel.driver.should_run('debug', channel.max_level):
|
|
20
|
+
continue
|
|
21
|
+
|
|
22
|
+
channel.driver.debug(message, *args, **kwargs)
|
|
23
|
+
|
|
24
|
+
def notice(self, message, *args, **kwargs):
|
|
25
|
+
for channel in self.channels:
|
|
26
|
+
if not channel.driver.should_run('notice', channel.max_level):
|
|
27
|
+
continue
|
|
28
|
+
|
|
29
|
+
channel.driver.notice(message, *args, **kwargs)
|
|
30
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from ..factory import DriverFactory
|
|
2
|
+
from fastapi_startkit.facades import Config
|
|
3
|
+
from fastapi_startkit.utils.filesystem import make_directory
|
|
4
|
+
import os
|
|
5
|
+
import pendulum
|
|
6
|
+
from .BaseChannel import BaseChannel
|
|
7
|
+
|
|
8
|
+
class SyslogChannel(BaseChannel):
|
|
9
|
+
|
|
10
|
+
def __init__(self, driver=None, path=None):
|
|
11
|
+
path = path or Config.get('logging.channels.syslog.path')
|
|
12
|
+
make_directory(path)
|
|
13
|
+
self.max_level = Config.get('logging.channels.syslog.level')
|
|
14
|
+
self.driver = DriverFactory.make(driver or Config.get('logging.channels.syslog.driver'))(path=path, max_level=self.max_level)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import pendulum
|
|
4
|
+
from fastapi_startkit.facades import Config
|
|
5
|
+
|
|
6
|
+
from ..factory import DriverFactory
|
|
7
|
+
from ..channels.BaseChannel import BaseChannel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TerminalChannel(BaseChannel):
|
|
11
|
+
|
|
12
|
+
def __init__(self, driver=None, path=None):
|
|
13
|
+
self.max_level = Config.get('logging.channels.terminal.level', 'debug')
|
|
14
|
+
self.driver = DriverFactory.make(driver or Config.get('logging.channels.terminal.driver'))(path=path, max_level=self.max_level)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from .SingleChannel import SingleChannel
|
|
2
|
+
from .TerminalChannel import TerminalChannel
|
|
3
|
+
from .DailyChannel import DailyChannel
|
|
4
|
+
from .SlackChannel import SlackChannel
|
|
5
|
+
from .SyslogChannel import SyslogChannel
|
|
6
|
+
from .StackChannel import StackChannel
|
|
7
|
+
from .BaseChannel import BaseChannel
|
|
8
|
+
from .MultiBaseChannel import MultiBaseChannel
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from fastapi_startkit.environment.environment import env
|
|
2
|
+
|
|
3
|
+
DEFAULT = env('LOG_CHANNEL', 'single')
|
|
4
|
+
|
|
5
|
+
CHANNELS = {
|
|
6
|
+
'timezone': env('LOG_TIMEZONE', 'UTC'),
|
|
7
|
+
'single': {
|
|
8
|
+
'driver': 'single',
|
|
9
|
+
'level': 'debug',
|
|
10
|
+
'path': 'storage/logs/single.log'
|
|
11
|
+
},
|
|
12
|
+
'stack': {
|
|
13
|
+
'driver': 'stack',
|
|
14
|
+
'channels': ['single', 'terminal']
|
|
15
|
+
},
|
|
16
|
+
'terminal': {
|
|
17
|
+
'driver': 'terminal',
|
|
18
|
+
'level': 'info'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import pendulum
|
|
2
|
+
from fastapi_startkit.facades import Config
|
|
3
|
+
|
|
4
|
+
class BaseDriver:
|
|
5
|
+
|
|
6
|
+
levels = [
|
|
7
|
+
'emergency',
|
|
8
|
+
'alert',
|
|
9
|
+
'critical',
|
|
10
|
+
'error',
|
|
11
|
+
'warning',
|
|
12
|
+
'notice',
|
|
13
|
+
'info',
|
|
14
|
+
'debug',
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
def get_time(self):
|
|
18
|
+
return pendulum.now().in_tz(Config.get('logging.channels.timezone', 'UTC'))
|
|
19
|
+
|
|
20
|
+
def should_run(self, level, max_level):
|
|
21
|
+
if not max_level:
|
|
22
|
+
return True
|
|
23
|
+
|
|
24
|
+
return self.levels.index(level) <= self.levels.index(max_level)
|
|
25
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from .BaseDriver import BaseDriver
|
|
4
|
+
|
|
5
|
+
class LogSingleDriver(BaseDriver):
|
|
6
|
+
|
|
7
|
+
def __init__(self, *args, **kwargs):
|
|
8
|
+
self.max_level = kwargs.get('max_level')
|
|
9
|
+
self.path = kwargs.get('path')
|
|
10
|
+
self.log = logging.getLogger('root')
|
|
11
|
+
|
|
12
|
+
handler = logging.FileHandler(self.path, 'a')
|
|
13
|
+
formatter = logging.Formatter('{} - %(levelname)s - %(message)s'.format(self.get_time().to_datetime_string()))
|
|
14
|
+
|
|
15
|
+
handler.setFormatter(formatter)
|
|
16
|
+
self.log.addHandler(handler)
|
|
17
|
+
|
|
18
|
+
def change_format(self, changed_format):
|
|
19
|
+
for hdlr in self.log.handlers[:]: # remove all old handlers
|
|
20
|
+
self.log.removeHandler(hdlr)
|
|
21
|
+
|
|
22
|
+
handler = logging.FileHandler(self.path, 'a')
|
|
23
|
+
formatter = logging.Formatter(changed_format)
|
|
24
|
+
|
|
25
|
+
handler.setFormatter(formatter)
|
|
26
|
+
|
|
27
|
+
self.log.addHandler(handler)
|
|
28
|
+
|
|
29
|
+
def emergency(self, message, *args, **kwargs):
|
|
30
|
+
self.log.setLevel(logging.CRITICAL)
|
|
31
|
+
self.change_format('{} - {} - %(message)s'.format(
|
|
32
|
+
self.get_time().to_datetime_string(),
|
|
33
|
+
'EMERGENCY'))
|
|
34
|
+
return self.log.critical(message)
|
|
35
|
+
|
|
36
|
+
def alert(self, message, *args, **kwargs):
|
|
37
|
+
self.log.setLevel(logging.CRITICAL)
|
|
38
|
+
self.change_format('{} - {} - %(message)s'.format(
|
|
39
|
+
self.get_time().to_datetime_string(),
|
|
40
|
+
'ALERT'))
|
|
41
|
+
return self.log.critical(message)
|
|
42
|
+
|
|
43
|
+
def critical(self, message, *args, **kwargs):
|
|
44
|
+
self.log.setLevel(logging.CRITICAL)
|
|
45
|
+
self.change_format('{} - {} - %(message)s'.format(
|
|
46
|
+
self.get_time().to_datetime_string(),
|
|
47
|
+
'CRITICAL'))
|
|
48
|
+
return self.log.critical(message)
|
|
49
|
+
|
|
50
|
+
def error(self, message, *args, **kwargs):
|
|
51
|
+
self.log.setLevel(logging.ERROR)
|
|
52
|
+
self.change_format('{} - {} - %(message)s'.format(
|
|
53
|
+
self.get_time().to_datetime_string(),
|
|
54
|
+
'ERROR'))
|
|
55
|
+
return self.log.error(message)
|
|
56
|
+
|
|
57
|
+
def warning(self, message, *args, **kwargs):
|
|
58
|
+
self.log.setLevel(logging.WARNING)
|
|
59
|
+
self.change_format('{} - {} - %(message)s'.format(
|
|
60
|
+
self.get_time().to_datetime_string(),
|
|
61
|
+
'WARNING'))
|
|
62
|
+
return self.log.warning(message)
|
|
63
|
+
|
|
64
|
+
def notice(self, message, *args, **kwargs):
|
|
65
|
+
self.log.setLevel(logging.INFO)
|
|
66
|
+
self.change_format('{} - {} - %(message)s'.format(
|
|
67
|
+
self.get_time().to_datetime_string(),
|
|
68
|
+
'NOTICE'))
|
|
69
|
+
return self.log.info(message)
|
|
70
|
+
|
|
71
|
+
def info(self, message, *args, **kwargs):
|
|
72
|
+
self.log.setLevel(logging.INFO)
|
|
73
|
+
self.change_format('{} - {} - %(message)s'.format(
|
|
74
|
+
self.get_time().to_datetime_string(),
|
|
75
|
+
'INFO'))
|
|
76
|
+
return self.log.info(message)
|
|
77
|
+
|
|
78
|
+
def debug(self, message, *args, **kwargs):
|
|
79
|
+
self.log.setLevel(logging.DEBUG)
|
|
80
|
+
self.change_format('{} - {} - %(message)s'.format(
|
|
81
|
+
self.get_time().to_datetime_string(),
|
|
82
|
+
'DEBUG'))
|
|
83
|
+
return self.log.debug(message)
|
|
84
|
+
|