tnfr 4.5.2__py3-none-any.whl → 7.0.0__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.
Potentially problematic release.
This version of tnfr might be problematic. Click here for more details.
- tnfr/__init__.py +275 -51
- tnfr/__init__.pyi +33 -0
- tnfr/_compat.py +10 -0
- tnfr/_generated_version.py +34 -0
- tnfr/_version.py +49 -0
- tnfr/_version.pyi +7 -0
- tnfr/alias.py +117 -31
- tnfr/alias.pyi +108 -0
- tnfr/cache.py +6 -572
- tnfr/cache.pyi +16 -0
- tnfr/callback_utils.py +16 -38
- tnfr/callback_utils.pyi +79 -0
- tnfr/cli/__init__.py +34 -14
- tnfr/cli/__init__.pyi +26 -0
- tnfr/cli/arguments.py +211 -28
- tnfr/cli/arguments.pyi +27 -0
- tnfr/cli/execution.py +470 -50
- tnfr/cli/execution.pyi +70 -0
- tnfr/cli/utils.py +18 -3
- tnfr/cli/utils.pyi +8 -0
- tnfr/config/__init__.py +13 -0
- tnfr/config/__init__.pyi +10 -0
- tnfr/{constants_glyphs.py → config/constants.py} +26 -20
- tnfr/config/constants.pyi +12 -0
- tnfr/config/feature_flags.py +83 -0
- tnfr/{config.py → config/init.py} +11 -7
- tnfr/config/init.pyi +8 -0
- tnfr/config/operator_names.py +93 -0
- tnfr/config/operator_names.pyi +28 -0
- tnfr/config/presets.py +84 -0
- tnfr/config/presets.pyi +7 -0
- tnfr/constants/__init__.py +80 -29
- tnfr/constants/__init__.pyi +92 -0
- tnfr/constants/aliases.py +31 -0
- tnfr/constants/core.py +4 -4
- tnfr/constants/core.pyi +17 -0
- tnfr/constants/init.py +1 -1
- tnfr/constants/init.pyi +12 -0
- tnfr/constants/metric.py +7 -15
- tnfr/constants/metric.pyi +19 -0
- tnfr/dynamics/__init__.py +165 -633
- tnfr/dynamics/__init__.pyi +82 -0
- tnfr/dynamics/adaptation.py +267 -0
- tnfr/dynamics/aliases.py +23 -0
- tnfr/dynamics/coordination.py +385 -0
- tnfr/dynamics/dnfr.py +2283 -400
- tnfr/dynamics/dnfr.pyi +24 -0
- tnfr/dynamics/integrators.py +406 -98
- tnfr/dynamics/integrators.pyi +34 -0
- tnfr/dynamics/runtime.py +881 -0
- tnfr/dynamics/sampling.py +10 -5
- tnfr/dynamics/sampling.pyi +7 -0
- tnfr/dynamics/selectors.py +719 -0
- tnfr/execution.py +70 -48
- tnfr/execution.pyi +45 -0
- tnfr/flatten.py +13 -9
- tnfr/flatten.pyi +21 -0
- tnfr/gamma.py +66 -53
- tnfr/gamma.pyi +34 -0
- tnfr/glyph_history.py +110 -52
- tnfr/glyph_history.pyi +35 -0
- tnfr/glyph_runtime.py +16 -0
- tnfr/glyph_runtime.pyi +9 -0
- tnfr/immutable.py +69 -28
- tnfr/immutable.pyi +34 -0
- tnfr/initialization.py +16 -16
- tnfr/initialization.pyi +65 -0
- tnfr/io.py +6 -240
- tnfr/io.pyi +16 -0
- tnfr/locking.pyi +7 -0
- tnfr/mathematics/__init__.py +81 -0
- tnfr/mathematics/backend.py +426 -0
- tnfr/mathematics/dynamics.py +398 -0
- tnfr/mathematics/epi.py +254 -0
- tnfr/mathematics/generators.py +222 -0
- tnfr/mathematics/metrics.py +119 -0
- tnfr/mathematics/operators.py +233 -0
- tnfr/mathematics/operators_factory.py +71 -0
- tnfr/mathematics/projection.py +78 -0
- tnfr/mathematics/runtime.py +173 -0
- tnfr/mathematics/spaces.py +247 -0
- tnfr/mathematics/transforms.py +292 -0
- tnfr/metrics/__init__.py +10 -10
- tnfr/metrics/__init__.pyi +20 -0
- tnfr/metrics/coherence.py +993 -324
- tnfr/metrics/common.py +23 -16
- tnfr/metrics/common.pyi +46 -0
- tnfr/metrics/core.py +251 -35
- tnfr/metrics/core.pyi +13 -0
- tnfr/metrics/diagnosis.py +708 -111
- tnfr/metrics/diagnosis.pyi +85 -0
- tnfr/metrics/export.py +27 -15
- tnfr/metrics/glyph_timing.py +232 -42
- tnfr/metrics/reporting.py +33 -22
- tnfr/metrics/reporting.pyi +12 -0
- tnfr/metrics/sense_index.py +987 -43
- tnfr/metrics/sense_index.pyi +9 -0
- tnfr/metrics/trig.py +214 -23
- tnfr/metrics/trig.pyi +13 -0
- tnfr/metrics/trig_cache.py +115 -22
- tnfr/metrics/trig_cache.pyi +10 -0
- tnfr/node.py +542 -136
- tnfr/node.pyi +178 -0
- tnfr/observers.py +152 -35
- tnfr/observers.pyi +31 -0
- tnfr/ontosim.py +23 -19
- tnfr/ontosim.pyi +28 -0
- tnfr/operators/__init__.py +601 -82
- tnfr/operators/__init__.pyi +45 -0
- tnfr/operators/definitions.py +513 -0
- tnfr/operators/definitions.pyi +78 -0
- tnfr/operators/grammar.py +760 -0
- tnfr/operators/jitter.py +107 -38
- tnfr/operators/jitter.pyi +11 -0
- tnfr/operators/registry.py +75 -0
- tnfr/operators/registry.pyi +13 -0
- tnfr/operators/remesh.py +149 -88
- tnfr/py.typed +0 -0
- tnfr/rng.py +46 -143
- tnfr/rng.pyi +14 -0
- tnfr/schemas/__init__.py +8 -0
- tnfr/schemas/grammar.json +94 -0
- tnfr/selector.py +25 -19
- tnfr/selector.pyi +19 -0
- tnfr/sense.py +72 -62
- tnfr/sense.pyi +23 -0
- tnfr/structural.py +522 -262
- tnfr/structural.pyi +69 -0
- tnfr/telemetry/__init__.py +35 -0
- tnfr/telemetry/cache_metrics.py +226 -0
- tnfr/telemetry/nu_f.py +423 -0
- tnfr/telemetry/nu_f.pyi +123 -0
- tnfr/telemetry/verbosity.py +37 -0
- tnfr/tokens.py +1 -3
- tnfr/tokens.pyi +36 -0
- tnfr/trace.py +270 -113
- tnfr/trace.pyi +40 -0
- tnfr/types.py +574 -6
- tnfr/types.pyi +331 -0
- tnfr/units.py +69 -0
- tnfr/units.pyi +16 -0
- tnfr/utils/__init__.py +217 -0
- tnfr/utils/__init__.pyi +202 -0
- tnfr/utils/cache.py +2395 -0
- tnfr/utils/cache.pyi +468 -0
- tnfr/utils/chunks.py +104 -0
- tnfr/utils/chunks.pyi +21 -0
- tnfr/{collections_utils.py → utils/data.py} +147 -90
- tnfr/utils/data.pyi +64 -0
- tnfr/utils/graph.py +85 -0
- tnfr/utils/graph.pyi +10 -0
- tnfr/utils/init.py +770 -0
- tnfr/utils/init.pyi +78 -0
- tnfr/utils/io.py +456 -0
- tnfr/{helpers → utils}/numeric.py +51 -24
- tnfr/utils/numeric.pyi +21 -0
- tnfr/validation/__init__.py +113 -0
- tnfr/validation/__init__.pyi +77 -0
- tnfr/validation/compatibility.py +95 -0
- tnfr/validation/compatibility.pyi +6 -0
- tnfr/validation/grammar.py +71 -0
- tnfr/validation/grammar.pyi +40 -0
- tnfr/validation/graph.py +138 -0
- tnfr/validation/graph.pyi +17 -0
- tnfr/validation/rules.py +281 -0
- tnfr/validation/rules.pyi +55 -0
- tnfr/validation/runtime.py +263 -0
- tnfr/validation/runtime.pyi +31 -0
- tnfr/validation/soft_filters.py +170 -0
- tnfr/validation/soft_filters.pyi +37 -0
- tnfr/validation/spectral.py +159 -0
- tnfr/validation/spectral.pyi +46 -0
- tnfr/validation/syntax.py +40 -0
- tnfr/validation/syntax.pyi +10 -0
- tnfr/validation/window.py +39 -0
- tnfr/validation/window.pyi +1 -0
- tnfr/viz/__init__.py +9 -0
- tnfr/viz/matplotlib.py +246 -0
- tnfr-7.0.0.dist-info/METADATA +179 -0
- tnfr-7.0.0.dist-info/RECORD +185 -0
- {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/licenses/LICENSE.md +1 -1
- tnfr/grammar.py +0 -344
- tnfr/graph_utils.py +0 -84
- tnfr/helpers/__init__.py +0 -71
- tnfr/import_utils.py +0 -228
- tnfr/json_utils.py +0 -162
- tnfr/logging_utils.py +0 -116
- tnfr/presets.py +0 -60
- tnfr/validators.py +0 -84
- tnfr/value_utils.py +0 -59
- tnfr-4.5.2.dist-info/METADATA +0 -379
- tnfr-4.5.2.dist-info/RECORD +0 -67
- {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/WHEEL +0 -0
- {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/entry_points.txt +0 -0
- {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/top_level.txt +0 -0
tnfr/structural.pyi
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Callable, Hashable, Iterable, Sequence
|
|
2
|
+
|
|
3
|
+
from .validation import SequenceValidationResult
|
|
4
|
+
from .operators.definitions import (
|
|
5
|
+
Coherence,
|
|
6
|
+
Contraction,
|
|
7
|
+
Coupling,
|
|
8
|
+
Dissonance,
|
|
9
|
+
Emission,
|
|
10
|
+
Expansion,
|
|
11
|
+
Mutation,
|
|
12
|
+
Operator,
|
|
13
|
+
Reception,
|
|
14
|
+
Recursivity,
|
|
15
|
+
Resonance,
|
|
16
|
+
SelfOrganization,
|
|
17
|
+
Silence,
|
|
18
|
+
Transition,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
import networkx as nx
|
|
23
|
+
from .mathematics import (
|
|
24
|
+
BasicStateProjector,
|
|
25
|
+
CoherenceOperator,
|
|
26
|
+
FrequencyOperator,
|
|
27
|
+
HilbertSpace,
|
|
28
|
+
MathematicalDynamicsEngine,
|
|
29
|
+
NFRValidator,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
__all__: tuple[str, ...]
|
|
33
|
+
|
|
34
|
+
def __getattr__(name: str) -> Any: ...
|
|
35
|
+
def create_nfr(
|
|
36
|
+
name: str,
|
|
37
|
+
*,
|
|
38
|
+
epi: float = ...,
|
|
39
|
+
vf: float = ...,
|
|
40
|
+
theta: float = ...,
|
|
41
|
+
graph: "nx.Graph" | None = ...,
|
|
42
|
+
dnfr_hook: Callable[..., None] = ...,
|
|
43
|
+
) -> tuple["nx.Graph", str]: ...
|
|
44
|
+
def create_math_nfr(
|
|
45
|
+
name: str,
|
|
46
|
+
*,
|
|
47
|
+
epi: float = ...,
|
|
48
|
+
vf: float = ...,
|
|
49
|
+
theta: float = ...,
|
|
50
|
+
graph: "nx.Graph" | None = ...,
|
|
51
|
+
dnfr_hook: Callable[..., None] = ...,
|
|
52
|
+
dimension: int | None = ...,
|
|
53
|
+
hilbert_space: "HilbertSpace" | None = ...,
|
|
54
|
+
coherence_operator: "CoherenceOperator" | None = ...,
|
|
55
|
+
coherence_spectrum: Sequence[float] | None = ...,
|
|
56
|
+
coherence_c_min: float | None = ...,
|
|
57
|
+
coherence_threshold: float | None = ...,
|
|
58
|
+
frequency_operator: "FrequencyOperator" | None = ...,
|
|
59
|
+
frequency_diagonal: Sequence[float] | None = ...,
|
|
60
|
+
generator_diagonal: Sequence[float] | None = ...,
|
|
61
|
+
state_projector: "BasicStateProjector" | None = ...,
|
|
62
|
+
dynamics_engine: "MathematicalDynamicsEngine" | None = ...,
|
|
63
|
+
validator: "NFRValidator" | None = ...,
|
|
64
|
+
) -> tuple["nx.Graph", str]: ...
|
|
65
|
+
|
|
66
|
+
OPERATORS: dict[str, Operator]
|
|
67
|
+
|
|
68
|
+
def validate_sequence(names: Iterable[str]) -> SequenceValidationResult: ...
|
|
69
|
+
def run_sequence(G: "nx.Graph", node: Hashable, ops: Iterable[Operator]) -> None: ...
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Telemetry helpers for shared observability settings."""
|
|
2
|
+
|
|
3
|
+
from .cache_metrics import (
|
|
4
|
+
CacheMetricsSnapshot,
|
|
5
|
+
CacheTelemetryPublisher,
|
|
6
|
+
ensure_cache_metrics_publisher,
|
|
7
|
+
publish_graph_cache_metrics,
|
|
8
|
+
)
|
|
9
|
+
from .nu_f import (
|
|
10
|
+
NuFSnapshot,
|
|
11
|
+
NuFTelemetryAccumulator,
|
|
12
|
+
NuFWindow,
|
|
13
|
+
ensure_nu_f_telemetry,
|
|
14
|
+
record_nu_f_window,
|
|
15
|
+
)
|
|
16
|
+
from .verbosity import (
|
|
17
|
+
TELEMETRY_VERBOSITY_DEFAULT,
|
|
18
|
+
TELEMETRY_VERBOSITY_LEVELS,
|
|
19
|
+
TelemetryVerbosity,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"CacheMetricsSnapshot",
|
|
24
|
+
"CacheTelemetryPublisher",
|
|
25
|
+
"ensure_cache_metrics_publisher",
|
|
26
|
+
"publish_graph_cache_metrics",
|
|
27
|
+
"NuFWindow",
|
|
28
|
+
"NuFSnapshot",
|
|
29
|
+
"NuFTelemetryAccumulator",
|
|
30
|
+
"ensure_nu_f_telemetry",
|
|
31
|
+
"record_nu_f_window",
|
|
32
|
+
"TelemetryVerbosity",
|
|
33
|
+
"TELEMETRY_VERBOSITY_DEFAULT",
|
|
34
|
+
"TELEMETRY_VERBOSITY_LEVELS",
|
|
35
|
+
]
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"""Cache telemetry publishers for structured observability channels."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import weakref
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Any, MutableMapping, TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from ..utils import (
|
|
11
|
+
_graph_cache_manager,
|
|
12
|
+
CacheManager,
|
|
13
|
+
CacheStatistics,
|
|
14
|
+
get_logger,
|
|
15
|
+
json_dumps,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING: # pragma: no cover - typing helpers
|
|
19
|
+
from networkx import Graph
|
|
20
|
+
|
|
21
|
+
from ..types import TNFRGraph
|
|
22
|
+
|
|
23
|
+
__all__ = (
|
|
24
|
+
"CacheMetricsSnapshot",
|
|
25
|
+
"CacheTelemetryPublisher",
|
|
26
|
+
"ensure_cache_metrics_publisher",
|
|
27
|
+
"publish_graph_cache_metrics",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class CacheMetricsSnapshot:
|
|
33
|
+
"""Structured cache metrics enriched with ratios and latency estimates."""
|
|
34
|
+
|
|
35
|
+
cache: str
|
|
36
|
+
hits: int
|
|
37
|
+
misses: int
|
|
38
|
+
evictions: int
|
|
39
|
+
total_time: float
|
|
40
|
+
timings: int
|
|
41
|
+
hit_ratio: float | None
|
|
42
|
+
miss_ratio: float | None
|
|
43
|
+
avg_latency: float | None
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def from_statistics(
|
|
47
|
+
cls, name: str, stats: CacheStatistics
|
|
48
|
+
) -> "CacheMetricsSnapshot":
|
|
49
|
+
"""Build a snapshot computing ratios from :class:`CacheStatistics`."""
|
|
50
|
+
|
|
51
|
+
hits = int(stats.hits)
|
|
52
|
+
misses = int(stats.misses)
|
|
53
|
+
evictions = int(stats.evictions)
|
|
54
|
+
total_time = float(stats.total_time)
|
|
55
|
+
timings = int(stats.timings)
|
|
56
|
+
requests = hits + misses
|
|
57
|
+
hit_ratio = (hits / requests) if requests else None
|
|
58
|
+
miss_ratio = (misses / requests) if requests else None
|
|
59
|
+
avg_latency = (total_time / timings) if timings else None
|
|
60
|
+
return cls(
|
|
61
|
+
cache=name,
|
|
62
|
+
hits=hits,
|
|
63
|
+
misses=misses,
|
|
64
|
+
evictions=evictions,
|
|
65
|
+
total_time=total_time,
|
|
66
|
+
timings=timings,
|
|
67
|
+
hit_ratio=hit_ratio,
|
|
68
|
+
miss_ratio=miss_ratio,
|
|
69
|
+
avg_latency=avg_latency,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def as_payload(self) -> dict[str, Any]:
|
|
73
|
+
"""Return a dictionary suitable for structured logging."""
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
"cache": self.cache,
|
|
77
|
+
"hits": self.hits,
|
|
78
|
+
"misses": self.misses,
|
|
79
|
+
"evictions": self.evictions,
|
|
80
|
+
"total_time": self.total_time,
|
|
81
|
+
"timings": self.timings,
|
|
82
|
+
"hit_ratio": self.hit_ratio,
|
|
83
|
+
"miss_ratio": self.miss_ratio,
|
|
84
|
+
"avg_latency": self.avg_latency,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class CacheTelemetryPublisher:
|
|
89
|
+
"""Metrics publisher broadcasting cache counters to observability channels."""
|
|
90
|
+
|
|
91
|
+
def __init__(
|
|
92
|
+
self,
|
|
93
|
+
*,
|
|
94
|
+
graph: "TNFRGraph | Graph | MutableMapping[str, Any] | None" = None,
|
|
95
|
+
logger: logging.Logger | None = None,
|
|
96
|
+
hit_ratio_alert: float = 0.5,
|
|
97
|
+
latency_alert: float = 0.1,
|
|
98
|
+
) -> None:
|
|
99
|
+
self._logger = logger or get_logger("tnfr.telemetry.cache")
|
|
100
|
+
self._graph_ref: weakref.ReferenceType[
|
|
101
|
+
"TNFRGraph | Graph | MutableMapping[str, Any]"
|
|
102
|
+
] | None = None
|
|
103
|
+
self._hit_ratio_alert = float(hit_ratio_alert)
|
|
104
|
+
self._latency_alert = float(latency_alert)
|
|
105
|
+
self.attach_graph(graph)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def logger(self) -> logging.Logger:
|
|
109
|
+
"""Logger used for structured cache telemetry."""
|
|
110
|
+
|
|
111
|
+
return self._logger
|
|
112
|
+
|
|
113
|
+
def attach_graph(
|
|
114
|
+
self, graph: "TNFRGraph | Graph | MutableMapping[str, Any] | None"
|
|
115
|
+
) -> None:
|
|
116
|
+
"""Attach ``graph`` so observability callbacks receive metrics."""
|
|
117
|
+
|
|
118
|
+
if graph is None:
|
|
119
|
+
return
|
|
120
|
+
try:
|
|
121
|
+
self._graph_ref = weakref.ref(graph) # type: ignore[arg-type]
|
|
122
|
+
except TypeError: # pragma: no cover - defensive path for exotic graphs
|
|
123
|
+
self._graph_ref = None
|
|
124
|
+
|
|
125
|
+
def _resolve_graph(
|
|
126
|
+
self,
|
|
127
|
+
) -> "TNFRGraph | Graph | MutableMapping[str, Any] | None":
|
|
128
|
+
return self._graph_ref() if self._graph_ref is not None else None
|
|
129
|
+
|
|
130
|
+
def __call__(self, name: str, stats: CacheStatistics) -> None:
|
|
131
|
+
"""Emit structured telemetry and invoke observability hooks."""
|
|
132
|
+
|
|
133
|
+
snapshot = CacheMetricsSnapshot.from_statistics(name, stats)
|
|
134
|
+
payload = snapshot.as_payload()
|
|
135
|
+
message = json_dumps({"event": "cache_metrics", **payload}, sort_keys=True)
|
|
136
|
+
self._logger.info(message)
|
|
137
|
+
|
|
138
|
+
if (
|
|
139
|
+
snapshot.hit_ratio is not None
|
|
140
|
+
and snapshot.hit_ratio < self._hit_ratio_alert
|
|
141
|
+
and snapshot.misses > 0
|
|
142
|
+
):
|
|
143
|
+
warning = json_dumps(
|
|
144
|
+
{
|
|
145
|
+
"event": "cache_metrics.low_hit_ratio",
|
|
146
|
+
"cache": name,
|
|
147
|
+
"hit_ratio": snapshot.hit_ratio,
|
|
148
|
+
"threshold": self._hit_ratio_alert,
|
|
149
|
+
"requests": snapshot.hits + snapshot.misses,
|
|
150
|
+
},
|
|
151
|
+
sort_keys=True,
|
|
152
|
+
)
|
|
153
|
+
self._logger.warning(warning)
|
|
154
|
+
|
|
155
|
+
if (
|
|
156
|
+
snapshot.avg_latency is not None
|
|
157
|
+
and snapshot.avg_latency > self._latency_alert
|
|
158
|
+
and snapshot.timings > 0
|
|
159
|
+
):
|
|
160
|
+
warning = json_dumps(
|
|
161
|
+
{
|
|
162
|
+
"event": "cache_metrics.high_latency",
|
|
163
|
+
"cache": name,
|
|
164
|
+
"avg_latency": snapshot.avg_latency,
|
|
165
|
+
"threshold": self._latency_alert,
|
|
166
|
+
"timings": snapshot.timings,
|
|
167
|
+
},
|
|
168
|
+
sort_keys=True,
|
|
169
|
+
)
|
|
170
|
+
self._logger.warning(warning)
|
|
171
|
+
|
|
172
|
+
graph = self._resolve_graph()
|
|
173
|
+
if graph is not None:
|
|
174
|
+
from ..callback_utils import CallbackEvent, callback_manager
|
|
175
|
+
|
|
176
|
+
ctx = {"cache": name, "metrics": payload}
|
|
177
|
+
callback_manager.invoke_callbacks(graph, CallbackEvent.CACHE_METRICS, ctx)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
_PUBLISHER_ATTR = "_tnfr_cache_metrics_publisher"
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def ensure_cache_metrics_publisher(
|
|
184
|
+
manager: CacheManager,
|
|
185
|
+
*,
|
|
186
|
+
graph: "TNFRGraph | Graph | MutableMapping[str, Any] | None" = None,
|
|
187
|
+
logger: logging.Logger | None = None,
|
|
188
|
+
hit_ratio_alert: float = 0.5,
|
|
189
|
+
latency_alert: float = 0.1,
|
|
190
|
+
) -> CacheTelemetryPublisher:
|
|
191
|
+
"""Attach a :class:`CacheTelemetryPublisher` to ``manager`` if missing."""
|
|
192
|
+
|
|
193
|
+
publisher = getattr(manager, _PUBLISHER_ATTR, None)
|
|
194
|
+
if not isinstance(publisher, CacheTelemetryPublisher):
|
|
195
|
+
publisher = CacheTelemetryPublisher(
|
|
196
|
+
graph=graph,
|
|
197
|
+
logger=logger,
|
|
198
|
+
hit_ratio_alert=hit_ratio_alert,
|
|
199
|
+
latency_alert=latency_alert,
|
|
200
|
+
)
|
|
201
|
+
manager.register_metrics_publisher(publisher)
|
|
202
|
+
setattr(manager, _PUBLISHER_ATTR, publisher)
|
|
203
|
+
else:
|
|
204
|
+
if graph is not None:
|
|
205
|
+
publisher.attach_graph(graph)
|
|
206
|
+
return publisher
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def publish_graph_cache_metrics(
|
|
210
|
+
graph: "TNFRGraph | Graph | MutableMapping[str, Any]",
|
|
211
|
+
*,
|
|
212
|
+
manager: CacheManager | None = None,
|
|
213
|
+
hit_ratio_alert: float = 0.5,
|
|
214
|
+
latency_alert: float = 0.1,
|
|
215
|
+
) -> None:
|
|
216
|
+
"""Publish cache metrics for ``graph`` using the shared manager."""
|
|
217
|
+
|
|
218
|
+
if manager is None:
|
|
219
|
+
manager = _graph_cache_manager(getattr(graph, "graph", graph))
|
|
220
|
+
ensure_cache_metrics_publisher(
|
|
221
|
+
manager,
|
|
222
|
+
graph=graph,
|
|
223
|
+
hit_ratio_alert=hit_ratio_alert,
|
|
224
|
+
latency_alert=latency_alert,
|
|
225
|
+
)
|
|
226
|
+
manager.publish_metrics()
|