esd-services-api-client 2.5.14a148.dev5__tar.gz → 2.6.1a149.dev13__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.
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/PKG-INFO +3 -5
- esd_services_api_client-2.6.1a149.dev13/esd_services_api_client/_version.py +1 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/boxer/_connector.py +5 -1
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/README.md +12 -1
- esd_services_api_client-2.6.1a149.dev13/esd_services_api_client/nexus/abstractions/logger_factory.py +124 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/core/app_core.py +78 -8
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/core/app_dependencies.py +7 -4
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/pyproject.toml +3 -3
- esd_services_api_client-2.5.14a148.dev5/esd_services_api_client/_version.py +0 -1
- esd_services_api_client-2.5.14a148.dev5/esd_services_api_client/nexus/abstractions/logger_factory.py +0 -64
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/LICENSE +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/README.md +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/beast/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/beast/v3/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/beast/v3/_connector.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/beast/v3/_models.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/boxer/README.md +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/boxer/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/boxer/_auth.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/boxer/_base.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/boxer/_models.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/common/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/crystal/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/crystal/_api_versions.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/crystal/_connector.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/crystal/_models.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/abstractions/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/abstractions/algrorithm_cache.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/abstractions/input_object.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/abstractions/nexus_object.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/abstractions/socket_provider.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/algorithms/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/algorithms/_baseline_algorithm.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/algorithms/_remote_algorithm.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/algorithms/distributed.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/algorithms/forked_algorithm.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/algorithms/minimalistic.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/algorithms/recursive.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/configurations/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/configurations/algorithm_configuration.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/core/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/core/serializers.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/exceptions/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/exceptions/_nexus_error.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/exceptions/cache_errors.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/exceptions/input_reader_error.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/exceptions/startup_error.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/input/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/input/input_processor.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/input/input_reader.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/input/payload_reader.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/modules/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/modules/astra_client_module.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/modules/mlflow_module.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/telemetry/__init__.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/telemetry/recorder.py +0 -0
- {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/nexus/telemetry/user_telemetry_recorder.py +0 -0
{esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/PKG-INFO
RENAMED
@@ -1,21 +1,19 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: esd-services-api-client
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.6.1a149.dev13
|
4
4
|
Summary: Python clients for ESD services
|
5
5
|
License: Apache 2.0
|
6
6
|
Author: ECCO Sneaks & Data
|
7
7
|
Author-email: esdsupport@ecco.com
|
8
8
|
Maintainer: GZU
|
9
9
|
Maintainer-email: gzu@ecco.com
|
10
|
-
Requires-Python: >=3.
|
10
|
+
Requires-Python: >=3.11,<3.12
|
11
11
|
Classifier: License :: Other/Proprietary License
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
15
13
|
Classifier: Programming Language :: Python :: 3.11
|
16
14
|
Provides-Extra: azure
|
17
15
|
Provides-Extra: nexus
|
18
|
-
Requires-Dist: adapta[
|
16
|
+
Requires-Dist: adapta[datadog,storage] (>=3.3,<4.0)
|
19
17
|
Requires-Dist: azure-identity (>=1.7,<1.8) ; extra == "azure"
|
20
18
|
Requires-Dist: dataclasses-json (>=0.6.0,<0.7.0)
|
21
19
|
Requires-Dist: httpx (>=0.27.0,<0.28.0) ; extra == "nexus"
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = 'v2.6.1a149.dev13'
|
@@ -20,7 +20,11 @@ import os
|
|
20
20
|
from functools import reduce
|
21
21
|
from typing import Optional, Iterator, final
|
22
22
|
|
23
|
-
|
23
|
+
try:
|
24
|
+
from adapta.security.clients import AzureClient
|
25
|
+
except ImportError:
|
26
|
+
pass
|
27
|
+
|
24
28
|
from adapta.utils import session_with_retries
|
25
29
|
from requests import Session, Response
|
26
30
|
|
@@ -22,7 +22,7 @@ import socketserver
|
|
22
22
|
import threading
|
23
23
|
from dataclasses import dataclass
|
24
24
|
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
|
25
|
-
from typing import
|
25
|
+
from typing import Optional, Any
|
26
26
|
|
27
27
|
import pandas
|
28
28
|
from adapta.metrics import MetricsProvider
|
@@ -30,6 +30,7 @@ from adapta.storage.query_enabled_store import QueryEnabledStore
|
|
30
30
|
from dataclasses_json import DataClassJsonMixin
|
31
31
|
from injector import inject
|
32
32
|
|
33
|
+
from esd_services_api_client.crystal import CrystalEntrypointArguments
|
33
34
|
from esd_services_api_client.nexus.abstractions.algrorithm_cache import InputCache
|
34
35
|
from esd_services_api_client.nexus.abstractions.logger_factory import LoggerFactory
|
35
36
|
from esd_services_api_client.nexus.abstractions.nexus_object import AlgorithmResult
|
@@ -292,6 +293,15 @@ async def main():
|
|
292
293
|
Mock HTTP Server
|
293
294
|
:return:
|
294
295
|
"""
|
296
|
+
def tags_from_payload(payload: MyAlgorithmPayload, _: CrystalEntrypointArguments) -> dict[str, str]:
|
297
|
+
return {
|
298
|
+
"test_tag": str(payload.x)
|
299
|
+
}
|
300
|
+
def enrich_from_payload(payload: MyAlgorithmPayload2, run_args: CrystalEntrypointArguments) -> dict[str, dict[str, str]]:
|
301
|
+
return {
|
302
|
+
"(value of y:{y})": {"y": payload.y},
|
303
|
+
"(request_id:{request_id})": {"request_id": run_args.request_id}
|
304
|
+
}
|
295
305
|
with ThreadingHTTPServer(("localhost", 9876), MockRequestHandler) as server:
|
296
306
|
server_thread = threading.Thread(target=server.serve_forever)
|
297
307
|
server_thread.daemon = True
|
@@ -306,6 +316,7 @@ async def main():
|
|
306
316
|
.on_complete(ObjectiveAnalytics)
|
307
317
|
.inject_configuration(MyAlgorithmConfiguration)
|
308
318
|
.inject_payload(MyAlgorithmPayload, MyAlgorithmPayload2)
|
319
|
+
.with_log_enricher(tags_from_payload, enrich_from_payload)
|
309
320
|
)
|
310
321
|
|
311
322
|
await nexus.activate()
|
esd_services_api_client-2.6.1a149.dev13/esd_services_api_client/nexus/abstractions/logger_factory.py
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
"""
|
2
|
+
Logger factory for async loggers.
|
3
|
+
"""
|
4
|
+
|
5
|
+
# Copyright (c) 2023-2024. ECCO Sneaks & Data
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
import json
|
21
|
+
import os
|
22
|
+
from abc import ABC
|
23
|
+
from logging import StreamHandler
|
24
|
+
from typing import final, TypeVar
|
25
|
+
|
26
|
+
from adapta.logs import LoggerInterface, create_async_logger
|
27
|
+
from adapta.logs.handlers.datadog_api_handler import DataDogApiHandler
|
28
|
+
from adapta.logs.models import LogLevel
|
29
|
+
|
30
|
+
TLogger = TypeVar("TLogger") # pylint: disable=C0103:
|
31
|
+
|
32
|
+
|
33
|
+
@final
|
34
|
+
class BootstrapLogger(LoggerInterface, ABC):
|
35
|
+
"""
|
36
|
+
Dummy class to separate bootstrap logging from core app loggers
|
37
|
+
"""
|
38
|
+
|
39
|
+
pass
|
40
|
+
|
41
|
+
|
42
|
+
@final
|
43
|
+
class BootstrapLoggerFactory:
|
44
|
+
"""
|
45
|
+
Bootstrap logger provisioner.
|
46
|
+
Bootstrap loggers do not use enriched properties since they are initialized before payload is deserialized.
|
47
|
+
"""
|
48
|
+
|
49
|
+
def __init__(self):
|
50
|
+
self._log_handlers = [
|
51
|
+
StreamHandler(),
|
52
|
+
]
|
53
|
+
if "NEXUS__DATADOG_LOGGER_CONFIGURATION" in os.environ:
|
54
|
+
self._log_handlers.append(
|
55
|
+
DataDogApiHandler(
|
56
|
+
**json.loads(os.getenv("NEXUS__DATADOG_LOGGER_CONFIGURATION"))
|
57
|
+
)
|
58
|
+
)
|
59
|
+
|
60
|
+
def create_logger(self, request_id: str, algorithm_name: str) -> LoggerInterface:
|
61
|
+
"""
|
62
|
+
Creates an async-safe logger for the provided class name.
|
63
|
+
"""
|
64
|
+
return create_async_logger(
|
65
|
+
logger_type=BootstrapLogger.__class__,
|
66
|
+
log_handlers=self._log_handlers,
|
67
|
+
min_log_level=LogLevel(os.getenv("NEXUS__LOG_LEVEL", "INFO")),
|
68
|
+
global_tags={
|
69
|
+
"request_id": request_id,
|
70
|
+
"algorithm": algorithm_name,
|
71
|
+
},
|
72
|
+
)
|
73
|
+
|
74
|
+
|
75
|
+
@final
|
76
|
+
class LoggerFactory:
|
77
|
+
"""
|
78
|
+
Async logger provisioner.
|
79
|
+
"""
|
80
|
+
|
81
|
+
def __init__(
|
82
|
+
self,
|
83
|
+
fixed_template: dict[str, dict[str, str]] | None = None,
|
84
|
+
fixed_template_delimiter: str = None,
|
85
|
+
global_tags: dict[str, str] | None = None,
|
86
|
+
):
|
87
|
+
self._global_tags = global_tags
|
88
|
+
self._fixed_template = fixed_template
|
89
|
+
self._fixed_template_delimiter = fixed_template_delimiter or ", "
|
90
|
+
self._log_handlers = [
|
91
|
+
StreamHandler(),
|
92
|
+
]
|
93
|
+
if "NEXUS__DATADOG_LOGGER_CONFIGURATION" in os.environ:
|
94
|
+
self._log_handlers.append(
|
95
|
+
DataDogApiHandler(
|
96
|
+
**json.loads(os.getenv("NEXUS__DATADOG_LOGGER_CONFIGURATION"))
|
97
|
+
)
|
98
|
+
)
|
99
|
+
if "NEXUS__LOGGER_FIXED_TEMPLATE" in os.environ:
|
100
|
+
self._fixed_template = self._fixed_template | json.loads(
|
101
|
+
os.getenv("NEXUS__LOGGER_FIXED_TEMPLATE")
|
102
|
+
)
|
103
|
+
|
104
|
+
if "NEXUS__LOGGER_FIXED_TEMPLATE_DELIMITER" in os.environ:
|
105
|
+
self._fixed_template_delimiter = (
|
106
|
+
self._fixed_template_delimiter
|
107
|
+
or os.getenv("NEXUS__LOGGER_FIXED_TEMPLATE")
|
108
|
+
)
|
109
|
+
|
110
|
+
def create_logger(
|
111
|
+
self,
|
112
|
+
logger_type: type[TLogger],
|
113
|
+
) -> LoggerInterface:
|
114
|
+
"""
|
115
|
+
Creates an async-safe logger for the provided class name.
|
116
|
+
"""
|
117
|
+
return create_async_logger(
|
118
|
+
logger_type=logger_type,
|
119
|
+
log_handlers=self._log_handlers,
|
120
|
+
min_log_level=LogLevel(os.getenv("NEXUS__LOG_LEVEL", "INFO")),
|
121
|
+
fixed_template=self._fixed_template,
|
122
|
+
fixed_template_delimiter=self._fixed_template_delimiter,
|
123
|
+
global_tags=self._global_tags,
|
124
|
+
)
|
@@ -23,7 +23,7 @@ import platform
|
|
23
23
|
import signal
|
24
24
|
import sys
|
25
25
|
import traceback
|
26
|
-
from typing import final, Type, Optional
|
26
|
+
from typing import final, Type, Optional, Callable
|
27
27
|
|
28
28
|
import backoff
|
29
29
|
import urllib3.exceptions
|
@@ -41,7 +41,10 @@ from esd_services_api_client.crystal import (
|
|
41
41
|
AlgorithmRunResult,
|
42
42
|
CrystalEntrypointArguments,
|
43
43
|
)
|
44
|
-
from esd_services_api_client.nexus.abstractions.logger_factory import
|
44
|
+
from esd_services_api_client.nexus.abstractions.logger_factory import (
|
45
|
+
LoggerFactory,
|
46
|
+
BootstrapLoggerFactory,
|
47
|
+
)
|
45
48
|
from esd_services_api_client.nexus.abstractions.nexus_object import AlgorithmResult
|
46
49
|
from esd_services_api_client.nexus.algorithms import (
|
47
50
|
BaselineAlgorithm,
|
@@ -119,6 +122,21 @@ class Nexus:
|
|
119
122
|
self._algorithm_run_task: Optional[asyncio.Task] = None
|
120
123
|
self._on_complete_tasks: list[type[UserTelemetryRecorder]] = []
|
121
124
|
self._payload_types: list[type[AlgorithmPayload]] = []
|
125
|
+
self._log_enricher: Callable[
|
126
|
+
[
|
127
|
+
AlgorithmPayload,
|
128
|
+
CrystalEntrypointArguments,
|
129
|
+
],
|
130
|
+
dict[str, dict[str, str]],
|
131
|
+
] | None = None
|
132
|
+
self._log_tagger: Callable[
|
133
|
+
[
|
134
|
+
AlgorithmPayload,
|
135
|
+
CrystalEntrypointArguments,
|
136
|
+
],
|
137
|
+
dict[str, str],
|
138
|
+
] | None = None
|
139
|
+
self._log_enrichment_delimiter: str = ", "
|
122
140
|
|
123
141
|
attach_signal_handlers()
|
124
142
|
|
@@ -177,6 +195,31 @@ class Nexus:
|
|
177
195
|
|
178
196
|
return self
|
179
197
|
|
198
|
+
def with_log_enricher(
|
199
|
+
self,
|
200
|
+
tagger: Callable[
|
201
|
+
[
|
202
|
+
AlgorithmPayload,
|
203
|
+
CrystalEntrypointArguments,
|
204
|
+
],
|
205
|
+
dict[str, str],
|
206
|
+
]
|
207
|
+
| None,
|
208
|
+
enricher: Callable[
|
209
|
+
[
|
210
|
+
AlgorithmPayload,
|
211
|
+
CrystalEntrypointArguments,
|
212
|
+
],
|
213
|
+
dict[str, dict[str, str]],
|
214
|
+
]
|
215
|
+
| None = None,
|
216
|
+
delimiter: str = ", ",
|
217
|
+
) -> "Nexus":
|
218
|
+
self._log_tagger = tagger
|
219
|
+
self._log_enricher = enricher
|
220
|
+
self._log_enrichment_delimiter = delimiter
|
221
|
+
return self
|
222
|
+
|
180
223
|
def with_module(self, module: Type[Module]) -> "Nexus":
|
181
224
|
"""
|
182
225
|
Adds a (custom) DI module into the DI container.
|
@@ -260,11 +303,14 @@ class Nexus:
|
|
260
303
|
|
261
304
|
self._injector = Injector(self._configurator.injection_binds)
|
262
305
|
|
263
|
-
|
264
|
-
|
306
|
+
bootstrap_logger: LoggerInterface = self._injector.get(
|
307
|
+
BootstrapLoggerFactory
|
308
|
+
).create_logger(
|
309
|
+
request_id=self._run_args.request_id,
|
310
|
+
algorithm_name=os.getenv("CRYSTAL__ALGORITHM_NAME"),
|
265
311
|
)
|
266
312
|
|
267
|
-
|
313
|
+
bootstrap_logger.start()
|
268
314
|
|
269
315
|
for payload_type in self._payload_types:
|
270
316
|
try:
|
@@ -272,10 +318,30 @@ class Nexus:
|
|
272
318
|
self._injector.binder.bind(
|
273
319
|
payload.__class__, to=payload, scope=singleton
|
274
320
|
)
|
321
|
+
# bind app-level LoggerFactory now
|
322
|
+
self._injector.binder.bind(
|
323
|
+
LoggerFactory.__class__,
|
324
|
+
to=LoggerFactory(
|
325
|
+
fixed_template=None
|
326
|
+
if not self._log_enricher
|
327
|
+
else self._log_enricher(payload, self._run_args),
|
328
|
+
fixed_template_delimiter=self._log_enrichment_delimiter,
|
329
|
+
global_tags=self._log_tagger(payload, self._run_args),
|
330
|
+
),
|
331
|
+
scope=singleton,
|
332
|
+
)
|
275
333
|
except BaseException as ex: # pylint: disable=broad-except
|
276
|
-
|
334
|
+
bootstrap_logger.error("Error reading algorithm payload", ex)
|
277
335
|
sys.exit(1)
|
278
336
|
|
337
|
+
bootstrap_logger.stop()
|
338
|
+
|
339
|
+
root_logger: LoggerInterface = self._injector.get(LoggerFactory).create_logger(
|
340
|
+
logger_type=self.__class__,
|
341
|
+
)
|
342
|
+
|
343
|
+
root_logger.start()
|
344
|
+
|
279
345
|
algorithm: BaselineAlgorithm = self._injector.get(self._algorithm_class)
|
280
346
|
telemetry_recorder: TelemetryRecorder = self._injector.get(TelemetryRecorder)
|
281
347
|
|
@@ -289,14 +355,18 @@ class Nexus:
|
|
289
355
|
self._algorithm_run_task = asyncio.create_task(
|
290
356
|
instance.run(**self._run_args.__dict__)
|
291
357
|
)
|
292
|
-
|
358
|
+
|
359
|
+
# avoid exception propagation to main thread, since we need to handle it later
|
360
|
+
await asyncio.wait(
|
361
|
+
[self._algorithm_run_task], return_when=asyncio.FIRST_EXCEPTION
|
362
|
+
)
|
293
363
|
ex = self._algorithm_run_task.exception()
|
294
364
|
|
295
365
|
if ex is not None:
|
296
366
|
root_logger.error(
|
297
367
|
"Algorithm {algorithm} run failed on Nexus version {version}",
|
298
368
|
ex,
|
299
|
-
algorithm=
|
369
|
+
algorithm=algorithm.__class__.__name__,
|
300
370
|
version=__version__,
|
301
371
|
)
|
302
372
|
|
@@ -30,7 +30,9 @@ from injector import Module, singleton, provider
|
|
30
30
|
|
31
31
|
from esd_services_api_client.crystal import CrystalConnector
|
32
32
|
from esd_services_api_client.nexus.abstractions.algrorithm_cache import InputCache
|
33
|
-
from esd_services_api_client.nexus.abstractions.logger_factory import
|
33
|
+
from esd_services_api_client.nexus.abstractions.logger_factory import (
|
34
|
+
BootstrapLoggerFactory,
|
35
|
+
)
|
34
36
|
from esd_services_api_client.nexus.abstractions.socket_provider import (
|
35
37
|
ExternalSocketProvider,
|
36
38
|
)
|
@@ -72,18 +74,18 @@ class MetricsModule(Module):
|
|
72
74
|
|
73
75
|
|
74
76
|
@final
|
75
|
-
class
|
77
|
+
class BootstrapLoggerFactoryModule(Module):
|
76
78
|
"""
|
77
79
|
Logger factory module.
|
78
80
|
"""
|
79
81
|
|
80
82
|
@singleton
|
81
83
|
@provider
|
82
|
-
def provide(self) ->
|
84
|
+
def provide(self) -> BootstrapLoggerFactory:
|
83
85
|
"""
|
84
86
|
DI factory method.
|
85
87
|
"""
|
86
|
-
return
|
88
|
+
return BootstrapLoggerFactory()
|
87
89
|
|
88
90
|
|
89
91
|
@final
|
@@ -234,6 +236,7 @@ class ServiceConfigurator:
|
|
234
236
|
|
235
237
|
def __init__(self):
|
236
238
|
self._injection_binds = [
|
239
|
+
BootstrapLoggerFactoryModule(),
|
237
240
|
MetricsModule(),
|
238
241
|
CrystalReceiverClientModule(),
|
239
242
|
QueryEnabledStoreModule(),
|
{esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/pyproject.toml
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "esd-services-api-client"
|
3
|
-
version = "v2.
|
3
|
+
version = "v2.6.1a149.dev13"
|
4
4
|
description = "Python clients for ESD services"
|
5
5
|
authors = ["ECCO Sneaks & Data <esdsupport@ecco.com>"]
|
6
6
|
maintainers = ['GZU <gzu@ecco.com>', 'JRB <ext-jrb@ecco.com>', 'VISA <visa@ecco.com>']
|
@@ -9,8 +9,8 @@ license = 'Apache 2.0'
|
|
9
9
|
repository = 'https://github.com/SneaksAndData/esd-services-api-client'
|
10
10
|
|
11
11
|
[tool.poetry.dependencies]
|
12
|
-
python = ">=3.
|
13
|
-
adapta = { version = "^3.
|
12
|
+
python = ">=3.11,<3.12"
|
13
|
+
adapta = { version = "^3.3", extras = ["storage", "datadog"] }
|
14
14
|
dataclasses-json = "^0.6.0"
|
15
15
|
pycryptodome = "~3.15"
|
16
16
|
azure-identity = { version = "~1.7", optional = true }
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = 'v2.5.14a148.dev5'
|
esd_services_api_client-2.5.14a148.dev5/esd_services_api_client/nexus/abstractions/logger_factory.py
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Logger factory for async loggers.
|
3
|
-
"""
|
4
|
-
|
5
|
-
# Copyright (c) 2023-2024. ECCO Sneaks & Data
|
6
|
-
#
|
7
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
-
# you may not use this file except in compliance with the License.
|
9
|
-
# You may obtain a copy of the License at
|
10
|
-
#
|
11
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
-
#
|
13
|
-
# Unless required by applicable law or agreed to in writing, software
|
14
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
-
# See the License for the specific language governing permissions and
|
17
|
-
# limitations under the License.
|
18
|
-
#
|
19
|
-
|
20
|
-
import json
|
21
|
-
import os
|
22
|
-
from logging import StreamHandler
|
23
|
-
from typing import final, Type, TypeVar, Optional, Dict
|
24
|
-
|
25
|
-
from adapta.logs import LoggerInterface, create_async_logger
|
26
|
-
from adapta.logs.handlers.datadog_api_handler import DataDogApiHandler
|
27
|
-
from adapta.logs.models import LogLevel
|
28
|
-
|
29
|
-
TLogger = TypeVar("TLogger") # pylint: disable=C0103:
|
30
|
-
|
31
|
-
|
32
|
-
@final
|
33
|
-
class LoggerFactory:
|
34
|
-
"""
|
35
|
-
Async logger provisioner.
|
36
|
-
"""
|
37
|
-
|
38
|
-
def __init__(self):
|
39
|
-
self._log_handlers = [
|
40
|
-
StreamHandler(),
|
41
|
-
]
|
42
|
-
if "NEXUS__DATADOG_LOGGER_CONFIGURATION" in os.environ:
|
43
|
-
self._log_handlers.append(
|
44
|
-
DataDogApiHandler(
|
45
|
-
**json.loads(os.getenv("NEXUS__DATADOG_LOGGER_CONFIGURATION"))
|
46
|
-
)
|
47
|
-
)
|
48
|
-
|
49
|
-
def create_logger(
|
50
|
-
self,
|
51
|
-
logger_type: Type[TLogger],
|
52
|
-
fixed_template: Optional[Dict[str, Dict[str, str]]] = None,
|
53
|
-
fixed_template_delimiter=", ",
|
54
|
-
) -> LoggerInterface:
|
55
|
-
"""
|
56
|
-
Creates an async-safe logger for the provided class name.
|
57
|
-
"""
|
58
|
-
return create_async_logger(
|
59
|
-
logger_type=logger_type,
|
60
|
-
log_handlers=self._log_handlers,
|
61
|
-
min_log_level=LogLevel(os.getenv("NEXUS__LOG_LEVEL", "INFO")),
|
62
|
-
fixed_template=fixed_template,
|
63
|
-
fixed_template_delimiter=fixed_template_delimiter,
|
64
|
-
)
|
File without changes
|
{esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/README.md
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|