runbooks 1.1.3__py3-none-any.whl → 1.1.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 (247) hide show
  1. runbooks/__init__.py +31 -2
  2. runbooks/__init___optimized.py +18 -4
  3. runbooks/_platform/__init__.py +1 -5
  4. runbooks/_platform/core/runbooks_wrapper.py +141 -138
  5. runbooks/aws2/accuracy_validator.py +812 -0
  6. runbooks/base.py +7 -0
  7. runbooks/cfat/WEIGHT_CONFIG_README.md +1 -1
  8. runbooks/cfat/assessment/compliance.py +8 -8
  9. runbooks/cfat/assessment/runner.py +1 -0
  10. runbooks/cfat/cloud_foundations_assessment.py +227 -239
  11. runbooks/cfat/models.py +6 -2
  12. runbooks/cfat/tests/__init__.py +6 -1
  13. runbooks/cli/__init__.py +13 -0
  14. runbooks/cli/commands/cfat.py +274 -0
  15. runbooks/cli/commands/finops.py +1164 -0
  16. runbooks/cli/commands/inventory.py +379 -0
  17. runbooks/cli/commands/operate.py +239 -0
  18. runbooks/cli/commands/security.py +248 -0
  19. runbooks/cli/commands/validation.py +825 -0
  20. runbooks/cli/commands/vpc.py +310 -0
  21. runbooks/cli/registry.py +107 -0
  22. runbooks/cloudops/__init__.py +23 -30
  23. runbooks/cloudops/base.py +96 -107
  24. runbooks/cloudops/cost_optimizer.py +549 -547
  25. runbooks/cloudops/infrastructure_optimizer.py +5 -4
  26. runbooks/cloudops/interfaces.py +226 -227
  27. runbooks/cloudops/lifecycle_manager.py +5 -4
  28. runbooks/cloudops/mcp_cost_validation.py +252 -235
  29. runbooks/cloudops/models.py +78 -53
  30. runbooks/cloudops/monitoring_automation.py +5 -4
  31. runbooks/cloudops/notebook_framework.py +179 -215
  32. runbooks/cloudops/security_enforcer.py +125 -159
  33. runbooks/common/accuracy_validator.py +11 -0
  34. runbooks/common/aws_pricing.py +349 -326
  35. runbooks/common/aws_pricing_api.py +211 -212
  36. runbooks/common/aws_profile_manager.py +341 -0
  37. runbooks/common/aws_utils.py +75 -80
  38. runbooks/common/business_logic.py +127 -105
  39. runbooks/common/cli_decorators.py +36 -60
  40. runbooks/common/comprehensive_cost_explorer_integration.py +456 -464
  41. runbooks/common/cross_account_manager.py +198 -205
  42. runbooks/common/date_utils.py +27 -39
  43. runbooks/common/decorators.py +235 -0
  44. runbooks/common/dry_run_examples.py +173 -208
  45. runbooks/common/dry_run_framework.py +157 -155
  46. runbooks/common/enhanced_exception_handler.py +15 -4
  47. runbooks/common/enhanced_logging_example.py +50 -64
  48. runbooks/common/enhanced_logging_integration_example.py +65 -37
  49. runbooks/common/env_utils.py +16 -16
  50. runbooks/common/error_handling.py +40 -38
  51. runbooks/common/lazy_loader.py +41 -23
  52. runbooks/common/logging_integration_helper.py +79 -86
  53. runbooks/common/mcp_cost_explorer_integration.py +478 -495
  54. runbooks/common/mcp_integration.py +63 -74
  55. runbooks/common/memory_optimization.py +140 -118
  56. runbooks/common/module_cli_base.py +37 -58
  57. runbooks/common/organizations_client.py +176 -194
  58. runbooks/common/patterns.py +204 -0
  59. runbooks/common/performance_monitoring.py +67 -71
  60. runbooks/common/performance_optimization_engine.py +283 -274
  61. runbooks/common/profile_utils.py +248 -39
  62. runbooks/common/rich_utils.py +643 -92
  63. runbooks/common/sre_performance_suite.py +177 -186
  64. runbooks/enterprise/__init__.py +1 -1
  65. runbooks/enterprise/logging.py +144 -106
  66. runbooks/enterprise/security.py +187 -204
  67. runbooks/enterprise/validation.py +43 -56
  68. runbooks/finops/__init__.py +29 -33
  69. runbooks/finops/account_resolver.py +1 -1
  70. runbooks/finops/advanced_optimization_engine.py +980 -0
  71. runbooks/finops/automation_core.py +268 -231
  72. runbooks/finops/business_case_config.py +184 -179
  73. runbooks/finops/cli.py +660 -139
  74. runbooks/finops/commvault_ec2_analysis.py +157 -164
  75. runbooks/finops/compute_cost_optimizer.py +336 -320
  76. runbooks/finops/config.py +20 -20
  77. runbooks/finops/cost_optimizer.py +488 -622
  78. runbooks/finops/cost_processor.py +332 -214
  79. runbooks/finops/dashboard_runner.py +1006 -172
  80. runbooks/finops/ebs_cost_optimizer.py +991 -657
  81. runbooks/finops/elastic_ip_optimizer.py +317 -257
  82. runbooks/finops/enhanced_mcp_integration.py +340 -0
  83. runbooks/finops/enhanced_progress.py +40 -37
  84. runbooks/finops/enhanced_trend_visualization.py +3 -2
  85. runbooks/finops/enterprise_wrappers.py +230 -292
  86. runbooks/finops/executive_export.py +203 -160
  87. runbooks/finops/helpers.py +130 -288
  88. runbooks/finops/iam_guidance.py +1 -1
  89. runbooks/finops/infrastructure/__init__.py +80 -0
  90. runbooks/finops/infrastructure/commands.py +506 -0
  91. runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
  92. runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
  93. runbooks/finops/markdown_exporter.py +338 -175
  94. runbooks/finops/mcp_validator.py +1952 -0
  95. runbooks/finops/nat_gateway_optimizer.py +1513 -482
  96. runbooks/finops/network_cost_optimizer.py +657 -587
  97. runbooks/finops/notebook_utils.py +226 -188
  98. runbooks/finops/optimization_engine.py +1136 -0
  99. runbooks/finops/optimizer.py +25 -29
  100. runbooks/finops/rds_snapshot_optimizer.py +367 -411
  101. runbooks/finops/reservation_optimizer.py +427 -363
  102. runbooks/finops/scenario_cli_integration.py +77 -78
  103. runbooks/finops/scenarios.py +1278 -439
  104. runbooks/finops/schemas.py +218 -182
  105. runbooks/finops/snapshot_manager.py +2289 -0
  106. runbooks/finops/tests/test_finops_dashboard.py +3 -3
  107. runbooks/finops/tests/test_reference_images_validation.py +2 -2
  108. runbooks/finops/tests/test_single_account_features.py +17 -17
  109. runbooks/finops/tests/validate_test_suite.py +1 -1
  110. runbooks/finops/types.py +3 -3
  111. runbooks/finops/validation_framework.py +263 -269
  112. runbooks/finops/vpc_cleanup_exporter.py +191 -146
  113. runbooks/finops/vpc_cleanup_optimizer.py +593 -575
  114. runbooks/finops/workspaces_analyzer.py +171 -182
  115. runbooks/hitl/enhanced_workflow_engine.py +1 -1
  116. runbooks/integration/__init__.py +89 -0
  117. runbooks/integration/mcp_integration.py +1920 -0
  118. runbooks/inventory/CLAUDE.md +816 -0
  119. runbooks/inventory/README.md +3 -3
  120. runbooks/inventory/Tests/common_test_data.py +30 -30
  121. runbooks/inventory/__init__.py +2 -2
  122. runbooks/inventory/cloud_foundations_integration.py +144 -149
  123. runbooks/inventory/collectors/aws_comprehensive.py +28 -11
  124. runbooks/inventory/collectors/aws_networking.py +111 -101
  125. runbooks/inventory/collectors/base.py +4 -0
  126. runbooks/inventory/core/collector.py +495 -313
  127. runbooks/inventory/discovery.md +2 -2
  128. runbooks/inventory/drift_detection_cli.py +69 -96
  129. runbooks/inventory/find_ec2_security_groups.py +1 -1
  130. runbooks/inventory/inventory_mcp_cli.py +48 -46
  131. runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
  132. runbooks/inventory/mcp_inventory_validator.py +549 -465
  133. runbooks/inventory/mcp_vpc_validator.py +359 -442
  134. runbooks/inventory/organizations_discovery.py +56 -52
  135. runbooks/inventory/rich_inventory_display.py +33 -32
  136. runbooks/inventory/unified_validation_engine.py +278 -251
  137. runbooks/inventory/vpc_analyzer.py +733 -696
  138. runbooks/inventory/vpc_architecture_validator.py +293 -348
  139. runbooks/inventory/vpc_dependency_analyzer.py +382 -378
  140. runbooks/inventory/vpc_flow_analyzer.py +3 -3
  141. runbooks/main.py +152 -9147
  142. runbooks/main_final.py +91 -60
  143. runbooks/main_minimal.py +22 -10
  144. runbooks/main_optimized.py +131 -100
  145. runbooks/main_ultra_minimal.py +7 -2
  146. runbooks/mcp/__init__.py +36 -0
  147. runbooks/mcp/integration.py +679 -0
  148. runbooks/metrics/dora_metrics_engine.py +2 -2
  149. runbooks/monitoring/performance_monitor.py +9 -4
  150. runbooks/operate/dynamodb_operations.py +3 -1
  151. runbooks/operate/ec2_operations.py +145 -137
  152. runbooks/operate/iam_operations.py +146 -152
  153. runbooks/operate/mcp_integration.py +1 -1
  154. runbooks/operate/networking_cost_heatmap.py +33 -10
  155. runbooks/operate/privatelink_operations.py +1 -1
  156. runbooks/operate/rds_operations.py +223 -254
  157. runbooks/operate/s3_operations.py +107 -118
  158. runbooks/operate/vpc_endpoints.py +1 -1
  159. runbooks/operate/vpc_operations.py +648 -618
  160. runbooks/remediation/base.py +1 -1
  161. runbooks/remediation/commons.py +10 -7
  162. runbooks/remediation/commvault_ec2_analysis.py +71 -67
  163. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
  164. runbooks/remediation/multi_account.py +24 -21
  165. runbooks/remediation/rds_snapshot_list.py +91 -65
  166. runbooks/remediation/remediation_cli.py +92 -146
  167. runbooks/remediation/universal_account_discovery.py +83 -79
  168. runbooks/remediation/workspaces_list.py +49 -44
  169. runbooks/security/__init__.py +19 -0
  170. runbooks/security/assessment_runner.py +1150 -0
  171. runbooks/security/baseline_checker.py +812 -0
  172. runbooks/security/cloudops_automation_security_validator.py +509 -535
  173. runbooks/security/compliance_automation_engine.py +17 -17
  174. runbooks/security/config/__init__.py +2 -2
  175. runbooks/security/config/compliance_config.py +50 -50
  176. runbooks/security/config_template_generator.py +63 -76
  177. runbooks/security/enterprise_security_framework.py +1 -1
  178. runbooks/security/executive_security_dashboard.py +519 -508
  179. runbooks/security/integration_test_enterprise_security.py +5 -3
  180. runbooks/security/multi_account_security_controls.py +959 -1210
  181. runbooks/security/real_time_security_monitor.py +422 -444
  182. runbooks/security/run_script.py +1 -1
  183. runbooks/security/security_baseline_tester.py +1 -1
  184. runbooks/security/security_cli.py +143 -112
  185. runbooks/security/test_2way_validation.py +439 -0
  186. runbooks/security/two_way_validation_framework.py +852 -0
  187. runbooks/sre/mcp_reliability_engine.py +6 -6
  188. runbooks/sre/production_monitoring_framework.py +167 -177
  189. runbooks/tdd/__init__.py +15 -0
  190. runbooks/tdd/cli.py +1071 -0
  191. runbooks/utils/__init__.py +14 -17
  192. runbooks/utils/logger.py +7 -2
  193. runbooks/utils/version_validator.py +51 -48
  194. runbooks/validation/__init__.py +6 -6
  195. runbooks/validation/cli.py +9 -3
  196. runbooks/validation/comprehensive_2way_validator.py +754 -708
  197. runbooks/validation/mcp_validator.py +906 -228
  198. runbooks/validation/terraform_citations_validator.py +104 -115
  199. runbooks/validation/terraform_drift_detector.py +447 -451
  200. runbooks/vpc/README.md +617 -0
  201. runbooks/vpc/__init__.py +8 -1
  202. runbooks/vpc/analyzer.py +577 -0
  203. runbooks/vpc/cleanup_wrapper.py +476 -413
  204. runbooks/vpc/cli_cloudtrail_commands.py +339 -0
  205. runbooks/vpc/cli_mcp_validation_commands.py +480 -0
  206. runbooks/vpc/cloudtrail_audit_integration.py +717 -0
  207. runbooks/vpc/config.py +92 -97
  208. runbooks/vpc/cost_engine.py +411 -148
  209. runbooks/vpc/cost_explorer_integration.py +553 -0
  210. runbooks/vpc/cross_account_session.py +101 -106
  211. runbooks/vpc/enhanced_mcp_validation.py +917 -0
  212. runbooks/vpc/eni_gate_validator.py +961 -0
  213. runbooks/vpc/heatmap_engine.py +190 -162
  214. runbooks/vpc/mcp_no_eni_validator.py +681 -640
  215. runbooks/vpc/nat_gateway_optimizer.py +358 -0
  216. runbooks/vpc/networking_wrapper.py +15 -8
  217. runbooks/vpc/pdca_remediation_planner.py +528 -0
  218. runbooks/vpc/performance_optimized_analyzer.py +219 -231
  219. runbooks/vpc/runbooks_adapter.py +1167 -241
  220. runbooks/vpc/tdd_red_phase_stubs.py +601 -0
  221. runbooks/vpc/test_data_loader.py +358 -0
  222. runbooks/vpc/tests/conftest.py +314 -4
  223. runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
  224. runbooks/vpc/tests/test_cost_engine.py +0 -2
  225. runbooks/vpc/topology_generator.py +326 -0
  226. runbooks/vpc/unified_scenarios.py +1302 -1129
  227. runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
  228. runbooks-1.1.5.dist-info/METADATA +328 -0
  229. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/RECORD +233 -200
  230. runbooks/finops/README.md +0 -414
  231. runbooks/finops/accuracy_cross_validator.py +0 -647
  232. runbooks/finops/business_cases.py +0 -950
  233. runbooks/finops/dashboard_router.py +0 -922
  234. runbooks/finops/ebs_optimizer.py +0 -956
  235. runbooks/finops/embedded_mcp_validator.py +0 -1629
  236. runbooks/finops/enhanced_dashboard_runner.py +0 -527
  237. runbooks/finops/finops_dashboard.py +0 -584
  238. runbooks/finops/finops_scenarios.py +0 -1218
  239. runbooks/finops/legacy_migration.py +0 -730
  240. runbooks/finops/multi_dashboard.py +0 -1519
  241. runbooks/finops/single_dashboard.py +0 -1113
  242. runbooks/finops/unlimited_scenarios.py +0 -393
  243. runbooks-1.1.3.dist-info/METADATA +0 -799
  244. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/WHEEL +0 -0
  245. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
  246. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
  247. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/top_level.txt +0 -0
