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.
Files changed (59) hide show
  1. {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/PKG-INFO +3 -5
  2. esd_services_api_client-2.6.1a149.dev13/esd_services_api_client/_version.py +1 -0
  3. {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
  4. {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
  5. esd_services_api_client-2.6.1a149.dev13/esd_services_api_client/nexus/abstractions/logger_factory.py +124 -0
  6. {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
  7. {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
  8. {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/pyproject.toml +3 -3
  9. esd_services_api_client-2.5.14a148.dev5/esd_services_api_client/_version.py +0 -1
  10. esd_services_api_client-2.5.14a148.dev5/esd_services_api_client/nexus/abstractions/logger_factory.py +0 -64
  11. {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/LICENSE +0 -0
  12. {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/README.md +0 -0
  13. {esd_services_api_client-2.5.14a148.dev5 → esd_services_api_client-2.6.1a149.dev13}/esd_services_api_client/__init__.py +0 -0
  14. {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
  15. {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
  16. {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
  17. {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
  18. {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
  19. {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
  20. {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
  21. {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
  22. {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
  23. {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
  24. {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
  25. {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
  26. {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
  27. {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
  28. {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
  29. {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
  30. {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
  31. {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
  32. {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
  33. {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
  34. {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
  35. {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
  36. {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
  37. {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
  38. {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
  39. {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
  40. {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
  41. {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
  42. {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
  43. {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
  44. {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
  45. {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
  46. {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
  47. {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
  48. {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
  49. {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
  50. {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
  51. {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
  52. {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
  53. {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
  54. {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
  55. {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
  56. {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
  57. {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
  58. {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
  59. {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
@@ -1,21 +1,19 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: esd-services-api-client
3
- Version: 2.5.14a148.dev5
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.9,<3.12
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[azure,datadog,storage] (>=3.2,<4.0)
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
- from adapta.security.clients import AzureClient
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 Dict, Optional, Any
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()
@@ -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 LoggerFactory
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
- root_logger: LoggerInterface = self._injector.get(LoggerFactory).create_logger(
264
- logger_type=self.__class__,
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
- root_logger.start()
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
- root_logger.error("Error reading algorithm payload", ex)
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
- await self._algorithm_run_task
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=self._algorithm_class,
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 LoggerFactory
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 LoggerFactoryModule(Module):
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) -> LoggerFactory:
84
+ def provide(self) -> BootstrapLoggerFactory:
83
85
  """
84
86
  DI factory method.
85
87
  """
86
- return LoggerFactory()
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(),
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "esd-services-api-client"
3
- version = "v2.5.14a148.dev5"
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.9,<3.12"
13
- adapta = { version = "^3.2", extras = ["azure", "storage", "datadog"] }
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'
@@ -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
- )