kailash 0.8.4__py3-none-any.whl → 0.8.5__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 (79) hide show
  1. kailash/__init__.py +1 -7
  2. kailash/cli/__init__.py +11 -1
  3. kailash/cli/validation_audit.py +570 -0
  4. kailash/core/actors/supervisor.py +1 -1
  5. kailash/core/resilience/circuit_breaker.py +71 -1
  6. kailash/core/resilience/health_monitor.py +172 -0
  7. kailash/edge/compliance.py +33 -0
  8. kailash/edge/consistency.py +609 -0
  9. kailash/edge/coordination/__init__.py +30 -0
  10. kailash/edge/coordination/global_ordering.py +355 -0
  11. kailash/edge/coordination/leader_election.py +217 -0
  12. kailash/edge/coordination/partition_detector.py +296 -0
  13. kailash/edge/coordination/raft.py +485 -0
  14. kailash/edge/discovery.py +63 -1
  15. kailash/edge/migration/__init__.py +19 -0
  16. kailash/edge/migration/edge_migrator.py +832 -0
  17. kailash/edge/monitoring/__init__.py +21 -0
  18. kailash/edge/monitoring/edge_monitor.py +736 -0
  19. kailash/edge/prediction/__init__.py +10 -0
  20. kailash/edge/prediction/predictive_warmer.py +591 -0
  21. kailash/edge/resource/__init__.py +102 -0
  22. kailash/edge/resource/cloud_integration.py +796 -0
  23. kailash/edge/resource/cost_optimizer.py +949 -0
  24. kailash/edge/resource/docker_integration.py +919 -0
  25. kailash/edge/resource/kubernetes_integration.py +893 -0
  26. kailash/edge/resource/platform_integration.py +913 -0
  27. kailash/edge/resource/predictive_scaler.py +959 -0
  28. kailash/edge/resource/resource_analyzer.py +824 -0
  29. kailash/edge/resource/resource_pools.py +610 -0
  30. kailash/integrations/dataflow_edge.py +261 -0
  31. kailash/mcp_server/registry_integration.py +1 -1
  32. kailash/monitoring/__init__.py +18 -0
  33. kailash/monitoring/alerts.py +646 -0
  34. kailash/monitoring/metrics.py +677 -0
  35. kailash/nodes/__init__.py +2 -0
  36. kailash/nodes/ai/semantic_memory.py +2 -2
  37. kailash/nodes/base.py +545 -0
  38. kailash/nodes/edge/__init__.py +36 -0
  39. kailash/nodes/edge/base.py +240 -0
  40. kailash/nodes/edge/cloud_node.py +710 -0
  41. kailash/nodes/edge/coordination.py +239 -0
  42. kailash/nodes/edge/docker_node.py +825 -0
  43. kailash/nodes/edge/edge_data.py +582 -0
  44. kailash/nodes/edge/edge_migration_node.py +392 -0
  45. kailash/nodes/edge/edge_monitoring_node.py +421 -0
  46. kailash/nodes/edge/edge_state.py +673 -0
  47. kailash/nodes/edge/edge_warming_node.py +393 -0
  48. kailash/nodes/edge/kubernetes_node.py +652 -0
  49. kailash/nodes/edge/platform_node.py +766 -0
  50. kailash/nodes/edge/resource_analyzer_node.py +378 -0
  51. kailash/nodes/edge/resource_optimizer_node.py +501 -0
  52. kailash/nodes/edge/resource_scaler_node.py +397 -0
  53. kailash/nodes/ports.py +676 -0
  54. kailash/runtime/local.py +344 -1
  55. kailash/runtime/validation/__init__.py +20 -0
  56. kailash/runtime/validation/connection_context.py +119 -0
  57. kailash/runtime/validation/enhanced_error_formatter.py +202 -0
  58. kailash/runtime/validation/error_categorizer.py +164 -0
  59. kailash/runtime/validation/metrics.py +380 -0
  60. kailash/runtime/validation/performance.py +615 -0
  61. kailash/runtime/validation/suggestion_engine.py +212 -0
  62. kailash/testing/fixtures.py +2 -2
  63. kailash/workflow/builder.py +230 -4
  64. kailash/workflow/contracts.py +418 -0
  65. kailash/workflow/edge_infrastructure.py +369 -0
  66. kailash/workflow/migration.py +3 -3
  67. kailash/workflow/type_inference.py +669 -0
  68. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/METADATA +43 -27
  69. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/RECORD +73 -27
  70. kailash/nexus/__init__.py +0 -21
  71. kailash/nexus/cli/__init__.py +0 -5
  72. kailash/nexus/cli/__main__.py +0 -6
  73. kailash/nexus/cli/main.py +0 -176
  74. kailash/nexus/factory.py +0 -413
  75. kailash/nexus/gateway.py +0 -545
  76. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/WHEEL +0 -0
  77. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/entry_points.txt +0 -0
  78. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/licenses/LICENSE +0 -0
  79. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,380 @@