@@ -59,7 +59,7 @@ __all__ = [
59
59
  "configure_enterprise_logging",
60
60
  # Security
61
61
  "get_enhanced_logger",
62
- "assess_vpc_security_posture",
62
+ "assess_vpc_security_posture",
63
63
  "validate_compliance_requirements",
64
64
  "evaluate_security_baseline",
65
65
  "classify_security_risk",
@@ -17,36 +17,37 @@ from typing import Any, Dict, List, Optional, Union, Literal
17
17
 
18
18
  try:
19
19
  from loguru import logger as loguru_logger
20
+
20
21
  _HAS_LOGURU = True
21
22
  except ImportError:
22
23
  # Create a mock loguru-like object for compatibility
23
24
  import logging
24
-
25
+
25
26
  class MockLoguru:
26
27
  def __init__(self):
27
28
  self.logger = logging.getLogger(__name__)
28
-
29
+
29
30
  def remove(self, *args, **kwargs):
30
31
  pass # No-op for standard logging
31
-
32
+
32
33
  def add(self, *args, **kwargs):
33
34
  pass # No-op for standard logging
34
-
35
+
35
36
  def bind(self, **kwargs):
36
37
  return self # Return self for chaining
37
-
38
+
38
39
  def info(self, message, *args, **kwargs):
39
40
  self.logger.info(message, *args)
40
-
41
+
41
42
  def warning(self, message, *args, **kwargs):
42
43
  self.logger.warning(message, *args)
43
-
44
+
44
45
  def error(self, message, *args, **kwargs):
45
46
  self.logger.error(message, *args)
46
-
47
+
47
48
  def debug(self, message, *args, **kwargs):
48
49
  self.logger.debug(message, *args)
49
-
50
+
50
51
  loguru_logger = MockLoguru()
51
52
  _HAS_LOGURU = False
52
53
 
@@ -58,6 +59,7 @@ try:
58
59
  from rich.panel import Panel
59
60
  from rich.text import Text
60
61
  from rich import box
62
+
61
63
  _HAS_RICH = True
62
64
  except ImportError:
63
65
  _HAS_RICH = False
@@ -72,7 +74,7 @@ class EnterpriseRichLogger:
72
74
  def __init__(
73
75
  self,
74
76
  name: str = "runbooks",
75
- level: str = "INFO",
77
+ level: str = "INFO",
76
78
  log_dir: Optional[Path] = None,
77
79
  enable_console: bool = True,
78
80
  enable_file: bool = True,
@@ -100,17 +102,17 @@ class EnterpriseRichLogger:
100
102
  self.log_dir = log_dir or Path.home() / ".runbooks" / "logs"
101
103
  self.correlation_id = correlation_id or self._generate_correlation_id()
102
104
  self.json_output = json_output
103
-
105
+
104
106
  # Initialize Rich console for beautiful output
105
107
  self.console = rich_console or (Console() if _HAS_RICH else None)
106
-
108
+
107
109
  # User-type specific styling
108
110
  self.level_styles = {
109
111
  "DEBUG": {"style": "dim white", "icon": "🔧", "label": "TECH"},
110
112
  "INFO": {"style": "cyan", "icon": "ℹ️", "label": "INFO"},
111
113
  "WARNING": {"style": "yellow bold", "icon": "⚠️", "label": "BIZ"},
112
114
  "ERROR": {"style": "red bold", "icon": "❌", "label": "ALL"},
113
- "CRITICAL": {"style": "red bold reverse", "icon": "🚨", "label": "ALL"}
115
+ "CRITICAL": {"style": "red bold reverse", "icon": "🚨", "label": "ALL"},
114
116
  }
115
117
 
116
118
  # Ensure log directory exists
@@ -222,18 +224,20 @@ class EnterpriseRichLogger:
222
224
  """Determine if message should be logged based on current log level."""
223
225
  level_hierarchy = {"DEBUG": 0, "INFO": 1, "WARNING": 2, "ERROR": 3, "CRITICAL": 4}
224
226
  return level_hierarchy.get(level, 0) >= level_hierarchy.get(self.level, 1)
225
-
226
- def _rich_log(self, level: str, message: str, details: Optional[Dict[str, Any]] = None, progress: Optional[Progress] = None) -> None:
227
+
228
+ def _rich_log(
229
+ self, level: str, message: str, details: Optional[Dict[str, Any]] = None, progress: Optional[Progress] = None
230
+ ) -> None:
227
231
  """Enhanced logging with Rich CLI formatting and user-type specific content."""
228
232
  if not self._should_log(level):
229
233
  return
230
-
234
+
231
235
  # Get level-specific styling
232
236
  level_config = self.level_styles.get(level, self.level_styles["INFO"])
233
237
  icon = level_config["icon"]
234
238
  style = level_config["style"]
235
239
  label = level_config["label"]
236
-
240
+
237
241
  # Handle JSON output for programmatic use
238
242
  if self.json_output:
239
243
  log_entry = {
@@ -241,35 +245,39 @@ class EnterpriseRichLogger:
241
245
  "level": level,
242
246
  "correlation_id": self.correlation_id,
243
247
  "message": message,
244
- "details": details or {}
248
+ "details": details or {},
245
249
  }
246
250
  if self.console:
247
251
  self.console.print_json(data=log_entry)
248
252
  else:
249
253
  print(json.dumps(log_entry))
250
254
  return
251
-
255
+
252
256
  # Rich console output with user-type specific formatting
253
257
  if self.console and _HAS_RICH:
254
258
  timestamp = datetime.now().strftime("%H:%M:%S")
255
-
259
+
256
260
  # User-type specific message formatting
257
261
  if level == "DEBUG":
258
262
  # Tech users - Full details with timing and API info
259
263
  self.console.print(f"[dim]{timestamp}[/] {icon} [bold]{label}[/] {message}")
260
264
  if details and "aws_api" in details and details["aws_api"]:
261
265
  api_details = details["aws_api"]
262
- self.console.print(f" └─ [dim]API: {api_details.get('service', 'unknown')} / {api_details.get('operation', 'unknown')}[/]")
266
+ self.console.print(
267
+ f" └─ [dim]API: {api_details.get('service', 'unknown')} / {api_details.get('operation', 'unknown')}[/]"
268
+ )
263
269
  if details.get("request_id"):
264
270
  self.console.print(f" └─ [dim]Request ID: {details['request_id']}[/]")
265
271
  if details.get("duration"):
266
- duration_color = "green" if details["duration"] < 1.0 else "yellow" if details["duration"] < 5.0 else "red"
272
+ duration_color = (
273
+ "green" if details["duration"] < 1.0 else "yellow" if details["duration"] < 5.0 else "red"
274
+ )
267
275
  self.console.print(f" └─ [dim]Duration: [{duration_color}]{details['duration']:.3f}s[/dim][/]")
268
276
  if details.get("memory_usage"):
269
277
  memory_mb = details["memory_usage"] / 1024 / 1024
270
278
  memory_color = "green" if memory_mb < 50 else "yellow" if memory_mb < 200 else "red"
271
279
  self.console.print(f" └─ [dim]Memory: [{memory_color}]{memory_mb:.1f}MB[/dim][/]")
272
-
280
+
273
281
  elif level == "INFO":
274
282
  # Standard users - Clean status with progress bars
275
283
  if progress:
@@ -282,27 +290,37 @@ class EnterpriseRichLogger:
282
290
  status_color = "green" if details["operation_status"] == "completed" else "yellow"
283
291
  info_text += f" [{status_color}][{details['operation_status']}][/]"
284
292
  self.console.print(info_text)
285
-
293
+
286
294
  elif level == "WARNING":
287
295
  # Business users - Recommendations and alerts
288
296
  self.console.print(f"{icon} [bold]{label}[/] [{style}]{message}[/]")
289
297
  if details.get("recommendation"):
290
298
  self.console.print(f" 💡 [bright_cyan]Recommendation:[/] {details['recommendation']}")
291
299
  if details.get("cost_impact"):
292
- impact_color = "red" if details["cost_impact"] > 1000 else "yellow" if details["cost_impact"] > 100 else "green"
300
+ impact_color = (
301
+ "red"
302
+ if details["cost_impact"] > 1000
303
+ else "yellow"
304
+ if details["cost_impact"] > 100
305
+ else "green"
306
+ )
293
307
  self.console.print(f" 💰 [{impact_color}]Cost Impact:[/] ${details['cost_impact']:,.2f}/month")
294
308
  if details.get("savings_opportunity"):
295
- self.console.print(f" 💎 [bright_green]Savings Opportunity:[/] ${details['savings_opportunity']:,.2f}/month")
309
+ self.console.print(
310
+ f" 💎 [bright_green]Savings Opportunity:[/] ${details['savings_opportunity']:,.2f}/month"
311
+ )
296
312
  if details.get("business_impact"):
297
313
  self.console.print(f" 📊 [bright_blue]Business Impact:[/] {details['business_impact']}")
298
-
314
+
299
315
  elif level in ["ERROR", "CRITICAL"]:
300
316
  # All users - Clear errors with solutions
301
317
  self.console.print(f"{icon} [bold]{label}[/] [{style}]{message}[/]")
302
318
  if details.get("solution"):
303
319
  self.console.print(f" 🔧 [bright_blue]Solution:[/] {details['solution']}")
304
320
  if details.get("suggested_command"):
305
- self.console.print(f" ⚡ [bright_yellow]Try this command:[/] [cyan]{details['suggested_command']}[/]")
321
+ self.console.print(
322
+ f" ⚡ [bright_yellow]Try this command:[/] [cyan]{details['suggested_command']}[/]"
323
+ )
306
324
  if details.get("aws_error"):
307
325
  self.console.print(f" 📋 [dim]AWS Error:[/] {details['aws_error']}")
308
326
  if details.get("troubleshooting_steps"):
@@ -312,56 +330,79 @@ class EnterpriseRichLogger:
312
330
  else:
313
331
  # Fallback to standard logging
314
332
  print(f"[{level}] {message}")
315
-
333
+
316
334
  # Always log to file systems
317
335
  if _HAS_LOGURU:
318
336
  loguru_logger.bind(correlation_id=self.correlation_id, **(details or {})).info(f"[{level}] {message}")
319
337
  else:
320
338
  logging.getLogger(self.name).info(f"[{level}] {message}")
321
339
 
322
- def debug_tech(self, message: str, aws_api: Optional[Dict[str, str]] = None, duration: Optional[float] = None,
323
- memory_usage: Optional[int] = None, request_id: Optional[str] = None, **kwargs) -> None:
340
+ def debug_tech(
341
+ self,
342
+ message: str,
343
+ aws_api: Optional[Dict[str, str]] = None,
344
+ duration: Optional[float] = None,
345
+ memory_usage: Optional[int] = None,
346
+ request_id: Optional[str] = None,
347
+ **kwargs,
348
+ ) -> None:
324
349
  """Log debug message for tech users (SRE/DevOps) with full API details."""
325
350
  details = {
326
- "aws_api": aws_api or {},
327
- "duration": duration,
351
+ "aws_api": aws_api or {},
352
+ "duration": duration,
328
353
  "memory_usage": memory_usage,
329
354
  "request_id": request_id,
330
- **kwargs
355
+ **kwargs,
331
356
  }
332
357
  self._rich_log("DEBUG", message, details)
333
358
 
334
- def info_standard(self, message: str, progress: Optional[Progress] = None, resource_count: Optional[int] = None,
335
- operation_status: Optional[str] = None, **kwargs) -> None:
359
+ def info_standard(
360
+ self,
361
+ message: str,
362
+ progress: Optional[Progress] = None,
363
+ resource_count: Optional[int] = None,
364
+ operation_status: Optional[str] = None,
365
+ **kwargs,
366
+ ) -> None:
336
367
  """Log info message for standard users with progress indicators."""
337
- details = {
338
- "resource_count": resource_count,
339
- "operation_status": operation_status,
340
- **kwargs
341
- }
368
+ details = {"resource_count": resource_count, "operation_status": operation_status, **kwargs}
342
369
  self._rich_log("INFO", message, details, progress)
343
370
 
344
- def warning_business(self, message: str, recommendation: Optional[str] = None, cost_impact: Optional[float] = None,
345
- savings_opportunity: Optional[float] = None, business_impact: Optional[str] = None, **kwargs) -> None:
371
+ def warning_business(
372
+ self,
373
+ message: str,
374
+ recommendation: Optional[str] = None,
375
+ cost_impact: Optional[float] = None,
376
+ savings_opportunity: Optional[float] = None,
377
+ business_impact: Optional[str] = None,
378
+ **kwargs,
379
+ ) -> None:
346
380
  """Log warning message for business users with recommendations and cost impact."""
347
381
  details = {
348
- "recommendation": recommendation,
382
+ "recommendation": recommendation,
349
383
  "cost_impact": cost_impact,
350
384
  "savings_opportunity": savings_opportunity,
351
385
  "business_impact": business_impact,
352
- **kwargs
386
+ **kwargs,
353
387
  }
354
388
  self._rich_log("WARNING", message, details)
355
389
 
356
- def error_all(self, message: str, solution: Optional[str] = None, aws_error: Optional[str] = None,
357
- suggested_command: Optional[str] = None, troubleshooting_steps: Optional[List[str]] = None, **kwargs) -> None:
390
+ def error_all(
391
+ self,
392
+ message: str,
393
+ solution: Optional[str] = None,
394
+ aws_error: Optional[str] = None,
395
+ suggested_command: Optional[str] = None,
396
+ troubleshooting_steps: Optional[List[str]] = None,
397
+ **kwargs,
398
+ ) -> None:
358
399
  """Log error message for all users with clear solutions."""
359
400
  details = {
360
- "solution": solution,
401
+ "solution": solution,
361
402
  "aws_error": aws_error,
362
403
  "suggested_command": suggested_command,
363
404
  "troubleshooting_steps": troubleshooting_steps or [],
364
- **kwargs
405
+ **kwargs,
365
406
  }
366
407
  self._rich_log("ERROR", message, details)
367
408
 
@@ -387,80 +428,87 @@ class EnterpriseRichLogger:
387
428
  self._rich_log("CRITICAL", message, kwargs)
388
429
 
389
430
  # Convenience methods for common operations
390
- def log_aws_operation(self, operation: str, service: str, duration: Optional[float] = None,
391
- success: bool = True, resource_count: Optional[int] = None, **kwargs) -> None:
431
+ def log_aws_operation(
432
+ self,
433
+ operation: str,
434
+ service: str,
435
+ duration: Optional[float] = None,
436
+ success: bool = True,
437
+ resource_count: Optional[int] = None,
438
+ **kwargs,
439
+ ) -> None:
392
440
  """Log AWS operation with appropriate level based on success and duration."""
393
441
  if not success:
394
442
  self.error_all(
395
443
  f"AWS {service} {operation} failed",
396
444
  solution=f"Check AWS permissions for {service}:{operation}",
397
445
  aws_error=kwargs.get("error"),
398
- suggested_command=f"aws {service} {operation.replace('_', '-')} --help"
446
+ suggested_command=f"aws {service} {operation.replace('_', '-')} --help",
399
447
  )
400
448
  elif self.level == "DEBUG":
401
449
  self.debug_tech(
402
450
  f"AWS {service} {operation} completed",
403
451
  aws_api={"service": service, "operation": operation},
404
452
  duration=duration,
405
- **kwargs
453
+ **kwargs,
406
454
  )
407
455
  else:
408
456
  status = "completed" if success else "failed"
409
457
  self.info_standard(
410
458
  f"{service.upper()} {operation.replace('_', ' ')} {status}",
411
459
  resource_count=resource_count,
412
- operation_status=status
460
+ operation_status=status,
413
461
  )
414
462
 
415
- def log_cost_analysis(self, operation: str, cost_impact: Optional[float] = None,
416
- savings_opportunity: Optional[float] = None, recommendation: Optional[str] = None) -> None:
463
+ def log_cost_analysis(
464
+ self,
465
+ operation: str,
466
+ cost_impact: Optional[float] = None,
467
+ savings_opportunity: Optional[float] = None,
468
+ recommendation: Optional[str] = None,
469
+ ) -> None:
417
470
  """Log cost analysis with business-focused messaging."""
418
471
  if cost_impact and cost_impact > 100: # Significant cost impact
419
472
  self.warning_business(
420
473
  f"Cost analysis: {operation}",
421
474
  cost_impact=cost_impact,
422
475
  savings_opportunity=savings_opportunity,
423
- recommendation=recommendation or f"Review {operation} for optimization opportunities"
476
+ recommendation=recommendation or f"Review {operation} for optimization opportunities",
424
477
  )
425
478
  else:
426
479
  self.info_standard(f"Cost analysis completed: {operation}")
427
480
 
428
- def log_performance_metric(self, operation: str, duration: float, threshold: float = 5.0,
429
- memory_usage: Optional[int] = None) -> None:
481
+ def log_performance_metric(
482
+ self, operation: str, duration: float, threshold: float = 5.0, memory_usage: Optional[int] = None
483
+ ) -> None:
430
484
  """Log performance metrics with appropriate warnings."""
431
485
  if duration > threshold:
432
486
  self.warning_business(
433
487
  f"Performance alert: {operation} took {duration:.2f}s",
434
488
  recommendation=f"Consider optimizing {operation} - target: <{threshold}s",
435
- business_impact="May affect user experience during peak hours"
489
+ business_impact="May affect user experience during peak hours",
436
490
  )
437
491
  elif self.level == "DEBUG":
438
- self.debug_tech(
439
- f"Performance: {operation}",
440
- duration=duration,
441
- memory_usage=memory_usage
442
- )
492
+ self.debug_tech(f"Performance: {operation}", duration=duration, memory_usage=memory_usage)
443
493
  else:
444
494
  self.info_standard(f"{operation} completed", operation_status="completed")
445
495
 
446
- def log_security_finding(self, finding: str, severity: str = "medium",
447
- remediation_steps: Optional[List[str]] = None) -> None:
496
+ def log_security_finding(
497
+ self, finding: str, severity: str = "medium", remediation_steps: Optional[List[str]] = None
498
+ ) -> None:
448
499
  """Log security finding with appropriate level and remediation."""
449
500
  if severity.lower() in ["high", "critical"]:
450
501
  self.error_all(
451
502
  f"Security finding: {finding}",
452
503
  solution=f"Immediate action required for {severity} severity finding",
453
- troubleshooting_steps=remediation_steps or [
454
- "Review security policies",
455
- "Apply security patches",
456
- "Contact security team if needed"
457
- ]
504
+ troubleshooting_steps=remediation_steps
505
+ or ["Review security policies", "Apply security patches", "Contact security team if needed"],
458
506
  )
459
507
  elif severity.lower() == "medium":
460
508
  self.warning_business(
461
509
  f"Security alert: {finding}",
462
510
  recommendation="Schedule remediation within next maintenance window",
463
- business_impact="Potential security risk if not addressed"
511
+ business_impact="Potential security risk if not addressed",
464
512
  )
465
513
  else:
466
514
  self.info_standard(f"Security scan: {finding} ({severity} severity)")
@@ -469,13 +517,14 @@ class EnterpriseRichLogger:
469
517
  def operation_context(self, operation_name: str, **context_details):
470
518
  """Context manager for logging operation start/end with performance tracking."""
471
519
  import time
520
+
472
521
  start_time = time.time()
473
-
522
+
474
523
  if self.level == "DEBUG":
475
524
  self.debug_tech(f"Starting {operation_name}", **context_details)
476
525
  else:
477
526
  self.info_standard(f"Starting {operation_name}")
478
-
527
+
479
528
  success = True
480
529
  try:
481
530
  yield self
@@ -484,23 +533,16 @@ class EnterpriseRichLogger:
484
533
  self.error_all(
485
534
  f"Operation failed: {operation_name}",
486
535
  solution="Check logs above for detailed error information",
487
- aws_error=str(e)
536
+ aws_error=str(e),
488
537
  )
489
538
  raise
490
539
  finally:
491
540
  duration = time.time() - start_time
492
541
  if success:
493
542
  if self.level == "DEBUG":
494
- self.debug_tech(
495
- f"Completed {operation_name}",
496
- duration=duration,
497
- **context_details
498
- )
543
+ self.debug_tech(f"Completed {operation_name}", duration=duration, **context_details)
499
544
  else:
500
- self.info_standard(
501
- f"Completed {operation_name}",
502
- operation_status="completed"
503
- )
545
+ self.info_standard(f"Completed {operation_name}", operation_status="completed")
504
546
  else:
505
547
  self.error_all(f"Failed {operation_name} after {duration:.2f}s")
506
548
 
@@ -668,6 +710,7 @@ def configure_enterprise_logging(
668
710
  json_output=json_output,
669
711
  )
670
712
 
713
+
671
714
  # Backward compatibility alias
672
715
  EnterpriseLogger = EnterpriseRichLogger
673
716
 
@@ -761,44 +804,41 @@ def get_logger() -> EnterpriseRichLogger:
761
804
  def get_context_logger(level: str = "INFO", json_output: bool = False) -> EnterpriseRichLogger:
762
805
  """
763
806
  Get context-aware enterprise logger with Rich CLI integration.
764
-
807
+
765
808
  This is the recommended way to get a logger instance with proper
766
809
  Rich CLI integration and user-type specific formatting.
767
-
810
+
768
811
  Args:
769
812
  level: Log level (DEBUG, INFO, WARNING, ERROR)
770
813
  json_output: Enable structured JSON output
771
-
814
+
772
815
  Returns:
773
816
  Configured enterprise logger with Rich CLI support
774
817
  """
775
818
  try:
776
819
  from runbooks.common.rich_utils import get_context_aware_console
820
+
777
821
  rich_console = get_context_aware_console()
778
822
  except ImportError:
779
823
  rich_console = Console() if _HAS_RICH else None
780
-
781
- return configure_enterprise_logging(
782
- level=level,
783
- rich_console=rich_console,
784
- json_output=json_output
785
- )
824
+
825
+ return configure_enterprise_logging(level=level, rich_console=rich_console, json_output=json_output)
786
826
 
787
827
 
788
828
  def get_module_logger(module_name: str, level: str = "INFO", json_output: bool = False) -> EnterpriseRichLogger:
789
829
  """
790
830
  Get a module-specific enhanced logger with automatic correlation ID and module identification.
791
-
831
+
792
832
  This is the recommended method for modules to get their logger instance.
793
-
833
+
794
834
  Args:
795
835
  module_name: Name of the module (e.g., 'finops', 'inventory', 'security')
796
836
  level: Log level (DEBUG, INFO, WARNING, ERROR)
797
837
  json_output: Enable structured JSON output
798
-
838
+
799
839
  Returns:
800
840
  Configured enterprise logger with module-specific identification
801
-
841
+
802
842
  Example:
803
843
  >>> from runbooks.enterprise.logging import get_module_logger
804
844
  >>> logger = get_module_logger("finops", level="INFO")
@@ -807,23 +847,21 @@ def get_module_logger(module_name: str, level: str = "INFO", json_output: bool =
807
847
  """
808
848
  try:
809
849
  from runbooks.common.rich_utils import get_context_aware_console
850
+
810
851
  rich_console = get_context_aware_console()
811
852
  except ImportError:
812
853
  rich_console = Console() if _HAS_RICH else None
813
-
854
+
814
855
  logger = EnterpriseRichLogger(
815
- name=f"runbooks.{module_name}",
816
- level=level,
817
- rich_console=rich_console,
818
- json_output=json_output
856
+ name=f"runbooks.{module_name}", level=level, rich_console=rich_console, json_output=json_output
819
857
  )
820
-
858
+
821
859
  # Add module-specific initialization message
822
860
  if level == "DEBUG":
823
861
  logger.debug_tech(
824
862
  f"Module logger initialized for {module_name}",
825
863
  aws_api={"service": "logging", "operation": "module_init"},
826
- duration=0.001
864
+ duration=0.001,
827
865
  )
828
-
866
+
829
867
  return logger