exonware-xwnode 0.0.1.12__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.
Files changed (132) hide show
  1. exonware/__init__.py +14 -0
  2. exonware/xwnode/__init__.py +127 -0
  3. exonware/xwnode/base.py +676 -0
  4. exonware/xwnode/config.py +178 -0
  5. exonware/xwnode/contracts.py +730 -0
  6. exonware/xwnode/errors.py +503 -0
  7. exonware/xwnode/facade.py +460 -0
  8. exonware/xwnode/strategies/__init__.py +158 -0
  9. exonware/xwnode/strategies/advisor.py +463 -0
  10. exonware/xwnode/strategies/edges/__init__.py +32 -0
  11. exonware/xwnode/strategies/edges/adj_list.py +227 -0
  12. exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
  13. exonware/xwnode/strategies/edges/base.py +169 -0
  14. exonware/xwnode/strategies/flyweight.py +328 -0
  15. exonware/xwnode/strategies/impls/__init__.py +13 -0
  16. exonware/xwnode/strategies/impls/_base_edge.py +403 -0
  17. exonware/xwnode/strategies/impls/_base_node.py +307 -0
  18. exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
  19. exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
  20. exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
  21. exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
  22. exonware/xwnode/strategies/impls/edge_coo.py +533 -0
  23. exonware/xwnode/strategies/impls/edge_csc.py +447 -0
  24. exonware/xwnode/strategies/impls/edge_csr.py +492 -0
  25. exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
  26. exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
  27. exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
  28. exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
  29. exonware/xwnode/strategies/impls/edge_octree.py +574 -0
  30. exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
  31. exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
  32. exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
  33. exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
  34. exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
  35. exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
  36. exonware/xwnode/strategies/manager.py +775 -0
  37. exonware/xwnode/strategies/metrics.py +538 -0
  38. exonware/xwnode/strategies/migration.py +432 -0
  39. exonware/xwnode/strategies/nodes/__init__.py +50 -0
  40. exonware/xwnode/strategies/nodes/_base_node.py +307 -0
  41. exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
  42. exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
  43. exonware/xwnode/strategies/nodes/array_list.py +209 -0
  44. exonware/xwnode/strategies/nodes/base.py +247 -0
  45. exonware/xwnode/strategies/nodes/deque.py +200 -0
  46. exonware/xwnode/strategies/nodes/hash_map.py +135 -0
  47. exonware/xwnode/strategies/nodes/heap.py +307 -0
  48. exonware/xwnode/strategies/nodes/linked_list.py +232 -0
  49. exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
  50. exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
  51. exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
  52. exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
  53. exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
  54. exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
  55. exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
  56. exonware/xwnode/strategies/nodes/node_btree.py +357 -0
  57. exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
  58. exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
  59. exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
  60. exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
  61. exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
  62. exonware/xwnode/strategies/nodes/node_heap.py +191 -0
  63. exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
  64. exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
  65. exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
  66. exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
  67. exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
  68. exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
  69. exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
  70. exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
  71. exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
  72. exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
  73. exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
  74. exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
  75. exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
  76. exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
  77. exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
  78. exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
  79. exonware/xwnode/strategies/nodes/node_treap.py +387 -0
  80. exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
  81. exonware/xwnode/strategies/nodes/node_trie.py +252 -0
  82. exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
  83. exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
  84. exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
  85. exonware/xwnode/strategies/nodes/queue.py +161 -0
  86. exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
  87. exonware/xwnode/strategies/nodes/stack.py +152 -0
  88. exonware/xwnode/strategies/nodes/trie.py +274 -0
  89. exonware/xwnode/strategies/nodes/union_find.py +283 -0
  90. exonware/xwnode/strategies/pattern_detector.py +603 -0
  91. exonware/xwnode/strategies/performance_monitor.py +487 -0
  92. exonware/xwnode/strategies/queries/__init__.py +24 -0
  93. exonware/xwnode/strategies/queries/base.py +236 -0
  94. exonware/xwnode/strategies/queries/cql.py +201 -0
  95. exonware/xwnode/strategies/queries/cypher.py +181 -0
  96. exonware/xwnode/strategies/queries/datalog.py +70 -0
  97. exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
  98. exonware/xwnode/strategies/queries/eql.py +70 -0
  99. exonware/xwnode/strategies/queries/flux.py +70 -0
  100. exonware/xwnode/strategies/queries/gql.py +70 -0
  101. exonware/xwnode/strategies/queries/graphql.py +240 -0
  102. exonware/xwnode/strategies/queries/gremlin.py +181 -0
  103. exonware/xwnode/strategies/queries/hiveql.py +214 -0
  104. exonware/xwnode/strategies/queries/hql.py +70 -0
  105. exonware/xwnode/strategies/queries/jmespath.py +219 -0
  106. exonware/xwnode/strategies/queries/jq.py +66 -0
  107. exonware/xwnode/strategies/queries/json_query.py +66 -0
  108. exonware/xwnode/strategies/queries/jsoniq.py +248 -0
  109. exonware/xwnode/strategies/queries/kql.py +70 -0
  110. exonware/xwnode/strategies/queries/linq.py +238 -0
  111. exonware/xwnode/strategies/queries/logql.py +70 -0
  112. exonware/xwnode/strategies/queries/mql.py +68 -0
  113. exonware/xwnode/strategies/queries/n1ql.py +210 -0
  114. exonware/xwnode/strategies/queries/partiql.py +70 -0
  115. exonware/xwnode/strategies/queries/pig.py +215 -0
  116. exonware/xwnode/strategies/queries/promql.py +70 -0
  117. exonware/xwnode/strategies/queries/sparql.py +220 -0
  118. exonware/xwnode/strategies/queries/sql.py +275 -0
  119. exonware/xwnode/strategies/queries/xml_query.py +66 -0
  120. exonware/xwnode/strategies/queries/xpath.py +223 -0
  121. exonware/xwnode/strategies/queries/xquery.py +258 -0
  122. exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
  123. exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
  124. exonware/xwnode/strategies/registry.py +604 -0
  125. exonware/xwnode/strategies/simple.py +273 -0
  126. exonware/xwnode/strategies/utils.py +532 -0
  127. exonware/xwnode/types.py +912 -0
  128. exonware/xwnode/version.py +78 -0
  129. exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
  130. exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
  131. exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
  132. exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,538 @@
