haiway 0.18.2__py3-none-any.whl → 0.19.1__py3-none-any.whl
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.
- haiway/__init__.py +0 -2
- haiway/context/access.py +53 -64
- haiway/context/observability.py +53 -48
- haiway/helpers/__init__.py +1 -2
- haiway/helpers/observability.py +53 -35
- haiway/helpers/tracing.py +50 -43
- haiway/opentelemetry/observability.py +53 -31
- haiway/state/structure.py +3 -151
- haiway/utils/__init__.py +2 -0
- haiway/utils/formatting.py +151 -0
- {haiway-0.18.2.dist-info → haiway-0.19.1.dist-info}/METADATA +1 -1
- {haiway-0.18.2.dist-info → haiway-0.19.1.dist-info}/RECORD +14 -13
- {haiway-0.18.2.dist-info → haiway-0.19.1.dist-info}/WHEEL +0 -0
- {haiway-0.18.2.dist-info → haiway-0.19.1.dist-info}/licenses/LICENSE +0 -0
haiway/__init__.py
CHANGED
@@ -20,7 +20,6 @@ from haiway.context import (
|
|
20
20
|
)
|
21
21
|
from haiway.helpers import (
|
22
22
|
LoggerObservability,
|
23
|
-
ResultTrace,
|
24
23
|
asynchronous,
|
25
24
|
cache,
|
26
25
|
retry,
|
@@ -87,7 +86,6 @@ __all__ = (
|
|
87
86
|
"ObservabilityMetricRecording",
|
88
87
|
"ObservabilityScopeEntering",
|
89
88
|
"ObservabilityScopeExiting",
|
90
|
-
"ResultTrace",
|
91
89
|
"ScopeContext",
|
92
90
|
"ScopeIdentifier",
|
93
91
|
"State",
|
haiway/context/access.py
CHANGED
@@ -11,6 +11,7 @@ from collections.abc import (
|
|
11
11
|
Callable,
|
12
12
|
Coroutine,
|
13
13
|
Iterable,
|
14
|
+
Mapping,
|
14
15
|
)
|
15
16
|
from logging import Logger
|
16
17
|
from types import TracebackType
|
@@ -597,81 +598,69 @@ class ctx:
|
|
597
598
|
ObservabilityLevel.DEBUG, message, *args, exception=exception, **extra
|
598
599
|
)
|
599
600
|
|
601
|
+
@overload
|
600
602
|
@staticmethod
|
601
|
-
def
|
602
|
-
|
603
|
+
def record(
|
604
|
+
level: ObservabilityLevel = ObservabilityLevel.DEBUG,
|
603
605
|
/,
|
604
606
|
*,
|
605
|
-
|
606
|
-
|
607
|
-
) -> None:
|
608
|
-
"""
|
609
|
-
Record event within current scope context.
|
610
|
-
|
611
|
-
Parameters
|
612
|
-
----------
|
613
|
-
event: State
|
614
|
-
contents of event to be recorded.
|
607
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
608
|
+
) -> None: ...
|
615
609
|
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
)
|
610
|
+
@overload
|
611
|
+
@staticmethod
|
612
|
+
def record(
|
613
|
+
level: ObservabilityLevel = ObservabilityLevel.DEBUG,
|
614
|
+
/,
|
615
|
+
*,
|
616
|
+
event: str,
|
617
|
+
attributes: Mapping[str, ObservabilityAttribute] | None = None,
|
618
|
+
) -> None: ...
|
626
619
|
|
620
|
+
@overload
|
627
621
|
@staticmethod
|
628
|
-
def
|
629
|
-
|
622
|
+
def record(
|
623
|
+
level: ObservabilityLevel = ObservabilityLevel.DEBUG,
|
630
624
|
/,
|
631
625
|
*,
|
626
|
+
metric: str,
|
632
627
|
value: float | int,
|
633
628
|
unit: str | None = None,
|
634
|
-
|
635
|
-
) -> None:
|
636
|
-
"""
|
637
|
-
Record metric within current scope context.
|
638
|
-
|
639
|
-
Parameters
|
640
|
-
----------
|
641
|
-
metric: State
|
642
|
-
name of metric to be recorded.
|
643
|
-
value: float | int
|
644
|
-
value of metric to be recorded.
|
645
|
-
unit: str | None = None
|
646
|
-
unit of metric to be recorded.
|
647
|
-
|
648
|
-
Returns
|
649
|
-
-------
|
650
|
-
None
|
651
|
-
"""
|
652
|
-
|
653
|
-
ObservabilityContext.record_metric(
|
654
|
-
metric,
|
655
|
-
value=value,
|
656
|
-
unit=unit,
|
657
|
-
**extra,
|
658
|
-
)
|
629
|
+
attributes: Mapping[str, ObservabilityAttribute] | None = None,
|
630
|
+
) -> None: ...
|
659
631
|
|
660
632
|
@staticmethod
|
661
|
-
def
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
633
|
+
def record(
|
634
|
+
level: ObservabilityLevel = ObservabilityLevel.DEBUG,
|
635
|
+
/,
|
636
|
+
*,
|
637
|
+
event: str | None = None,
|
638
|
+
metric: str | None = None,
|
639
|
+
value: float | int | None = None,
|
640
|
+
unit: str | None = None,
|
641
|
+
attributes: Mapping[str, ObservabilityAttribute] | None = None,
|
642
|
+
) -> None:
|
643
|
+
if event is not None:
|
644
|
+
assert metric is None # nosec: B101
|
645
|
+
ObservabilityContext.record_event(
|
646
|
+
level,
|
647
|
+
event,
|
648
|
+
attributes=attributes or {},
|
649
|
+
)
|
669
650
|
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
651
|
+
elif metric is not None:
|
652
|
+
assert event is None # nosec: B101
|
653
|
+
assert value is not None # nosec: B101
|
654
|
+
ObservabilityContext.record_metric(
|
655
|
+
level,
|
656
|
+
metric,
|
657
|
+
value=value,
|
658
|
+
unit=unit,
|
659
|
+
attributes=attributes or {},
|
660
|
+
)
|
674
661
|
|
675
|
-
|
676
|
-
|
677
|
-
|
662
|
+
else:
|
663
|
+
ObservabilityContext.record_attributes(
|
664
|
+
level,
|
665
|
+
attributes=attributes or {},
|
666
|
+
)
|
haiway/context/observability.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from collections.abc import Sequence
|
1
|
+
from collections.abc import Mapping, Sequence
|
2
2
|
from contextvars import ContextVar, Token
|
3
3
|
from enum import IntEnum
|
4
4
|
from logging import DEBUG as DEBUG_LOGGING
|
@@ -7,17 +7,14 @@ from logging import INFO as INFO_LOGGING
|
|
7
7
|
from logging import WARNING as WARNING_LOGGING
|
8
8
|
from logging import Logger, getLogger
|
9
9
|
from types import TracebackType
|
10
|
-
from typing import Any,
|
10
|
+
from typing import Any, Protocol, Self, final, runtime_checkable
|
11
11
|
|
12
12
|
from haiway.context.identifier import ScopeIdentifier
|
13
13
|
from haiway.state import State
|
14
|
-
from haiway.types import
|
14
|
+
from haiway.types import Missing
|
15
|
+
from haiway.utils.formatting import format_str
|
15
16
|
|
16
17
|
__all__ = (
|
17
|
-
"DEBUG",
|
18
|
-
"ERROR",
|
19
|
-
"INFO",
|
20
|
-
"WARNING",
|
21
18
|
"Observability",
|
22
19
|
"ObservabilityAttribute",
|
23
20
|
"ObservabilityAttributesRecording",
|
@@ -39,11 +36,6 @@ class ObservabilityLevel(IntEnum):
|
|
39
36
|
DEBUG = DEBUG_LOGGING
|
40
37
|
|
41
38
|
|
42
|
-
ERROR: Final[int] = ObservabilityLevel.ERROR
|
43
|
-
WARNING: Final[int] = ObservabilityLevel.WARNING
|
44
|
-
INFO: Final[int] = ObservabilityLevel.INFO
|
45
|
-
DEBUG: Final[int] = ObservabilityLevel.DEBUG
|
46
|
-
|
47
39
|
type ObservabilityAttribute = (
|
48
40
|
Sequence[str]
|
49
41
|
| Sequence[float]
|
@@ -68,7 +60,6 @@ class ObservabilityLogRecording(Protocol):
|
|
68
60
|
message: str,
|
69
61
|
*args: Any,
|
70
62
|
exception: BaseException | None,
|
71
|
-
**extra: Any,
|
72
63
|
) -> None: ...
|
73
64
|
|
74
65
|
|
@@ -78,10 +69,10 @@ class ObservabilityEventRecording(Protocol):
|
|
78
69
|
self,
|
79
70
|
scope: ScopeIdentifier,
|
80
71
|
/,
|
81
|
-
*,
|
82
72
|
level: ObservabilityLevel,
|
83
|
-
|
84
|
-
|
73
|
+
*,
|
74
|
+
event: str,
|
75
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
85
76
|
) -> None: ...
|
86
77
|
|
87
78
|
|
@@ -91,11 +82,12 @@ class ObservabilityMetricRecording(Protocol):
|
|
91
82
|
self,
|
92
83
|
scope: ScopeIdentifier,
|
93
84
|
/,
|
85
|
+
level: ObservabilityLevel,
|
94
86
|
*,
|
95
87
|
metric: str,
|
96
88
|
value: float | int,
|
97
89
|
unit: str | None,
|
98
|
-
|
90
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
99
91
|
) -> None: ...
|
100
92
|
|
101
93
|
|
@@ -105,7 +97,8 @@ class ObservabilityAttributesRecording(Protocol):
|
|
105
97
|
self,
|
106
98
|
scope: ScopeIdentifier,
|
107
99
|
/,
|
108
|
-
|
100
|
+
level: ObservabilityLevel,
|
101
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
109
102
|
) -> None: ...
|
110
103
|
|
111
104
|
|
@@ -217,7 +210,6 @@ def _logger_observability(
|
|
217
210
|
message: str,
|
218
211
|
*args: Any,
|
219
212
|
exception: BaseException | None,
|
220
|
-
**extra: Any,
|
221
213
|
) -> None:
|
222
214
|
logger.log(
|
223
215
|
level,
|
@@ -229,42 +221,51 @@ def _logger_observability(
|
|
229
221
|
def event_recording(
|
230
222
|
scope: ScopeIdentifier,
|
231
223
|
/,
|
232
|
-
*,
|
233
224
|
level: ObservabilityLevel,
|
234
|
-
|
235
|
-
|
225
|
+
*,
|
226
|
+
event: str,
|
227
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
236
228
|
) -> None:
|
237
229
|
logger.log(
|
238
230
|
level,
|
239
|
-
f"{scope.unique_name} Recorded event
|
231
|
+
f"{scope.unique_name} Recorded event: {event} {format_str(attributes)}",
|
240
232
|
)
|
241
233
|
|
242
234
|
def metric_recording(
|
243
235
|
scope: ScopeIdentifier,
|
244
236
|
/,
|
237
|
+
level: ObservabilityLevel,
|
245
238
|
*,
|
246
239
|
metric: str,
|
247
240
|
value: float | int,
|
248
241
|
unit: str | None,
|
249
|
-
|
242
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
250
243
|
) -> None:
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
244
|
+
if attributes:
|
245
|
+
logger.log(
|
246
|
+
level,
|
247
|
+
f"{scope.unique_name} Recorded metric: {metric}={value}{unit or ''}"
|
248
|
+
f"\n{format_str(attributes)}",
|
249
|
+
)
|
250
|
+
|
251
|
+
else:
|
252
|
+
logger.log(
|
253
|
+
level,
|
254
|
+
f"{scope.unique_name} Recorded metric: {metric}={value}{unit or ''}",
|
255
|
+
)
|
255
256
|
|
256
257
|
def attributes_recording(
|
257
258
|
scope: ScopeIdentifier,
|
258
259
|
/,
|
259
|
-
|
260
|
+
level: ObservabilityLevel,
|
261
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
260
262
|
) -> None:
|
261
263
|
if not attributes:
|
262
264
|
return
|
263
265
|
|
264
266
|
logger.log(
|
265
|
-
|
266
|
-
f"{scope.unique_name} Recorded attributes:"
|
267
|
-
f"\n{'\n'.join(f'{k}: {v}' for k, v in attributes.items() if v is not None and v is not MISSING)}", # noqa: E501
|
267
|
+
level,
|
268
|
+
f"{scope.unique_name} Recorded attributes: {format_str(attributes)}",
|
268
269
|
)
|
269
270
|
|
270
271
|
def scope_entering[Metric: State](
|
@@ -272,7 +273,7 @@ def _logger_observability(
|
|
272
273
|
/,
|
273
274
|
) -> None:
|
274
275
|
logger.log(
|
275
|
-
DEBUG,
|
276
|
+
ObservabilityLevel.DEBUG,
|
276
277
|
f"{scope.unique_name} Entering scope: {scope.label}",
|
277
278
|
)
|
278
279
|
|
@@ -283,7 +284,7 @@ def _logger_observability(
|
|
283
284
|
exception: BaseException | None,
|
284
285
|
) -> None:
|
285
286
|
logger.log(
|
286
|
-
DEBUG,
|
287
|
+
ObservabilityLevel.DEBUG,
|
287
288
|
f"{scope.unique_name} Exiting scope: {scope.label}",
|
288
289
|
exc_info=exception,
|
289
290
|
)
|
@@ -357,7 +358,6 @@ class ObservabilityContext:
|
|
357
358
|
/,
|
358
359
|
*args: Any,
|
359
360
|
exception: BaseException | None,
|
360
|
-
**extra: Any,
|
361
361
|
) -> None:
|
362
362
|
try: # catch exceptions - we don't wan't to blow up on observability
|
363
363
|
context: Self = cls._context.get()
|
@@ -369,7 +369,6 @@ class ObservabilityContext:
|
|
369
369
|
message,
|
370
370
|
*args,
|
371
371
|
exception=exception,
|
372
|
-
**extra,
|
373
372
|
)
|
374
373
|
|
375
374
|
except LookupError:
|
@@ -383,11 +382,11 @@ class ObservabilityContext:
|
|
383
382
|
@classmethod
|
384
383
|
def record_event(
|
385
384
|
cls,
|
386
|
-
|
385
|
+
level: ObservabilityLevel,
|
386
|
+
event: str,
|
387
387
|
/,
|
388
388
|
*,
|
389
|
-
|
390
|
-
**extra: Any,
|
389
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
391
390
|
) -> None:
|
392
391
|
try: # catch exceptions - we don't wan't to blow up on observability
|
393
392
|
context: Self = cls._context.get()
|
@@ -397,12 +396,12 @@ class ObservabilityContext:
|
|
397
396
|
context._scope,
|
398
397
|
level=level,
|
399
398
|
event=event,
|
400
|
-
|
399
|
+
attributes=attributes,
|
401
400
|
)
|
402
401
|
|
403
402
|
except Exception as exc:
|
404
403
|
cls.record_log(
|
405
|
-
ERROR,
|
404
|
+
ObservabilityLevel.ERROR,
|
406
405
|
f"Failed to record event: {type(event).__qualname__}",
|
407
406
|
exception=exc,
|
408
407
|
)
|
@@ -410,12 +409,13 @@ class ObservabilityContext:
|
|
410
409
|
@classmethod
|
411
410
|
def record_metric(
|
412
411
|
cls,
|
412
|
+
level: ObservabilityLevel,
|
413
413
|
metric: str,
|
414
414
|
/,
|
415
415
|
*,
|
416
416
|
value: float | int,
|
417
417
|
unit: str | None,
|
418
|
-
|
418
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
419
419
|
) -> None:
|
420
420
|
try: # catch exceptions - we don't wan't to blow up on observability
|
421
421
|
context: Self = cls._context.get()
|
@@ -423,15 +423,16 @@ class ObservabilityContext:
|
|
423
423
|
if context.observability is not None:
|
424
424
|
context.observability.metric_recording(
|
425
425
|
context._scope,
|
426
|
+
level=level,
|
426
427
|
metric=metric,
|
427
428
|
value=value,
|
428
429
|
unit=unit,
|
429
|
-
|
430
|
+
attributes=attributes,
|
430
431
|
)
|
431
432
|
|
432
433
|
except Exception as exc:
|
433
434
|
cls.record_log(
|
434
|
-
ERROR,
|
435
|
+
ObservabilityLevel.ERROR,
|
435
436
|
f"Failed to record metric: {metric}",
|
436
437
|
exception=exc,
|
437
438
|
)
|
@@ -439,7 +440,10 @@ class ObservabilityContext:
|
|
439
440
|
@classmethod
|
440
441
|
def record_attributes(
|
441
442
|
cls,
|
442
|
-
|
443
|
+
level: ObservabilityLevel,
|
444
|
+
/,
|
445
|
+
*,
|
446
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
443
447
|
) -> None:
|
444
448
|
try: # catch exceptions - we don't wan't to blow up on observability
|
445
449
|
context: Self = cls._context.get()
|
@@ -447,13 +451,14 @@ class ObservabilityContext:
|
|
447
451
|
if context.observability is not None:
|
448
452
|
context.observability.attributes_recording(
|
449
453
|
context._scope,
|
450
|
-
|
454
|
+
level=level,
|
455
|
+
attributes=attributes,
|
451
456
|
)
|
452
457
|
|
453
458
|
except Exception as exc:
|
454
459
|
cls.record_log(
|
455
|
-
ERROR,
|
456
|
-
|
460
|
+
ObservabilityLevel.ERROR,
|
461
|
+
"Failed to record attributes",
|
457
462
|
exception=exc,
|
458
463
|
)
|
459
464
|
|
haiway/helpers/__init__.py
CHANGED
@@ -4,14 +4,13 @@ from haiway.helpers.observability import LoggerObservability
|
|
4
4
|
from haiway.helpers.retries import retry
|
5
5
|
from haiway.helpers.throttling import throttle
|
6
6
|
from haiway.helpers.timeouted import timeout
|
7
|
-
from haiway.helpers.tracing import
|
7
|
+
from haiway.helpers.tracing import traced
|
8
8
|
|
9
9
|
__all__ = (
|
10
10
|
"CacheMakeKey",
|
11
11
|
"CacheRead",
|
12
12
|
"CacheWrite",
|
13
13
|
"LoggerObservability",
|
14
|
-
"ResultTrace",
|
15
14
|
"asynchronous",
|
16
15
|
"cache",
|
17
16
|
"retry",
|
haiway/helpers/observability.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
from
|
1
|
+
from collections.abc import Mapping
|
2
|
+
from logging import Logger, getLogger
|
2
3
|
from time import monotonic
|
3
4
|
from typing import Any
|
4
5
|
|
5
6
|
from haiway.context import Observability, ObservabilityLevel, ScopeIdentifier
|
6
7
|
from haiway.context.observability import ObservabilityAttribute
|
7
8
|
from haiway.state import State
|
8
|
-
from haiway.
|
9
|
+
from haiway.utils.formatting import format_str
|
9
10
|
|
10
11
|
__all__ = ("LoggerObservability",)
|
11
12
|
|
@@ -63,12 +64,13 @@ class ScopeStore:
|
|
63
64
|
|
64
65
|
|
65
66
|
def LoggerObservability( # noqa: C901, PLR0915
|
66
|
-
logger: Logger,
|
67
|
+
logger: Logger | None = None,
|
67
68
|
/,
|
68
69
|
*,
|
69
|
-
|
70
|
+
debug_context: bool = __debug__,
|
70
71
|
) -> Observability:
|
71
72
|
root_scope: ScopeIdentifier | None = None
|
73
|
+
root_logger: Logger | None = logger
|
72
74
|
scopes: dict[str, ScopeStore] = {}
|
73
75
|
|
74
76
|
def log_recording(
|
@@ -78,12 +80,12 @@ def LoggerObservability( # noqa: C901, PLR0915
|
|
78
80
|
message: str,
|
79
81
|
*args: Any,
|
80
82
|
exception: BaseException | None,
|
81
|
-
**extra: Any,
|
82
83
|
) -> None:
|
83
84
|
assert root_scope is not None # nosec: B101
|
85
|
+
assert root_logger is not None # nosec: B101
|
84
86
|
assert scope.scope_id in scopes # nosec: B101
|
85
87
|
|
86
|
-
|
88
|
+
root_logger.log(
|
87
89
|
level,
|
88
90
|
f"{scope.unique_name} {message}",
|
89
91
|
*args,
|
@@ -93,19 +95,20 @@ def LoggerObservability( # noqa: C901, PLR0915
|
|
93
95
|
def event_recording(
|
94
96
|
scope: ScopeIdentifier,
|
95
97
|
/,
|
96
|
-
*,
|
97
98
|
level: ObservabilityLevel,
|
98
|
-
|
99
|
-
|
99
|
+
*,
|
100
|
+
event: str,
|
101
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
100
102
|
) -> None:
|
101
103
|
assert root_scope is not None # nosec: B101
|
104
|
+
assert root_logger is not None # nosec: B101
|
102
105
|
assert scope.scope_id in scopes # nosec: B101
|
103
106
|
|
104
|
-
event_str: str = f"Event
|
105
|
-
if
|
107
|
+
event_str: str = f"Event: {event} {format_str(attributes)}"
|
108
|
+
if debug_context: # store only for summary
|
106
109
|
scopes[scope.scope_id].store.append(event_str)
|
107
110
|
|
108
|
-
|
111
|
+
root_logger.log(
|
109
112
|
level,
|
110
113
|
f"{scope.unique_name} {event_str}",
|
111
114
|
)
|
@@ -113,41 +116,50 @@ def LoggerObservability( # noqa: C901, PLR0915
|
|
113
116
|
def metric_recording(
|
114
117
|
scope: ScopeIdentifier,
|
115
118
|
/,
|
119
|
+
level: ObservabilityLevel,
|
116
120
|
*,
|
117
121
|
metric: str,
|
118
122
|
value: float | int,
|
119
123
|
unit: str | None,
|
120
|
-
|
124
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
121
125
|
) -> None:
|
122
126
|
assert root_scope is not None # nosec: B101
|
127
|
+
assert root_logger is not None # nosec: B101
|
123
128
|
assert scope.scope_id in scopes # nosec: B101
|
124
129
|
|
125
|
-
metric_str: str
|
126
|
-
if
|
130
|
+
metric_str: str
|
131
|
+
if attributes:
|
132
|
+
metric_str = f"Metric: {metric}={value}{unit or ''}\n{format_str(attributes)}"
|
133
|
+
|
134
|
+
else:
|
135
|
+
metric_str = f"Metric: {metric}={value}{unit or ''}"
|
136
|
+
|
137
|
+
if debug_context: # store only for summary
|
127
138
|
scopes[scope.scope_id].store.append(metric_str)
|
128
139
|
|
129
|
-
|
130
|
-
|
140
|
+
root_logger.log(
|
141
|
+
level,
|
131
142
|
f"{scope.unique_name} {metric_str}",
|
132
143
|
)
|
133
144
|
|
134
145
|
def attributes_recording(
|
135
146
|
scope: ScopeIdentifier,
|
136
147
|
/,
|
137
|
-
|
148
|
+
level: ObservabilityLevel,
|
149
|
+
attributes: Mapping[str, ObservabilityAttribute],
|
138
150
|
) -> None:
|
151
|
+
assert root_scope is not None # nosec: B101
|
152
|
+
assert root_logger is not None # nosec: B101
|
153
|
+
|
139
154
|
if not attributes:
|
140
155
|
return
|
141
156
|
|
142
|
-
attributes_str: str = (
|
143
|
-
|
144
|
-
f"\n{'\n'.join(f'{k}: {v}' for k, v in attributes.items() if v is not None and v is not MISSING)}" # noqa: E501
|
145
|
-
)
|
146
|
-
if summarize_context: # store only for summary
|
157
|
+
attributes_str: str = f"Attributes: {format_str(attributes)}"
|
158
|
+
if debug_context: # store only for summary
|
147
159
|
scopes[scope.scope_id].store.append(attributes_str)
|
148
160
|
|
149
|
-
|
150
|
-
|
161
|
+
root_logger.log(
|
162
|
+
level,
|
151
163
|
attributes_str,
|
152
164
|
)
|
153
165
|
|
@@ -159,18 +171,21 @@ def LoggerObservability( # noqa: C901, PLR0915
|
|
159
171
|
scope_store: ScopeStore = ScopeStore(scope)
|
160
172
|
scopes[scope.scope_id] = scope_store
|
161
173
|
|
162
|
-
logger.log(
|
163
|
-
ObservabilityLevel.INFO,
|
164
|
-
f"{scope.unique_name} Entering scope: {scope.label}",
|
165
|
-
)
|
166
|
-
|
167
174
|
nonlocal root_scope
|
175
|
+
nonlocal root_logger
|
168
176
|
if root_scope is None:
|
169
177
|
root_scope = scope
|
178
|
+
root_logger = logger or getLogger(scope.label)
|
170
179
|
|
171
180
|
else:
|
172
181
|
scopes[scope.parent_id].nested.append(scope_store)
|
173
182
|
|
183
|
+
assert root_logger is not None # nosec: B101
|
184
|
+
root_logger.log(
|
185
|
+
ObservabilityLevel.INFO,
|
186
|
+
f"{scope.unique_name} Entering scope: {scope.label}",
|
187
|
+
)
|
188
|
+
|
174
189
|
def scope_exiting[Metric: State](
|
175
190
|
scope: ScopeIdentifier,
|
176
191
|
/,
|
@@ -178,8 +193,10 @@ def LoggerObservability( # noqa: C901, PLR0915
|
|
178
193
|
exception: BaseException | None,
|
179
194
|
) -> None:
|
180
195
|
nonlocal root_scope
|
196
|
+
nonlocal root_logger
|
181
197
|
nonlocal scopes
|
182
198
|
assert root_scope is not None # nosec: B101
|
199
|
+
assert root_logger is not None # nosec: B101
|
183
200
|
assert scope.scope_id in scopes # nosec: B101
|
184
201
|
|
185
202
|
scopes[scope.scope_id].exit()
|
@@ -187,15 +204,15 @@ def LoggerObservability( # noqa: C901, PLR0915
|
|
187
204
|
if not scopes[scope.scope_id].try_complete():
|
188
205
|
return # not completed yet or already completed
|
189
206
|
|
190
|
-
|
207
|
+
root_logger.log(
|
191
208
|
ObservabilityLevel.INFO,
|
192
209
|
f"{scope.unique_name} Exiting scope: {scope.label}",
|
193
210
|
)
|
194
211
|
metric_str: str = f"Metric - scope_time:{scopes[scope.scope_id].time:.3f}s"
|
195
|
-
if
|
212
|
+
if debug_context: # store only for summary
|
196
213
|
scopes[scope.scope_id].store.append(metric_str)
|
197
214
|
|
198
|
-
|
215
|
+
root_logger.log(
|
199
216
|
ObservabilityLevel.INFO,
|
200
217
|
f"{scope.unique_name} {metric_str}",
|
201
218
|
)
|
@@ -207,14 +224,15 @@ def LoggerObservability( # noqa: C901, PLR0915
|
|
207
224
|
|
208
225
|
# check for root completion
|
209
226
|
if scopes[root_scope.scope_id].completed:
|
210
|
-
if
|
211
|
-
|
227
|
+
if debug_context:
|
228
|
+
root_logger.log(
|
212
229
|
ObservabilityLevel.DEBUG,
|
213
230
|
f"Observability summary:\n{_tree_summary(scopes[root_scope.scope_id])}",
|
214
231
|
)
|
215
232
|
|
216
233
|
# finished root - cleanup state
|
217
234
|
root_scope = None
|
235
|
+
root_logger = None
|
218
236
|
scopes = {}
|
219
237
|
|
220
238
|
return Observability(
|