runbooks 0.7.9__py3-none-any.whl → 0.9.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- runbooks/__init__.py +1 -1
- runbooks/cfat/README.md +12 -1
- runbooks/cfat/__init__.py +1 -1
- runbooks/cfat/assessment/compliance.py +4 -1
- runbooks/cfat/assessment/runner.py +42 -34
- runbooks/cfat/models.py +1 -1
- runbooks/cloudops/__init__.py +123 -0
- runbooks/cloudops/base.py +385 -0
- runbooks/cloudops/cost_optimizer.py +811 -0
- runbooks/cloudops/infrastructure_optimizer.py +29 -0
- runbooks/cloudops/interfaces.py +828 -0
- runbooks/cloudops/lifecycle_manager.py +29 -0
- runbooks/cloudops/mcp_cost_validation.py +678 -0
- runbooks/cloudops/models.py +251 -0
- runbooks/cloudops/monitoring_automation.py +29 -0
- runbooks/cloudops/notebook_framework.py +676 -0
- runbooks/cloudops/security_enforcer.py +449 -0
- runbooks/common/__init__.py +152 -0
- runbooks/common/accuracy_validator.py +1039 -0
- runbooks/common/context_logger.py +440 -0
- runbooks/common/cross_module_integration.py +594 -0
- runbooks/common/enhanced_exception_handler.py +1108 -0
- runbooks/common/enterprise_audit_integration.py +634 -0
- runbooks/common/mcp_cost_explorer_integration.py +900 -0
- runbooks/common/mcp_integration.py +548 -0
- runbooks/common/performance_monitor.py +387 -0
- runbooks/common/profile_utils.py +216 -0
- runbooks/common/rich_utils.py +172 -1
- runbooks/feedback/user_feedback_collector.py +440 -0
- runbooks/finops/README.md +377 -458
- runbooks/finops/__init__.py +4 -21
- runbooks/finops/account_resolver.py +279 -0
- runbooks/finops/accuracy_cross_validator.py +638 -0
- runbooks/finops/aws_client.py +721 -36
- runbooks/finops/budget_integration.py +313 -0
- runbooks/finops/cli.py +59 -5
- runbooks/finops/cost_optimizer.py +1340 -0
- runbooks/finops/cost_processor.py +211 -37
- runbooks/finops/dashboard_router.py +900 -0
- runbooks/finops/dashboard_runner.py +990 -232
- runbooks/finops/embedded_mcp_validator.py +288 -0
- runbooks/finops/enhanced_dashboard_runner.py +8 -7
- runbooks/finops/enhanced_progress.py +327 -0
- runbooks/finops/enhanced_trend_visualization.py +423 -0
- runbooks/finops/finops_dashboard.py +184 -1829
- runbooks/finops/helpers.py +509 -196
- runbooks/finops/iam_guidance.py +400 -0
- runbooks/finops/markdown_exporter.py +466 -0
- runbooks/finops/multi_dashboard.py +1502 -0
- runbooks/finops/optimizer.py +15 -15
- runbooks/finops/profile_processor.py +2 -2
- runbooks/finops/runbooks.inventory.organizations_discovery.log +0 -0
- runbooks/finops/runbooks.security.report_generator.log +0 -0
- runbooks/finops/runbooks.security.run_script.log +0 -0
- runbooks/finops/runbooks.security.security_export.log +0 -0
- runbooks/finops/schemas.py +589 -0
- runbooks/finops/service_mapping.py +195 -0
- runbooks/finops/single_dashboard.py +710 -0
- runbooks/finops/tests/test_reference_images_validation.py +1 -1
- runbooks/inventory/README.md +12 -1
- runbooks/inventory/core/collector.py +157 -29
- runbooks/inventory/list_ec2_instances.py +9 -6
- runbooks/inventory/list_ssm_parameters.py +10 -10
- runbooks/inventory/organizations_discovery.py +210 -164
- runbooks/inventory/rich_inventory_display.py +74 -107
- runbooks/inventory/run_on_multi_accounts.py +13 -13
- runbooks/inventory/runbooks.inventory.organizations_discovery.log +0 -0
- runbooks/inventory/runbooks.security.security_export.log +0 -0
- runbooks/main.py +1371 -240
- runbooks/metrics/dora_metrics_engine.py +711 -17
- runbooks/monitoring/performance_monitor.py +433 -0
- runbooks/operate/README.md +394 -0
- runbooks/operate/base.py +215 -47
- runbooks/operate/ec2_operations.py +435 -5
- runbooks/operate/iam_operations.py +598 -3
- runbooks/operate/privatelink_operations.py +1 -1
- runbooks/operate/rds_operations.py +508 -0
- runbooks/operate/s3_operations.py +508 -0
- runbooks/operate/vpc_endpoints.py +1 -1
- runbooks/remediation/README.md +489 -13
- runbooks/remediation/base.py +5 -3
- runbooks/remediation/commons.py +8 -4
- runbooks/security/ENTERPRISE_SECURITY_FRAMEWORK.md +506 -0
- runbooks/security/README.md +12 -1
- runbooks/security/__init__.py +265 -33
- runbooks/security/cloudops_automation_security_validator.py +1164 -0
- runbooks/security/compliance_automation.py +12 -10
- runbooks/security/compliance_automation_engine.py +1021 -0
- runbooks/security/enterprise_security_framework.py +930 -0
- runbooks/security/enterprise_security_policies.json +293 -0
- runbooks/security/executive_security_dashboard.py +1247 -0
- runbooks/security/integration_test_enterprise_security.py +879 -0
- runbooks/security/module_security_integrator.py +641 -0
- runbooks/security/multi_account_security_controls.py +2254 -0
- runbooks/security/real_time_security_monitor.py +1196 -0
- runbooks/security/report_generator.py +1 -1
- runbooks/security/run_script.py +4 -8
- runbooks/security/security_baseline_tester.py +39 -52
- runbooks/security/security_export.py +99 -120
- runbooks/sre/README.md +472 -0
- runbooks/sre/__init__.py +33 -0
- runbooks/sre/mcp_reliability_engine.py +1049 -0
- runbooks/sre/performance_optimization_engine.py +1032 -0
- runbooks/sre/production_monitoring_framework.py +584 -0
- runbooks/sre/reliability_monitoring_framework.py +1011 -0
- runbooks/validation/__init__.py +2 -2
- runbooks/validation/benchmark.py +154 -149
- runbooks/validation/cli.py +159 -147
- runbooks/validation/mcp_validator.py +291 -248
- runbooks/vpc/README.md +478 -0
- runbooks/vpc/__init__.py +2 -2
- runbooks/vpc/manager_interface.py +366 -351
- runbooks/vpc/networking_wrapper.py +68 -36
- runbooks/vpc/rich_formatters.py +22 -8
- runbooks-0.9.1.dist-info/METADATA +308 -0
- {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/RECORD +120 -59
- {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/entry_points.txt +1 -1
- runbooks/finops/cross_validation.py +0 -375
- runbooks-0.7.9.dist-info/METADATA +0 -636
- {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/WHEEL +0 -0
- {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/licenses/LICENSE +0 -0
- {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,440 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Context-Aware Logging System for CloudOps Runbooks
|
4
|
+
|
5
|
+
This module provides adaptive logging that detects execution context (CLI vs Jupyter)
|
6
|
+
and adjusts verbosity, formatting, and output style accordingly.
|
7
|
+
|
8
|
+
Features:
|
9
|
+
- Automatic CLI vs Jupyter environment detection
|
10
|
+
- Adaptive logging levels (technical for CLI, clean for Jupyter)
|
11
|
+
- Smart Rich console output based on context
|
12
|
+
- Performance metrics display optimization
|
13
|
+
- Context-aware error handling and stack traces
|
14
|
+
|
15
|
+
Usage:
|
16
|
+
from runbooks.common.context_logger import ContextLogger, get_context_console
|
17
|
+
|
18
|
+
logger = ContextLogger("finops.dashboard")
|
19
|
+
console = get_context_console()
|
20
|
+
|
21
|
+
logger.info("Starting analysis") # Detailed in CLI, simple in Jupyter
|
22
|
+
logger.technical_detail("AWS API call details") # Only shown in CLI
|
23
|
+
|
24
|
+
Author: CloudOps Runbooks Team
|
25
|
+
Version: 0.8.0
|
26
|
+
"""
|
27
|
+
|
28
|
+
import os
|
29
|
+
import sys
|
30
|
+
import time
|
31
|
+
from dataclasses import dataclass
|
32
|
+
from enum import Enum
|
33
|
+
from typing import Any, Dict, List, Optional, Union
|
34
|
+
|
35
|
+
from rich.console import Console
|
36
|
+
from rich.panel import Panel
|
37
|
+
from rich.progress import BarColumn, Progress, SpinnerColumn, TaskProgressColumn, TextColumn, TimeElapsedColumn
|
38
|
+
from rich.table import Table
|
39
|
+
from rich.text import Text
|
40
|
+
from rich.traceback import install as install_rich_traceback
|
41
|
+
|
42
|
+
from runbooks.common.rich_utils import (
|
43
|
+
CLOUDOPS_THEME,
|
44
|
+
STATUS_INDICATORS,
|
45
|
+
create_panel,
|
46
|
+
format_cost,
|
47
|
+
print_error,
|
48
|
+
print_info,
|
49
|
+
print_status,
|
50
|
+
print_success,
|
51
|
+
print_warning,
|
52
|
+
)
|
53
|
+
from runbooks.common.rich_utils import (
|
54
|
+
console as rich_console,
|
55
|
+
)
|
56
|
+
|
57
|
+
|
58
|
+
class ExecutionContext(Enum):
|
59
|
+
"""Execution context types."""
|
60
|
+
|
61
|
+
CLI = "cli"
|
62
|
+
JUPYTER = "jupyter"
|
63
|
+
UNKNOWN = "unknown"
|
64
|
+
|
65
|
+
|
66
|
+
@dataclass
|
67
|
+
class ContextConfig:
|
68
|
+
"""Configuration for context-aware logging."""
|
69
|
+
|
70
|
+
context: ExecutionContext
|
71
|
+
show_technical_details: bool
|
72
|
+
show_performance_metrics: bool
|
73
|
+
show_progress_bars: bool
|
74
|
+
show_full_stack_traces: bool
|
75
|
+
console_width: Optional[int] = None
|
76
|
+
|
77
|
+
|
78
|
+
class ContextDetector:
|
79
|
+
"""Detect execution environment context."""
|
80
|
+
|
81
|
+
@staticmethod
|
82
|
+
def detect_context() -> ExecutionContext:
|
83
|
+
"""
|
84
|
+
Detect if running in CLI vs Jupyter environment.
|
85
|
+
|
86
|
+
Returns:
|
87
|
+
ExecutionContext: Detected execution context
|
88
|
+
"""
|
89
|
+
# Check for IPython/Jupyter kernel
|
90
|
+
try:
|
91
|
+
# Check if we're in IPython/Jupyter
|
92
|
+
from IPython import get_ipython
|
93
|
+
|
94
|
+
ipython = get_ipython()
|
95
|
+
|
96
|
+
if ipython is not None:
|
97
|
+
# Check if it's a Jupyter kernel
|
98
|
+
if hasattr(ipython, "kernel"):
|
99
|
+
return ExecutionContext.JUPYTER
|
100
|
+
|
101
|
+
# Check for Jupyter-specific modules
|
102
|
+
if "zmq" in str(type(ipython)).lower():
|
103
|
+
return ExecutionContext.JUPYTER
|
104
|
+
|
105
|
+
# Check for notebook environment variables
|
106
|
+
if any(key in os.environ for key in ["JUPYTER_SERVER_ROOT", "JPY_SESSION_NAME", "KERNEL_ID"]):
|
107
|
+
return ExecutionContext.JUPYTER
|
108
|
+
|
109
|
+
except ImportError:
|
110
|
+
# IPython not available, definitely not Jupyter
|
111
|
+
pass
|
112
|
+
|
113
|
+
# Check for terminal environment
|
114
|
+
if hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
|
115
|
+
return ExecutionContext.CLI
|
116
|
+
|
117
|
+
# Check for common CLI indicators
|
118
|
+
if any(arg in sys.argv for arg in ["--help", "-h", "runbooks"]):
|
119
|
+
return ExecutionContext.CLI
|
120
|
+
|
121
|
+
# Default fallback
|
122
|
+
return ExecutionContext.UNKNOWN
|
123
|
+
|
124
|
+
@staticmethod
|
125
|
+
def get_context_config() -> ContextConfig:
|
126
|
+
"""
|
127
|
+
Get context configuration based on detected environment.
|
128
|
+
|
129
|
+
Returns:
|
130
|
+
ContextConfig: Configuration optimized for detected context
|
131
|
+
"""
|
132
|
+
context = ContextDetector.detect_context()
|
133
|
+
|
134
|
+
if context == ExecutionContext.CLI:
|
135
|
+
return ContextConfig(
|
136
|
+
context=context,
|
137
|
+
show_technical_details=True,
|
138
|
+
show_performance_metrics=True,
|
139
|
+
show_progress_bars=True,
|
140
|
+
show_full_stack_traces=True,
|
141
|
+
console_width=None, # Auto-detect
|
142
|
+
)
|
143
|
+
elif context == ExecutionContext.JUPYTER:
|
144
|
+
return ContextConfig(
|
145
|
+
context=context,
|
146
|
+
show_technical_details=False,
|
147
|
+
show_performance_metrics=False,
|
148
|
+
show_progress_bars=True, # Still useful in notebooks
|
149
|
+
show_full_stack_traces=False,
|
150
|
+
console_width=100, # Fixed width for notebook display
|
151
|
+
)
|
152
|
+
else:
|
153
|
+
# Conservative defaults for unknown context
|
154
|
+
return ContextConfig(
|
155
|
+
context=context,
|
156
|
+
show_technical_details=True,
|
157
|
+
show_performance_metrics=True,
|
158
|
+
show_progress_bars=True,
|
159
|
+
show_full_stack_traces=True,
|
160
|
+
console_width=None,
|
161
|
+
)
|
162
|
+
|
163
|
+
|
164
|
+
class ContextAwareConsole:
|
165
|
+
"""Console wrapper that adapts output based on execution context."""
|
166
|
+
|
167
|
+
def __init__(self, config: Optional[ContextConfig] = None):
|
168
|
+
"""
|
169
|
+
Initialize context-aware console.
|
170
|
+
|
171
|
+
Args:
|
172
|
+
config: Optional context configuration (auto-detected if None)
|
173
|
+
"""
|
174
|
+
self.config = config or ContextDetector.get_context_config()
|
175
|
+
|
176
|
+
# Create console with appropriate configuration
|
177
|
+
console_kwargs = {
|
178
|
+
"theme": CLOUDOPS_THEME,
|
179
|
+
"force_terminal": self.config.context == ExecutionContext.CLI,
|
180
|
+
}
|
181
|
+
|
182
|
+
if self.config.console_width:
|
183
|
+
console_kwargs["width"] = self.config.console_width
|
184
|
+
|
185
|
+
self.console = Console(**console_kwargs)
|
186
|
+
|
187
|
+
# Install rich tracebacks if configured
|
188
|
+
if self.config.show_full_stack_traces:
|
189
|
+
install_rich_traceback(show_locals=True, console=self.console)
|
190
|
+
|
191
|
+
def print(self, *args, **kwargs) -> None:
|
192
|
+
"""Print with context awareness."""
|
193
|
+
self.console.print(*args, **kwargs)
|
194
|
+
|
195
|
+
def log(self, *args, **kwargs) -> None:
|
196
|
+
"""Log with context awareness."""
|
197
|
+
if self.config.show_technical_details:
|
198
|
+
self.console.log(*args, **kwargs)
|
199
|
+
|
200
|
+
def print_technical_detail(self, message: str, style: str = "dim") -> None:
|
201
|
+
"""Print technical detail only in appropriate contexts."""
|
202
|
+
if self.config.show_technical_details:
|
203
|
+
self.console.print(f"🔧 {message}", style=style)
|
204
|
+
|
205
|
+
def print_performance_metric(self, metric_name: str, value: Union[str, float], unit: str = "") -> None:
|
206
|
+
"""Print performance metrics only in appropriate contexts."""
|
207
|
+
if self.config.show_performance_metrics:
|
208
|
+
if isinstance(value, float):
|
209
|
+
formatted_value = f"{value:.2f}{unit}"
|
210
|
+
else:
|
211
|
+
formatted_value = f"{value}{unit}"
|
212
|
+
self.console.print(f"⚡ {metric_name}: [highlight]{formatted_value}[/]", style="info")
|
213
|
+
|
214
|
+
def create_progress(self, description: str = "Processing") -> Progress:
|
215
|
+
"""Create progress bar appropriate for context."""
|
216
|
+
if self.config.show_progress_bars:
|
217
|
+
if self.config.context == ExecutionContext.JUPYTER:
|
218
|
+
# Simpler progress for Jupyter
|
219
|
+
return Progress(
|
220
|
+
TextColumn("[progress.description]{task.description}"),
|
221
|
+
BarColumn(bar_width=40),
|
222
|
+
TaskProgressColumn(),
|
223
|
+
console=self.console,
|
224
|
+
transient=False, # Don't hide in notebooks
|
225
|
+
)
|
226
|
+
else:
|
227
|
+
# Full progress for CLI
|
228
|
+
return Progress(
|
229
|
+
SpinnerColumn(spinner_name="dots", style="cyan"),
|
230
|
+
TextColumn("[progress.description]{task.description}"),
|
231
|
+
BarColumn(bar_width=40, style="cyan", complete_style="green"),
|
232
|
+
TaskProgressColumn(),
|
233
|
+
TimeElapsedColumn(),
|
234
|
+
console=self.console,
|
235
|
+
transient=True,
|
236
|
+
)
|
237
|
+
else:
|
238
|
+
# Minimal progress fallback
|
239
|
+
return Progress(
|
240
|
+
TextColumn("[progress.description]{task.description}"),
|
241
|
+
console=self.console,
|
242
|
+
)
|
243
|
+
|
244
|
+
|
245
|
+
class ContextLogger:
|
246
|
+
"""Context-aware logger for CloudOps operations."""
|
247
|
+
|
248
|
+
def __init__(self, name: str, console: Optional[ContextAwareConsole] = None):
|
249
|
+
"""
|
250
|
+
Initialize context logger.
|
251
|
+
|
252
|
+
Args:
|
253
|
+
name: Logger name (typically module.operation)
|
254
|
+
console: Optional context-aware console (auto-created if None)
|
255
|
+
"""
|
256
|
+
self.name = name
|
257
|
+
self.console = console or ContextAwareConsole()
|
258
|
+
self.start_time = time.time()
|
259
|
+
self._operation_start_times: Dict[str, float] = {}
|
260
|
+
|
261
|
+
def info(self, message: str, technical_detail: Optional[str] = None) -> None:
|
262
|
+
"""
|
263
|
+
Log info message with optional technical detail.
|
264
|
+
|
265
|
+
Args:
|
266
|
+
message: Main message (always shown)
|
267
|
+
technical_detail: Technical detail (CLI only)
|
268
|
+
"""
|
269
|
+
# Always show main message
|
270
|
+
print_info(message)
|
271
|
+
|
272
|
+
# Show technical detail only in appropriate context
|
273
|
+
if technical_detail and self.console.config.show_technical_details:
|
274
|
+
self.console.print_technical_detail(technical_detail)
|
275
|
+
|
276
|
+
def success(self, message: str, metrics: Optional[Dict[str, Any]] = None) -> None:
|
277
|
+
"""
|
278
|
+
Log success message with optional performance metrics.
|
279
|
+
|
280
|
+
Args:
|
281
|
+
message: Success message
|
282
|
+
metrics: Optional performance metrics (CLI only)
|
283
|
+
"""
|
284
|
+
print_success(message)
|
285
|
+
|
286
|
+
if metrics and self.console.config.show_performance_metrics:
|
287
|
+
for metric_name, metric_value in metrics.items():
|
288
|
+
if isinstance(metric_value, dict) and "value" in metric_value:
|
289
|
+
self.console.print_performance_metric(
|
290
|
+
metric_name, metric_value["value"], metric_value.get("unit", "")
|
291
|
+
)
|
292
|
+
else:
|
293
|
+
self.console.print_performance_metric(metric_name, metric_value)
|
294
|
+
|
295
|
+
def warning(self, message: str, technical_detail: Optional[str] = None) -> None:
|
296
|
+
"""
|
297
|
+
Log warning message with optional technical detail.
|
298
|
+
|
299
|
+
Args:
|
300
|
+
message: Warning message
|
301
|
+
technical_detail: Technical detail (CLI only)
|
302
|
+
"""
|
303
|
+
print_warning(message)
|
304
|
+
|
305
|
+
if technical_detail and self.console.config.show_technical_details:
|
306
|
+
self.console.print_technical_detail(f"Details: {technical_detail}", style="yellow")
|
307
|
+
|
308
|
+
def error(self, message: str, exception: Optional[Exception] = None, show_traceback: bool = True) -> None:
|
309
|
+
"""
|
310
|
+
Log error message with context-appropriate error handling.
|
311
|
+
|
312
|
+
Args:
|
313
|
+
message: Error message
|
314
|
+
exception: Optional exception object
|
315
|
+
show_traceback: Whether to show full traceback
|
316
|
+
"""
|
317
|
+
if exception:
|
318
|
+
if self.console.config.show_full_stack_traces and show_traceback:
|
319
|
+
# Full error details for CLI
|
320
|
+
print_error(message, exception)
|
321
|
+
self.console.console.print_exception(show_locals=True)
|
322
|
+
else:
|
323
|
+
# Simple error for Jupyter
|
324
|
+
error_detail = f"{type(exception).__name__}: {str(exception)}"
|
325
|
+
print_error(f"{message} - {error_detail}")
|
326
|
+
else:
|
327
|
+
print_error(message)
|
328
|
+
|
329
|
+
def start_operation(self, operation: str, description: Optional[str] = None) -> None:
|
330
|
+
"""
|
331
|
+
Start timing an operation.
|
332
|
+
|
333
|
+
Args:
|
334
|
+
operation: Operation name
|
335
|
+
description: Optional description
|
336
|
+
"""
|
337
|
+
self._operation_start_times[operation] = time.time()
|
338
|
+
|
339
|
+
if description:
|
340
|
+
display_msg = f"{description}"
|
341
|
+
else:
|
342
|
+
display_msg = f"Starting {operation}"
|
343
|
+
|
344
|
+
if self.console.config.show_technical_details:
|
345
|
+
self.console.print_technical_detail(f"Operation: {operation}")
|
346
|
+
|
347
|
+
self.info(display_msg)
|
348
|
+
|
349
|
+
def complete_operation(self, operation: str, result_summary: Optional[str] = None) -> float:
|
350
|
+
"""
|
351
|
+
Complete timing an operation and log results.
|
352
|
+
|
353
|
+
Args:
|
354
|
+
operation: Operation name
|
355
|
+
result_summary: Optional result summary
|
356
|
+
|
357
|
+
Returns:
|
358
|
+
Operation duration in seconds
|
359
|
+
"""
|
360
|
+
if operation not in self._operation_start_times:
|
361
|
+
self.warning(f"Operation '{operation}' was not started with start_operation()")
|
362
|
+
return 0.0
|
363
|
+
|
364
|
+
duration = time.time() - self._operation_start_times[operation]
|
365
|
+
del self._operation_start_times[operation]
|
366
|
+
|
367
|
+
# Build success message
|
368
|
+
success_msg = f"Completed {operation}"
|
369
|
+
if result_summary:
|
370
|
+
success_msg = f"{success_msg}: {result_summary}"
|
371
|
+
|
372
|
+
# Include metrics if configured
|
373
|
+
metrics = None
|
374
|
+
if self.console.config.show_performance_metrics:
|
375
|
+
metrics = {
|
376
|
+
"Duration": {"value": duration, "unit": "s"},
|
377
|
+
"Total Runtime": {"value": time.time() - self.start_time, "unit": "s"},
|
378
|
+
}
|
379
|
+
|
380
|
+
self.success(success_msg, metrics)
|
381
|
+
return duration
|
382
|
+
|
383
|
+
def create_progress_context(self, description: str = "Processing"):
|
384
|
+
"""
|
385
|
+
Create a progress context manager.
|
386
|
+
|
387
|
+
Args:
|
388
|
+
description: Progress description
|
389
|
+
|
390
|
+
Returns:
|
391
|
+
Progress context manager
|
392
|
+
"""
|
393
|
+
return self.console.create_progress(description)
|
394
|
+
|
395
|
+
|
396
|
+
# Global instances for easy access
|
397
|
+
_global_config: Optional[ContextConfig] = None
|
398
|
+
_global_console: Optional[ContextAwareConsole] = None
|
399
|
+
|
400
|
+
|
401
|
+
def get_context_config() -> ContextConfig:
|
402
|
+
"""Get global context configuration."""
|
403
|
+
global _global_config
|
404
|
+
if _global_config is None:
|
405
|
+
_global_config = ContextDetector.get_context_config()
|
406
|
+
return _global_config
|
407
|
+
|
408
|
+
|
409
|
+
def get_context_console() -> ContextAwareConsole:
|
410
|
+
"""Get global context-aware console."""
|
411
|
+
global _global_console
|
412
|
+
if _global_console is None:
|
413
|
+
_global_console = ContextAwareConsole(get_context_config())
|
414
|
+
return _global_console
|
415
|
+
|
416
|
+
|
417
|
+
def create_context_logger(name: str) -> ContextLogger:
|
418
|
+
"""
|
419
|
+
Create a context logger for a module.
|
420
|
+
|
421
|
+
Args:
|
422
|
+
name: Logger name (typically module.operation)
|
423
|
+
|
424
|
+
Returns:
|
425
|
+
ContextLogger instance
|
426
|
+
"""
|
427
|
+
return ContextLogger(name, get_context_console())
|
428
|
+
|
429
|
+
|
430
|
+
# Export public API
|
431
|
+
__all__ = [
|
432
|
+
"ExecutionContext",
|
433
|
+
"ContextConfig",
|
434
|
+
"ContextDetector",
|
435
|
+
"ContextAwareConsole",
|
436
|
+
"ContextLogger",
|
437
|
+
"get_context_config",
|
438
|
+
"get_context_console",
|
439
|
+
"create_context_logger",
|
440
|
+
]
|