1
+ #!/usr/bin/env python3
2
+ #exonware/xwnode/src/exonware/xwnode/strategies/metrics.py
3
+ """
4
+ Strategy Metrics and Statistics
5
+
6
+ Comprehensive metrics collection and analysis for strategy performance,
7
+ memory usage, and optimization recommendations.
8
+
9
+ Company: eXonware.com
10
+ Author: Eng. Muhammad AlShehri
11
+ Email: connect@exonware.com
12
+ Version: 0.0.1.12
13
+ Generation Date: 07-Sep-2025
14
+ """
15
+
16
+ import time
17
+ import threading
18
+ from typing import Any, Dict, List, Optional, Union
19
+ from dataclasses import dataclass, field
20
+ from collections import defaultdict, deque
21
+ from enum import Enum
22
+ from exonware.xwsystem import get_logger
23
+
24
+ logger = get_logger(__name__)
25
+
26
+ from ..types import NodeMode, EdgeMode
27
+ from .flyweight import get_flyweight_stats
28
+ from .pattern_detector import get_detector
29
+ from .performance_monitor import get_monitor, get_performance_summary
30
+
31
+
32
+
33
+ class MetricType(Enum):
34
+ """Types of metrics to collect."""
35
+ PERFORMANCE = "performance"
36
+ MEMORY = "memory"
37
+ USAGE = "usage"
38
+ OPTIMIZATION = "optimization"
39
+ ERROR = "error"
40
+
41
+
42
+ @dataclass
43
+ class MetricSnapshot:
44
+ """Snapshot of metrics at a point in time."""
45
+ timestamp: float
46
+ metric_type: MetricType
47
+ value: float
48
+ metadata: Dict[str, Any] = field(default_factory=dict)
49
+
50
+
51
+ @dataclass
52
+ class StrategyMetrics:
53
+ """Comprehensive metrics for a strategy."""
54
+ strategy_id: str
55
+ strategy_name: str
56
+ mode: Union[NodeMode, EdgeMode]
57
+ total_operations: int = 0
58
+ total_time: float = 0.0
59
+ average_time: float = 0.0
60
+ memory_usage: float = 0.0
61
+ error_count: int = 0
62
+ error_rate: float = 0.0
63
+ optimization_score: float = 0.0
64
+ last_updated: float = field(default_factory=time.time)
65
+ snapshots: List[MetricSnapshot] = field(default_factory=list)
66
+
67
+
68
+ class StrategyMetricsCollector:
69
+ """
70
+ Comprehensive metrics collector for strategy performance analysis.
71
+ """
72
+
73
+ def __init__(self, history_size: int = 1000):
74
+ """
75
+ Initialize metrics collector.
76
+
77
+ Args:
78
+ history_size: Maximum number of metric snapshots to keep
79
+ """
80
+ self._history_size = history_size
81
+ self._strategy_metrics: Dict[str, StrategyMetrics] = {}
82
+ self._global_metrics: Dict[str, Any] = {
83
+ 'total_strategies': 0,
84
+ 'total_operations': 0,
85
+ 'total_memory_usage': 0.0,
86
+ 'average_performance': 0.0,
87
+ 'system_uptime': time.time(),
88
+ 'last_collection': time.time()
89
+ }
90
+ self._lock = threading.RLock()
91
+ self._collection_interval = 60.0 # 1 minute
92
+ self._last_collection = time.time()
93
+
94
+ def collect_comprehensive_metrics(self) -> Dict[str, Any]:
95
+ """
96
+ Collect comprehensive metrics from all components.
97
+
98
+ Returns:
99
+ Complete metrics dictionary
100
+ """
101
+ with self._lock:
102
+ current_time = time.time()
103
+
104
+ # Collect from all components
105
+ flyweight_stats = get_flyweight_stats()
106
+ monitor_summary = get_performance_summary()
107
+ detector_stats = get_detector().get_stats()
108
+
109
+ # Update global metrics
110
+ self._global_metrics.update({
111
+ 'total_strategies': len(self._strategy_metrics),
112
+ 'total_operations': monitor_summary.get('total_operations', 0),
113
+ 'total_memory_usage': monitor_summary.get('average_operation_time', 0.0),
114
+ 'average_performance': monitor_summary.get('average_operation_time', 0.0),
115
+ 'last_collection': current_time,
116
+ 'collection_interval': current_time - self._last_collection
117
+ })
118
+
119
+ self._last_collection = current_time
120
+
121
+ return {
122
+ 'timestamp': current_time,
123
+ 'global_metrics': self._global_metrics.copy(),
124
+ 'flyweight_metrics': flyweight_stats,
125
+ 'performance_metrics': monitor_summary,
126
+ 'detector_metrics': detector_stats,
127
+ 'strategy_metrics': self._get_strategy_metrics_summary(),
128
+ 'optimization_recommendations': self._generate_optimization_recommendations(),
129
+ 'system_health': self._assess_system_health()
130
+ }
131
+
132
+ def record_strategy_metric(
133
+ self,
134
+ strategy_id: str,
135
+ strategy_name: str,
136
+ mode: Union[NodeMode, EdgeMode],
137
+ metric_type: MetricType,
138
+ value: float,
139
+ **metadata: Any
140
+ ) -> None:
141
+ """
142
+ Record a metric for a specific strategy.
143
+
144
+ Args:
145
+ strategy_id: Unique strategy identifier
146
+ strategy_name: Human-readable strategy name
147
+ mode: Strategy mode
148
+ metric_type: Type of metric
149
+ value: Metric value
150
+ **metadata: Additional metadata
151
+ """
152
+ with self._lock:
153
+ # Get or create strategy metrics
154
+ if strategy_id not in self._strategy_metrics:
155
+ self._strategy_metrics[strategy_id] = StrategyMetrics(
156
+ strategy_id=strategy_id,
157
+ strategy_name=strategy_name,
158
+ mode=mode
159
+ )
160
+
161
+ metrics = self._strategy_metrics[strategy_id]
162
+
163
+ # Update metrics based on type
164
+ if metric_type == MetricType.PERFORMANCE:
165
+ metrics.total_operations += 1
166
+ metrics.total_time += value
167
+ metrics.average_time = metrics.total_time / metrics.total_operations
168
+ elif metric_type == MetricType.MEMORY:
169
+ metrics.memory_usage = value
170
+ elif metric_type == MetricType.ERROR:
171
+ metrics.error_count += 1
172
+ metrics.error_rate = metrics.error_count / max(metrics.total_operations, 1)
173
+
174
+ # Add snapshot
175
+ snapshot = MetricSnapshot(
176
+ timestamp=time.time(),
177
+ metric_type=metric_type,
178
+ value=value,
179
+ metadata=metadata
180
+ )
181
+ metrics.snapshots.append(snapshot)
182
+
183
+ # Trim history
184
+ if len(metrics.snapshots) > self._history_size:
185
+ metrics.snapshots = metrics.snapshots[-self._history_size:]
186
+
187
+ metrics.last_updated = time.time()
188
+
189
+ logger.debug(f"๐Ÿ“Š Recorded {metric_type.value} metric for {strategy_name}: {value}")
190
+
191
+ def get_strategy_metrics(self, strategy_id: str) -> Optional[StrategyMetrics]:
192
+ """
193
+ Get metrics for a specific strategy.
194
+
195
+ Args:
196
+ strategy_id: Strategy identifier
197
+
198
+ Returns:
199
+ Strategy metrics or None if not found
200
+ """
201
+ with self._lock:
202
+ return self._strategy_metrics.get(strategy_id)
203
+
204
+ def get_top_performing_strategies(self, limit: int = 5) -> List[StrategyMetrics]:
205
+ """
206
+ Get top performing strategies by average operation time.
207
+
208
+ Args:
209
+ limit: Maximum number of strategies to return
210
+
211
+ Returns:
212
+ List of top performing strategies
213
+ """
214
+ with self._lock:
215
+ strategies = [
216
+ metrics for metrics in self._strategy_metrics.values()
217
+ if metrics.total_operations > 0
218
+ ]
219
+
220
+ # Sort by average time (lower is better)
221
+ strategies.sort(key=lambda x: x.average_time)
222
+
223
+ return strategies[:limit]
224
+
225
+ def get_memory_usage_summary(self) -> Dict[str, Any]:
226
+ """
227
+ Get memory usage summary across all strategies.
228
+
229
+ Returns:
230
+ Memory usage summary
231
+ """
232
+ with self._lock:
233
+ total_memory = sum(metrics.memory_usage for metrics in self._strategy_metrics.values())
234
+ strategy_count = len(self._strategy_metrics)
235
+
236
+ return {
237
+ 'total_memory_usage': total_memory,
238
+ 'average_memory_per_strategy': total_memory / max(strategy_count, 1),
239
+ 'strategy_count': strategy_count,
240
+ 'memory_by_strategy': {
241
+ metrics.strategy_name: metrics.memory_usage
242
+ for metrics in self._strategy_metrics.values()
243
+ }
244
+ }
245
+
246
+ def get_performance_trends(self, strategy_id: str, hours: int = 24) -> Dict[str, Any]:
247
+ """
248
+ Get performance trends for a strategy over time.
249
+
250
+ Args:
251
+ strategy_id: Strategy identifier
252
+ hours: Number of hours to analyze
253
+
254
+ Returns:
255
+ Performance trends data
256
+ """
257
+ with self._lock:
258
+ metrics = self._strategy_metrics.get(strategy_id)
259
+ if not metrics:
260
+ return {}
261
+
262
+ cutoff_time = time.time() - (hours * 3600)
263
+ recent_snapshots = [
264
+ snapshot for snapshot in metrics.snapshots
265
+ if snapshot.timestamp >= cutoff_time
266
+ ]
267
+
268
+ if not recent_snapshots:
269
+ return {}
270
+
271
+ # Analyze trends
272
+ performance_snapshots = [
273
+ s for s in recent_snapshots if s.metric_type == MetricType.PERFORMANCE
274
+ ]
275
+
276
+ if len(performance_snapshots) < 2:
277
+ return {'trend': 'insufficient_data'}
278
+
279
+ # Calculate trend
280
+ first_half = performance_snapshots[:len(performance_snapshots)//2]
281
+ second_half = performance_snapshots[len(performance_snapshots)//2:]
282
+
283
+ first_avg = sum(s.value for s in first_half) / len(first_half)
284
+ second_avg = sum(s.value for s in second_half) / len(second_half)
285
+
286
+ trend_direction = 'improving' if second_avg < first_avg else 'degrading'
287
+ trend_magnitude = abs(second_avg - first_avg) / first_avg if first_avg > 0 else 0
288
+
289
+ return {
290
+ 'trend': trend_direction,
291
+ 'magnitude': trend_magnitude,
292
+ 'first_half_avg': first_avg,
293
+ 'second_half_avg': second_avg,
294
+ 'data_points': len(performance_snapshots)
295
+ }
296
+
297
+ def _get_strategy_metrics_summary(self) -> Dict[str, Any]:
298
+ """Get summary of all strategy metrics."""
299
+ with self._lock:
300
+ if not self._strategy_metrics:
301
+ return {}
302
+
303
+ total_operations = sum(m.total_operations for m in self._strategy_metrics.values())
304
+ total_time = sum(m.total_time for m in self._strategy_metrics.values())
305
+ total_memory = sum(m.memory_usage for m in self._strategy_metrics.values())
306
+
307
+ return {
308
+ 'total_strategies': len(self._strategy_metrics),
309
+ 'total_operations': total_operations,
310
+ 'total_time': total_time,
311
+ 'total_memory': total_memory,
312
+ 'average_operation_time': total_time / max(total_operations, 1),
313
+ 'strategies': {
314
+ sid: {
315
+ 'name': metrics.strategy_name,
316
+ 'mode': metrics.mode.name,
317
+ 'operations': metrics.total_operations,
318
+ 'avg_time': metrics.average_time,
319
+ 'memory': metrics.memory_usage,
320
+ 'error_rate': metrics.error_rate,
321
+ 'last_updated': metrics.last_updated
322
+ }
323
+ for sid, metrics in self._strategy_metrics.items()
324
+ }
325
+ }
326
+
327
+ def _generate_optimization_recommendations(self) -> List[Dict[str, Any]]:
328
+ """Generate optimization recommendations based on metrics."""
329
+ recommendations = []
330
+
331
+ with self._lock:
332
+ for strategy_id, metrics in self._strategy_metrics.items():
333
+ # High error rate recommendation
334
+ if metrics.error_rate > 0.05: # 5%
335
+ recommendations.append({
336
+ 'strategy_id': strategy_id,
337
+ 'strategy_name': metrics.strategy_name,
338
+ 'type': 'high_error_rate',
339
+ 'severity': 'high',
340
+ 'description': f"High error rate: {metrics.error_rate:.1%}",
341
+ 'recommendation': "Consider switching to a more stable strategy"
342
+ })
343
+
344
+ # Slow performance recommendation
345
+ if metrics.average_time > 0.01: # 10ms
346
+ recommendations.append({
347
+ 'strategy_id': strategy_id,
348
+ 'strategy_name': metrics.strategy_name,
349
+ 'type': 'slow_performance',
350
+ 'severity': 'medium',
351
+ 'description': f"Slow average operation time: {metrics.average_time:.3f}s",
352
+ 'recommendation': "Consider optimizing or switching strategies"
353
+ })
354
+
355
+ # High memory usage recommendation
356
+ if metrics.memory_usage > 100 * 1024 * 1024: # 100MB
357
+ recommendations.append({
358
+ 'strategy_id': strategy_id,
359
+ 'strategy_name': metrics.strategy_name,
360
+ 'type': 'high_memory_usage',
361
+ 'severity': 'medium',
362
+ 'description': f"High memory usage: {metrics.memory_usage / 1024 / 1024:.1f}MB",
363
+ 'recommendation': "Consider memory-efficient strategy alternatives"
364
+ })
365
+
366
+ return recommendations
367
+
368
+ def _assess_system_health(self) -> Dict[str, Any]:
369
+ """Assess overall system health based on metrics."""
370
+ with self._lock:
371
+ if not self._strategy_metrics:
372
+ return {'status': 'unknown', 'score': 0.0}
373
+
374
+ # Calculate health score (0-100)
375
+ total_strategies = len(self._strategy_metrics)
376
+ high_error_strategies = sum(1 for m in self._strategy_metrics.values() if m.error_rate > 0.05)
377
+ slow_strategies = sum(1 for m in self._strategy_metrics.values() if m.average_time > 0.01)
378
+
379
+ error_penalty = (high_error_strategies / total_strategies) * 50
380
+ performance_penalty = (slow_strategies / total_strategies) * 30
381
+
382
+ health_score = max(0, 100 - error_penalty - performance_penalty)
383
+
384
+ # Determine status
385
+ if health_score >= 80:
386
+ status = 'excellent'
387
+ elif health_score >= 60:
388
+ status = 'good'
389
+ elif health_score >= 40:
390
+ status = 'fair'
391
+ else:
392
+ status = 'poor'
393
+
394
+ return {
395
+ 'status': status,
396
+ 'score': health_score,
397
+ 'total_strategies': total_strategies,
398
+ 'high_error_strategies': high_error_strategies,
399
+ 'slow_strategies': slow_strategies,
400
+ 'recommendations_count': len(self._generate_optimization_recommendations())
401
+ }
402
+
403
+ def export_metrics(self, format: str = 'json') -> Union[Dict[str, Any], str]:
404
+ """
405
+ Export metrics in specified format.
406
+
407
+ Args:
408
+ format: Export format ('json' or 'summary')
409
+
410
+ Returns:
411
+ Exported metrics
412
+ """
413
+ metrics = self.collect_comprehensive_metrics()
414
+
415
+ if format == 'summary':
416
+ return self._format_summary(metrics)
417
+ else:
418
+ return metrics
419
+
420
+ def _format_summary(self, metrics: Dict[str, Any]) -> str:
421
+ """Format metrics as a human-readable summary."""
422
+ global_metrics = metrics.get('global_metrics', {})
423
+ system_health = metrics.get('system_health', {})
424
+ recommendations = metrics.get('optimization_recommendations', [])
425
+
426
+ summary = f"""
427
+ ๐Ÿ“Š XWNode Strategy Metrics Summary
428
+ {'=' * 50}
429
+
430
+ ๐Ÿฅ System Health: {system_health.get('status', 'unknown').upper()} ({system_health.get('score', 0):.1f}/100)
431
+ ๐Ÿ“ˆ Total Strategies: {global_metrics.get('total_strategies', 0)}
432
+ โšก Total Operations: {global_metrics.get('total_operations', 0)}
433
+ ๐Ÿ’พ Memory Usage: {global_metrics.get('total_memory_usage', 0):.2f} MB
434
+ โฑ๏ธ Avg Operation Time: {global_metrics.get('average_performance', 0):.3f}s
435
+
436
+ ๐Ÿ”ง Optimization Recommendations: {len(recommendations)}
437
+ """
438
+
439
+ if recommendations:
440
+ summary += "\n๐Ÿ“‹ Top Recommendations:\n"
441
+ for i, rec in enumerate(recommendations[:3], 1):
442
+ summary += f" {i}. {rec['strategy_name']}: {rec['description']}\n"
443
+
444
+ return summary.strip()
445
+
446
+ def clear_metrics(self) -> None:
447
+ """Clear all collected metrics."""
448
+ with self._lock:
449
+ self._strategy_metrics.clear()
450
+ self._global_metrics = {
451
+ 'total_strategies': 0,
452
+ 'total_operations': 0,
453
+ 'total_memory_usage': 0.0,
454
+ 'average_performance': 0.0,
455
+ 'system_uptime': time.time(),
456
+ 'last_collection': time.time()
457
+ }
458
+ logger.info("๐Ÿงน Cleared all strategy metrics")
459
+
460
+
461
+ # Global metrics collector instance
462
+ _metrics_collector: Optional[StrategyMetricsCollector] = None
463
+ _metrics_lock = threading.Lock()
464
+
465
+
466
+ def get_metrics_collector() -> StrategyMetricsCollector:
467
+ """
468
+ Get the global metrics collector instance.
469
+
470
+ Returns:
471
+ Global StrategyMetricsCollector instance
472
+ """
473
+ global _metrics_collector
474
+
475
+ if _metrics_collector is None:
476
+ with _metrics_lock:
477
+ if _metrics_collector is None:
478
+ _metrics_collector = StrategyMetricsCollector()
479
+ logger.info("๐Ÿ“Š Initialized global strategy metrics collector")
480
+
481
+ return _metrics_collector
482
+
483
+
484
+ def collect_comprehensive_metrics() -> Dict[str, Any]:
485
+ """
486
+ Collect comprehensive metrics using the global collector.
487
+
488
+ Returns:
489
+ Complete metrics dictionary
490
+ """
491
+ return get_metrics_collector().collect_comprehensive_metrics()
492
+
493
+
494
+ def record_strategy_metric(
495
+ strategy_id: str,
496
+ strategy_name: str,
497
+ mode: Union[NodeMode, EdgeMode],
498
+ metric_type: MetricType,
499
+ value: float,
500
+ **metadata: Any
501
+ ) -> None:
502
+ """
503
+ Record a strategy metric using the global collector.
504
+
505
+ Args:
506
+ strategy_id: Strategy identifier
507
+ strategy_name: Strategy name
508
+ mode: Strategy mode
509
+ metric_type: Metric type
510
+ value: Metric value
511
+ **metadata: Additional metadata
512
+ """
513
+ get_metrics_collector().record_strategy_metric(
514
+ strategy_id, strategy_name, mode, metric_type, value, **metadata
515
+ )
516
+
517
+
518
+ def get_metrics_summary() -> str:
519
+ """
520
+ Get a formatted metrics summary.
521
+
522
+ Returns:
523
+ Human-readable metrics summary
524
+ """
525
+ return get_metrics_collector().export_metrics('summary')
526
+
527
+
528
+ def export_metrics(format: str = 'json') -> Union[Dict[str, Any], str]:
529
+ """
530
+ Export metrics in specified format.
531
+
532
+ Args:
533
+ format: Export format
534
+
535
+ Returns:
536
+ Exported metrics
537
+ """
538
+ return get_metrics_collector().export_metrics(format)