1
+ """
2
+ Performance monitoring and metrics collection for connection validation.
3
+
4
+ Tracks validation performance, security violations, and provides insights
5
+ into validation effectiveness and potential performance bottlenecks.
6
+ """
7
+
8
+ import logging
9
+ import time
10
+ from collections import defaultdict
11
+ from dataclasses import dataclass, field
12
+ from datetime import UTC, datetime
13
+ from enum import Enum
14
+ from typing import Any, Dict, List, Optional
15
+
16
+ from kailash.runtime.validation.error_categorizer import ErrorCategory
17
+
18
+
19
+ class ValidationEventType(Enum):
20
+ """Types of validation events to track."""
21
+
22
+ VALIDATION_STARTED = "validation_started"
23
+ VALIDATION_COMPLETED = "validation_completed"
24
+ VALIDATION_FAILED = "validation_failed"
25
+ SECURITY_VIOLATION = "security_violation"
26
+ CACHE_HIT = "cache_hit"
27
+ CACHE_MISS = "cache_miss"
28
+ TYPE_COERCION = "type_coercion"
29
+ MODE_BYPASS = "mode_bypass"
30
+
31
+
32
+ @dataclass
33
+ class ValidationMetric:
34
+ """Single validation metric entry."""
35
+
36
+ timestamp: datetime
37
+ event_type: ValidationEventType
38
+ node_id: str
39
+ node_type: str
40
+ duration_ms: Optional[float] = None
41
+ error_category: Optional[ErrorCategory] = None
42
+ validation_mode: Optional[str] = None
43
+ connection_source: Optional[str] = None
44
+ connection_target: Optional[str] = None
45
+ additional_data: Dict[str, Any] = field(default_factory=dict)
46
+
47
+
48
+ class ValidationMetricsCollector:
49
+ """Collects and aggregates validation performance metrics."""
50
+
51
+ def __init__(self, enable_detailed_logging: bool = False):
52
+ """Initialize metrics collector.
53
+
54
+ Args:
55
+ enable_detailed_logging: Whether to log detailed metrics to logger
56
+ """
57
+ self.metrics: List[ValidationMetric] = []
58
+ self.node_validation_times: Dict[str, List[float]] = defaultdict(list)
59
+ self.error_counts: Dict[ErrorCategory, int] = defaultdict(int)
60
+ self.security_violations: List[ValidationMetric] = []
61
+ self.enable_detailed_logging = enable_detailed_logging
62
+ self.logger = logging.getLogger("kailash.validation.metrics")
63
+
64
+ # Performance tracking
65
+ self._active_validations: Dict[str, float] = {}
66
+ self._cache_stats = {"hits": 0, "misses": 0}
67
+
68
+ def start_validation(
69
+ self, node_id: str, node_type: str, validation_mode: str
70
+ ) -> None:
71
+ """Record the start of a validation operation.
72
+
73
+ Args:
74
+ node_id: ID of the node being validated
75
+ node_type: Type of the node
76
+ validation_mode: Validation mode (off, warn, strict)
77
+ """
78
+ self._active_validations[node_id] = time.time()
79
+
80
+ metric = ValidationMetric(
81
+ timestamp=datetime.now(UTC),
82
+ event_type=ValidationEventType.VALIDATION_STARTED,
83
+ node_id=node_id,
84
+ node_type=node_type,
85
+ validation_mode=validation_mode,
86
+ )
87
+ self.metrics.append(metric)
88
+
89
+ if self.enable_detailed_logging:
90
+ self.logger.debug(
91
+ f"Validation started for {node_id} ({node_type}) in {validation_mode} mode"
92
+ )
93
+
94
+ def end_validation(
95
+ self,
96
+ node_id: str,
97
+ node_type: str,
98
+ success: bool,
99
+ error_category: Optional[ErrorCategory] = None,
100
+ connection_info: Optional[Dict[str, str]] = None,
101
+ ) -> None:
102
+ """Record the end of a validation operation.
103
+
104
+ Args:
105
+ node_id: ID of the node that was validated
106
+ node_type: Type of the node
107
+ success: Whether validation succeeded
108
+ error_category: Category of error if validation failed
109
+ connection_info: Optional connection source/target information
110
+ """
111
+ # Calculate duration
112
+ duration_ms = None
113
+ if node_id in self._active_validations:
114
+ start_time = self._active_validations.pop(node_id)
115
+ duration_ms = (time.time() - start_time) * 1000 # Convert to milliseconds
116
+ self.node_validation_times[node_type].append(duration_ms)
117
+
118
+ # Record appropriate event
119
+ event_type = (
120
+ ValidationEventType.VALIDATION_COMPLETED
121
+ if success
122
+ else ValidationEventType.VALIDATION_FAILED
123
+ )
124
+
125
+ metric = ValidationMetric(
126
+ timestamp=datetime.now(UTC),
127
+ event_type=event_type,
128
+ node_id=node_id,
129
+ node_type=node_type,
130
+ duration_ms=duration_ms,
131
+ error_category=error_category,
132
+ connection_source=(
133
+ connection_info.get("source") if connection_info else None
134
+ ),
135
+ connection_target=(
136
+ connection_info.get("target") if connection_info else None
137
+ ),
138
+ )
139
+ self.metrics.append(metric)
140
+
141
+ # Track error counts
142
+ if error_category:
143
+ self.error_counts[error_category] += 1
144
+
145
+ if self.enable_detailed_logging:
146
+ status = "succeeded" if success else "failed"
147
+ duration_str = f" in {duration_ms:.2f}ms" if duration_ms else ""
148
+ self.logger.debug(
149
+ f"Validation {status} for {node_id} ({node_type}){duration_str}"
150
+ )
151
+
152
+ def record_security_violation(
153
+ self,
154
+ node_id: str,
155
+ node_type: str,
156
+ violation_details: Dict[str, Any],
157
+ connection_info: Optional[Dict[str, str]] = None,
158
+ ) -> None:
159
+ """Record a security violation event.
160
+
161
+ Args:
162
+ node_id: ID of the node where violation occurred
163
+ node_type: Type of the node
164
+ violation_details: Details about the security violation
165
+ connection_info: Optional connection source/target information
166
+ """
167
+ metric = ValidationMetric(
168
+ timestamp=datetime.now(UTC),
169
+ event_type=ValidationEventType.SECURITY_VIOLATION,
170
+ node_id=node_id,
171
+ node_type=node_type,
172
+ error_category=ErrorCategory.SECURITY_VIOLATION,
173
+ connection_source=(
174
+ connection_info.get("source") if connection_info else None
175
+ ),
176
+ connection_target=(
177
+ connection_info.get("target") if connection_info else None
178
+ ),
179
+ additional_data=violation_details,
180
+ )
181
+
182
+ self.metrics.append(metric)
183
+ self.security_violations.append(metric)
184
+ self.error_counts[ErrorCategory.SECURITY_VIOLATION] += 1
185
+
186
+ # Always log security violations regardless of detailed logging setting
187
+ self.logger.warning(
188
+ f"SECURITY VIOLATION in {node_id} ({node_type}): {violation_details.get('message', 'Unknown')}"
189
+ )
190
+
191
+ def record_cache_hit(self, node_type: str) -> None:
192
+ """Record a validation cache hit."""
193
+ self._cache_stats["hits"] += 1
194
+
195
+ metric = ValidationMetric(
196
+ timestamp=datetime.now(UTC),
197
+ event_type=ValidationEventType.CACHE_HIT,
198
+ node_id="cache",
199
+ node_type=node_type,
200
+ )
201
+ self.metrics.append(metric)
202
+
203
+ def record_cache_miss(self, node_type: str) -> None:
204
+ """Record a validation cache miss."""
205
+ self._cache_stats["misses"] += 1
206
+
207
+ metric = ValidationMetric(
208
+ timestamp=datetime.now(UTC),
209
+ event_type=ValidationEventType.CACHE_MISS,
210
+ node_id="cache",
211
+ node_type=node_type,
212
+ )
213
+ self.metrics.append(metric)
214
+
215
+ def record_mode_bypass(self, node_id: str, node_type: str, mode: str) -> None:
216
+ """Record when validation is bypassed due to mode setting.
217
+
218
+ Args:
219
+ node_id: ID of the node
220
+ node_type: Type of the node
221
+ mode: Validation mode that caused bypass
222
+ """
223
+ metric = ValidationMetric(
224
+ timestamp=datetime.now(UTC),
225
+ event_type=ValidationEventType.MODE_BYPASS,
226
+ node_id=node_id,
227
+ node_type=node_type,
228
+ validation_mode=mode,
229
+ )
230
+ self.metrics.append(metric)
231
+
232
+ def get_performance_summary(self) -> Dict[str, Any]:
233
+ """Get a summary of validation performance metrics.
234
+
235
+ Returns:
236
+ Dictionary containing performance statistics
237
+ """
238
+ total_validations = sum(
239
+ 1
240
+ for m in self.metrics
241
+ if m.event_type
242
+ in [
243
+ ValidationEventType.VALIDATION_COMPLETED,
244
+ ValidationEventType.VALIDATION_FAILED,
245
+ ]
246
+ )
247
+
248
+ failed_validations = sum(
249
+ 1
250
+ for m in self.metrics
251
+ if m.event_type == ValidationEventType.VALIDATION_FAILED
252
+ )
253
+
254
+ # Calculate average validation times by node type
255
+ avg_times = {}
256
+ for node_type, times in self.node_validation_times.items():
257
+ if times:
258
+ avg_times[node_type] = {
259
+ "avg_ms": sum(times) / len(times),
260
+ "min_ms": min(times),
261
+ "max_ms": max(times),
262
+ "count": len(times),
263
+ }
264
+
265
+ # Cache effectiveness
266
+ total_cache_ops = self._cache_stats["hits"] + self._cache_stats["misses"]
267
+ cache_hit_rate = (
268
+ self._cache_stats["hits"] / total_cache_ops * 100
269
+ if total_cache_ops > 0
270
+ else 0
271
+ )
272
+
273
+ return {
274
+ "total_validations": total_validations,
275
+ "failed_validations": failed_validations,
276
+ "failure_rate": (
277
+ failed_validations / total_validations * 100
278
+ if total_validations > 0
279
+ else 0
280
+ ),
281
+ "security_violations": len(self.security_violations),
282
+ "error_breakdown": dict(self.error_counts),
283
+ "performance_by_node_type": avg_times,
284
+ "cache_stats": {
285
+ "hits": self._cache_stats["hits"],
286
+ "misses": self._cache_stats["misses"],
287
+ "hit_rate": cache_hit_rate,
288
+ },
289
+ "mode_bypasses": sum(
290
+ 1
291
+ for m in self.metrics
292
+ if m.event_type == ValidationEventType.MODE_BYPASS
293
+ ),
294
+ }
295
+
296
+ def get_security_report(self) -> Dict[str, Any]:
297
+ """Get a detailed security violations report.
298
+
299
+ Returns:
300
+ Dictionary containing security violation details
301
+ """
302
+ violations_by_node = defaultdict(list)
303
+ for violation in self.security_violations:
304
+ violations_by_node[violation.node_type].append(
305
+ {
306
+ "timestamp": violation.timestamp.isoformat(),
307
+ "node_id": violation.node_id,
308
+ "connection": f"{violation.connection_source} → {violation.connection_target}",
309
+ "details": violation.additional_data,
310
+ }
311
+ )
312
+
313
+ return {
314
+ "total_violations": len(self.security_violations),
315
+ "violations_by_node_type": dict(violations_by_node),
316
+ "most_recent_violations": [
317
+ {
318
+ "timestamp": v.timestamp.isoformat(),
319
+ "node": f"{v.node_id} ({v.node_type})",
320
+ "details": v.additional_data,
321
+ }
322
+ for v in sorted(
323
+ self.security_violations, key=lambda x: x.timestamp, reverse=True
324
+ )[:10]
325
+ ],
326
+ }
327
+
328
+ def reset_metrics(self) -> None:
329
+ """Reset all collected metrics."""
330
+ self.metrics.clear()
331
+ self.node_validation_times.clear()
332
+ self.error_counts.clear()
333
+ self.security_violations.clear()
334
+ self._cache_stats = {"hits": 0, "misses": 0}
335
+ self._active_validations.clear()
336
+
337
+ def export_metrics(self) -> List[Dict[str, Any]]:
338
+ """Export all metrics as a list of dictionaries.
339
+
340
+ Returns:
341
+ List of metric dictionaries for external processing
342
+ """
343
+ return [
344
+ {
345
+ "timestamp": m.timestamp.isoformat(),
346
+ "event_type": m.event_type.value,
347
+ "node_id": m.node_id,
348
+ "node_type": m.node_type,
349
+ "duration_ms": m.duration_ms,
350
+ "error_category": m.error_category.value if m.error_category else None,
351
+ "validation_mode": m.validation_mode,
352
+ "connection_source": m.connection_source,
353
+ "connection_target": m.connection_target,
354
+ "additional_data": m.additional_data,
355
+ }
356
+ for m in self.metrics
357
+ ]
358
+
359
+
360
+ # Global metrics collector instance
361
+ _global_metrics_collector = None
362
+
363
+
364
+ def get_metrics_collector() -> ValidationMetricsCollector:
365
+ """Get the global metrics collector instance.
366
+
367
+ Returns:
368
+ The global ValidationMetricsCollector instance
369
+ """
370
+ global _global_metrics_collector
371
+ if _global_metrics_collector is None:
372
+ _global_metrics_collector = ValidationMetricsCollector()
373
+ return _global_metrics_collector
374
+
375
+
376
+ def reset_global_metrics() -> None:
377
+ """Reset the global metrics collector."""
378
+ global _global_metrics_collector
379
+ if _global_metrics_collector:
380
+ _global_metrics_collector.reset_metrics()