claude-mpm 4.1.0__py3-none-any.whl → 4.1.2__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.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__main__.py +1 -1
- claude_mpm/agents/BASE_PM.md +74 -46
- claude_mpm/agents/INSTRUCTIONS.md +11 -153
- claude_mpm/agents/WORKFLOW.md +61 -321
- claude_mpm/agents/__init__.py +11 -11
- claude_mpm/agents/agent_loader.py +23 -20
- claude_mpm/agents/agent_loader_integration.py +1 -1
- claude_mpm/agents/agents_metadata.py +27 -0
- claude_mpm/agents/async_agent_loader.py +5 -8
- claude_mpm/agents/base_agent_loader.py +36 -25
- claude_mpm/agents/frontmatter_validator.py +6 -6
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +9 -9
- claude_mpm/agents/templates/api_qa.json +47 -2
- claude_mpm/agents/templates/imagemagick.json +256 -0
- claude_mpm/agents/templates/qa.json +41 -2
- claude_mpm/agents/templates/ticketing.json +5 -5
- claude_mpm/agents/templates/web_qa.json +133 -58
- claude_mpm/agents/templates/web_ui.json +3 -3
- claude_mpm/cli/__init__.py +51 -46
- claude_mpm/cli/__main__.py +1 -1
- claude_mpm/cli/commands/__init__.py +10 -12
- claude_mpm/cli/commands/agent_manager.py +186 -181
- claude_mpm/cli/commands/agents.py +271 -268
- claude_mpm/cli/commands/aggregate.py +30 -29
- claude_mpm/cli/commands/cleanup.py +50 -44
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
- claude_mpm/cli/commands/config.py +162 -127
- claude_mpm/cli/commands/doctor.py +52 -62
- claude_mpm/cli/commands/info.py +37 -25
- claude_mpm/cli/commands/mcp.py +3 -7
- claude_mpm/cli/commands/mcp_command_router.py +14 -18
- claude_mpm/cli/commands/mcp_install_commands.py +28 -23
- claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
- claude_mpm/cli/commands/mcp_server_commands.py +23 -17
- claude_mpm/cli/commands/memory.py +192 -141
- claude_mpm/cli/commands/monitor.py +117 -88
- claude_mpm/cli/commands/run.py +120 -84
- claude_mpm/cli/commands/run_config_checker.py +4 -5
- claude_mpm/cli/commands/socketio_monitor.py +17 -19
- claude_mpm/cli/commands/tickets.py +92 -92
- claude_mpm/cli/parser.py +1 -5
- claude_mpm/cli/parsers/__init__.py +1 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
- claude_mpm/cli/parsers/agents_parser.py +2 -3
- claude_mpm/cli/parsers/base_parser.py +7 -5
- claude_mpm/cli/parsers/mcp_parser.py +4 -2
- claude_mpm/cli/parsers/monitor_parser.py +26 -18
- claude_mpm/cli/shared/__init__.py +10 -10
- claude_mpm/cli/shared/argument_patterns.py +57 -71
- claude_mpm/cli/shared/base_command.py +61 -53
- claude_mpm/cli/shared/error_handling.py +62 -58
- claude_mpm/cli/shared/output_formatters.py +78 -77
- claude_mpm/cli/startup_logging.py +204 -172
- claude_mpm/cli/utils.py +10 -11
- claude_mpm/cli_module/__init__.py +1 -1
- claude_mpm/cli_module/args.py +1 -1
- claude_mpm/cli_module/migration_example.py +5 -5
- claude_mpm/config/__init__.py +9 -9
- claude_mpm/config/agent_config.py +15 -14
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/paths.py +0 -1
- claude_mpm/config/socketio_config.py +5 -6
- claude_mpm/constants.py +1 -2
- claude_mpm/core/__init__.py +8 -8
- claude_mpm/core/agent_name_normalizer.py +1 -1
- claude_mpm/core/agent_registry.py +20 -23
- claude_mpm/core/agent_session_manager.py +3 -3
- claude_mpm/core/base_service.py +7 -15
- claude_mpm/core/cache.py +4 -6
- claude_mpm/core/claude_runner.py +85 -113
- claude_mpm/core/config.py +43 -28
- claude_mpm/core/config_aliases.py +0 -9
- claude_mpm/core/config_constants.py +52 -30
- claude_mpm/core/constants.py +0 -1
- claude_mpm/core/container.py +18 -27
- claude_mpm/core/exceptions.py +2 -2
- claude_mpm/core/factories.py +10 -12
- claude_mpm/core/framework_loader.py +581 -280
- claude_mpm/core/hook_manager.py +26 -22
- claude_mpm/core/hook_performance_config.py +58 -47
- claude_mpm/core/injectable_service.py +1 -1
- claude_mpm/core/interactive_session.py +61 -152
- claude_mpm/core/interfaces.py +1 -100
- claude_mpm/core/lazy.py +5 -5
- claude_mpm/core/log_manager.py +587 -0
- claude_mpm/core/logger.py +125 -8
- claude_mpm/core/logging_config.py +15 -15
- claude_mpm/core/minimal_framework_loader.py +5 -8
- claude_mpm/core/oneshot_session.py +15 -33
- claude_mpm/core/optimized_agent_loader.py +4 -6
- claude_mpm/core/optimized_startup.py +2 -1
- claude_mpm/core/output_style_manager.py +147 -106
- claude_mpm/core/pm_hook_interceptor.py +0 -1
- claude_mpm/core/service_registry.py +11 -8
- claude_mpm/core/session_manager.py +1 -2
- claude_mpm/core/shared/__init__.py +1 -1
- claude_mpm/core/shared/config_loader.py +101 -97
- claude_mpm/core/shared/path_resolver.py +72 -68
- claude_mpm/core/shared/singleton_manager.py +56 -50
- claude_mpm/core/socketio_pool.py +26 -6
- claude_mpm/core/tool_access_control.py +4 -5
- claude_mpm/core/typing_utils.py +50 -59
- claude_mpm/core/unified_agent_registry.py +14 -19
- claude_mpm/core/unified_config.py +4 -6
- claude_mpm/core/unified_paths.py +197 -109
- claude_mpm/dashboard/open_dashboard.py +2 -4
- claude_mpm/experimental/cli_enhancements.py +51 -36
- claude_mpm/generators/agent_profile_generator.py +2 -4
- claude_mpm/hooks/base_hook.py +1 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
- claude_mpm/hooks/claude_hooks/event_handlers.py +93 -38
- claude_mpm/hooks/claude_hooks/hook_handler.py +130 -76
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
- claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
- claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
- claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
- claude_mpm/hooks/memory_integration_hook.py +5 -5
- claude_mpm/hooks/tool_call_interceptor.py +1 -1
- claude_mpm/hooks/validation_hooks.py +4 -4
- claude_mpm/init.py +4 -9
- claude_mpm/models/__init__.py +2 -2
- claude_mpm/models/agent_session.py +11 -14
- claude_mpm/scripts/mcp_server.py +20 -11
- claude_mpm/scripts/mcp_wrapper.py +5 -5
- claude_mpm/scripts/mpm_doctor.py +321 -0
- claude_mpm/scripts/socketio_daemon.py +28 -25
- claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
- claude_mpm/scripts/socketio_server_manager.py +116 -95
- claude_mpm/services/__init__.py +49 -49
- claude_mpm/services/agent_capabilities_service.py +12 -18
- claude_mpm/services/agents/__init__.py +22 -22
- claude_mpm/services/agents/agent_builder.py +140 -119
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
- claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
- claude_mpm/services/agents/deployment/agent_deployment.py +136 -106
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
- claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
- claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
- claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
- claude_mpm/services/agents/deployment/agent_validator.py +0 -1
- claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
- claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
- claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
- claude_mpm/services/agents/deployment/config/__init__.py +1 -1
- claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
- claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
- claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
- claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
- claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
- claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
- claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
- claude_mpm/services/agents/deployment/results/__init__.py +1 -1
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
- claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
- claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
- claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
- claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
- claude_mpm/services/agents/loading/__init__.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
- claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
- claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
- claude_mpm/services/agents/management/__init__.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
- claude_mpm/services/agents/management/agent_management_service.py +5 -9
- claude_mpm/services/agents/memory/__init__.py +4 -4
- claude_mpm/services/agents/memory/agent_memory_manager.py +280 -160
- claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
- claude_mpm/services/agents/memory/content_manager.py +44 -38
- claude_mpm/services/agents/memory/template_generator.py +4 -6
- claude_mpm/services/agents/registry/__init__.py +10 -6
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
- claude_mpm/services/agents/registry/modification_tracker.py +3 -6
- claude_mpm/services/async_session_logger.py +1 -2
- claude_mpm/services/claude_session_logger.py +1 -2
- claude_mpm/services/command_deployment_service.py +173 -0
- claude_mpm/services/command_handler_service.py +20 -22
- claude_mpm/services/core/__init__.py +25 -25
- claude_mpm/services/core/base.py +0 -5
- claude_mpm/services/core/interfaces/__init__.py +32 -32
- claude_mpm/services/core/interfaces/agent.py +0 -21
- claude_mpm/services/core/interfaces/communication.py +0 -27
- claude_mpm/services/core/interfaces/infrastructure.py +0 -56
- claude_mpm/services/core/interfaces/service.py +0 -29
- claude_mpm/services/diagnostics/__init__.py +1 -1
- claude_mpm/services/diagnostics/checks/__init__.py +6 -6
- claude_mpm/services/diagnostics/checks/agent_check.py +89 -80
- claude_mpm/services/diagnostics/checks/base_check.py +12 -16
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
- claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
- claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
- claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
- claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
- claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
- claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
- claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
- claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
- claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
- claude_mpm/services/diagnostics/models.py +21 -19
- claude_mpm/services/event_aggregator.py +10 -17
- claude_mpm/services/event_bus/__init__.py +1 -1
- claude_mpm/services/event_bus/config.py +54 -35
- claude_mpm/services/event_bus/event_bus.py +76 -71
- claude_mpm/services/event_bus/relay.py +74 -64
- claude_mpm/services/events/__init__.py +11 -11
- claude_mpm/services/events/consumers/__init__.py +3 -3
- claude_mpm/services/events/consumers/dead_letter.py +71 -63
- claude_mpm/services/events/consumers/logging.py +39 -37
- claude_mpm/services/events/consumers/metrics.py +56 -57
- claude_mpm/services/events/consumers/socketio.py +82 -81
- claude_mpm/services/events/core.py +110 -99
- claude_mpm/services/events/interfaces.py +56 -72
- claude_mpm/services/events/producers/__init__.py +1 -1
- claude_mpm/services/events/producers/hook.py +38 -38
- claude_mpm/services/events/producers/system.py +46 -44
- claude_mpm/services/exceptions.py +81 -80
- claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
- claude_mpm/services/hook_service.py +6 -9
- claude_mpm/services/infrastructure/__init__.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +8 -12
- claude_mpm/services/infrastructure/monitoring.py +21 -23
- claude_mpm/services/mcp_gateway/__init__.py +37 -37
- claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
- claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
- claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
- claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
- claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
- claude_mpm/services/mcp_gateway/core/base.py +0 -3
- claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
- claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
- claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
- claude_mpm/services/mcp_gateway/main.py +2 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
- claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
- claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
- claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
- claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
- claude_mpm/services/memory/__init__.py +3 -3
- claude_mpm/services/memory/builder.py +3 -6
- claude_mpm/services/memory/cache/__init__.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/memory/indexed_memory.py +5 -7
- claude_mpm/services/memory/optimizer.py +7 -10
- claude_mpm/services/memory/router.py +8 -9
- claude_mpm/services/memory_hook_service.py +48 -34
- claude_mpm/services/monitor_build_service.py +77 -73
- claude_mpm/services/port_manager.py +130 -108
- claude_mpm/services/project/analyzer.py +12 -10
- claude_mpm/services/project/registry.py +11 -11
- claude_mpm/services/recovery_manager.py +10 -19
- claude_mpm/services/response_tracker.py +0 -1
- claude_mpm/services/runner_configuration_service.py +19 -20
- claude_mpm/services/session_management_service.py +7 -11
- claude_mpm/services/shared/__init__.py +1 -1
- claude_mpm/services/shared/async_service_base.py +58 -50
- claude_mpm/services/shared/config_service_base.py +73 -67
- claude_mpm/services/shared/lifecycle_service_base.py +82 -78
- claude_mpm/services/shared/manager_base.py +94 -82
- claude_mpm/services/shared/service_factory.py +96 -98
- claude_mpm/services/socketio/__init__.py +3 -3
- claude_mpm/services/socketio/client_proxy.py +5 -5
- claude_mpm/services/socketio/event_normalizer.py +199 -181
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +5 -4
- claude_mpm/services/socketio/handlers/connection.py +163 -136
- claude_mpm/services/socketio/handlers/file.py +13 -14
- claude_mpm/services/socketio/handlers/git.py +12 -7
- claude_mpm/services/socketio/handlers/hook.py +49 -44
- claude_mpm/services/socketio/handlers/memory.py +0 -1
- claude_mpm/services/socketio/handlers/project.py +0 -1
- claude_mpm/services/socketio/handlers/registry.py +37 -19
- claude_mpm/services/socketio/migration_utils.py +98 -84
- claude_mpm/services/socketio/server/__init__.py +1 -1
- claude_mpm/services/socketio/server/broadcaster.py +81 -87
- claude_mpm/services/socketio/server/core.py +65 -54
- claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
- claude_mpm/services/socketio/server/main.py +64 -38
- claude_mpm/services/socketio_client_manager.py +10 -12
- claude_mpm/services/subprocess_launcher_service.py +4 -7
- claude_mpm/services/system_instructions_service.py +13 -14
- claude_mpm/services/ticket_manager.py +2 -2
- claude_mpm/services/utility_service.py +5 -13
- claude_mpm/services/version_control/__init__.py +16 -16
- claude_mpm/services/version_control/branch_strategy.py +5 -8
- claude_mpm/services/version_control/conflict_resolution.py +9 -23
- claude_mpm/services/version_control/git_operations.py +5 -7
- claude_mpm/services/version_control/semantic_versioning.py +16 -17
- claude_mpm/services/version_control/version_parser.py +13 -18
- claude_mpm/services/version_service.py +10 -11
- claude_mpm/storage/__init__.py +1 -1
- claude_mpm/storage/state_storage.py +22 -28
- claude_mpm/utils/__init__.py +6 -6
- claude_mpm/utils/agent_dependency_loader.py +47 -33
- claude_mpm/utils/config_manager.py +11 -14
- claude_mpm/utils/dependency_cache.py +1 -1
- claude_mpm/utils/dependency_manager.py +13 -17
- claude_mpm/utils/dependency_strategies.py +8 -10
- claude_mpm/utils/environment_context.py +3 -9
- claude_mpm/utils/error_handler.py +3 -13
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/path_operations.py +8 -12
- claude_mpm/utils/robust_installer.py +110 -33
- claude_mpm/utils/subprocess_utils.py +5 -6
- claude_mpm/validation/agent_validator.py +3 -6
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/METADATA +1 -1
- claude_mpm-4.1.2.dist-info/RECORD +498 -0
- claude_mpm-4.1.0.dist-info/RECORD +0 -494
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,6 @@ Handles events that failed processing in other consumers.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
|
-
import os
|
|
10
9
|
from datetime import datetime
|
|
11
10
|
from pathlib import Path
|
|
12
11
|
from typing import Any, Dict, List, Optional
|
|
@@ -20,24 +19,24 @@ from ..interfaces import ConsumerConfig, ConsumerPriority, IEventConsumer
|
|
|
20
19
|
class DeadLetterConsumer(IEventConsumer):
|
|
21
20
|
"""
|
|
22
21
|
Handles failed events by persisting them for later analysis.
|
|
23
|
-
|
|
22
|
+
|
|
24
23
|
Features:
|
|
25
24
|
- Persist failed events to disk
|
|
26
25
|
- Configurable retention policy
|
|
27
26
|
- Event replay capability
|
|
28
27
|
- Failed event analysis
|
|
29
28
|
"""
|
|
30
|
-
|
|
29
|
+
|
|
31
30
|
def __init__(
|
|
32
31
|
self,
|
|
33
32
|
output_dir: Optional[Path] = None,
|
|
34
33
|
max_file_size: int = 10 * 1024 * 1024, # 10MB
|
|
35
34
|
retention_days: int = 7,
|
|
36
|
-
topics: List[str] = None,
|
|
35
|
+
topics: Optional[List[str]] = None,
|
|
37
36
|
):
|
|
38
37
|
"""
|
|
39
38
|
Initialize dead letter consumer.
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
Args:
|
|
42
41
|
output_dir: Directory to store failed events
|
|
43
42
|
max_file_size: Maximum size per file (bytes)
|
|
@@ -45,17 +44,17 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
45
44
|
topics: Topics to handle (None = all failed events)
|
|
46
45
|
"""
|
|
47
46
|
self.logger = get_logger("DeadLetterConsumer")
|
|
48
|
-
|
|
47
|
+
|
|
49
48
|
# Configuration
|
|
50
49
|
self.output_dir = output_dir or Path.home() / ".claude-mpm" / "dead-letter"
|
|
51
50
|
self.max_file_size = max_file_size
|
|
52
51
|
self.retention_days = retention_days
|
|
53
|
-
|
|
52
|
+
|
|
54
53
|
# State
|
|
55
54
|
self._initialized = False
|
|
56
55
|
self._current_file: Optional[Path] = None
|
|
57
56
|
self._current_file_size = 0
|
|
58
|
-
|
|
57
|
+
|
|
59
58
|
# Metrics
|
|
60
59
|
self._metrics = {
|
|
61
60
|
"events_stored": 0,
|
|
@@ -63,7 +62,7 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
63
62
|
"files_created": 0,
|
|
64
63
|
"total_size_bytes": 0,
|
|
65
64
|
}
|
|
66
|
-
|
|
65
|
+
|
|
67
66
|
# Consumer configuration
|
|
68
67
|
self._config = ConsumerConfig(
|
|
69
68
|
name="DeadLetterConsumer",
|
|
@@ -71,62 +70,64 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
71
70
|
priority=ConsumerPriority.CRITICAL, # Process failed events first
|
|
72
71
|
filter_func=self._should_store,
|
|
73
72
|
)
|
|
74
|
-
|
|
73
|
+
|
|
75
74
|
async def initialize(self) -> bool:
|
|
76
75
|
"""Initialize the dead letter consumer."""
|
|
77
76
|
try:
|
|
78
77
|
# Create output directory
|
|
79
78
|
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
80
|
-
|
|
79
|
+
|
|
81
80
|
# Clean old files
|
|
82
81
|
await self._cleanup_old_files()
|
|
83
|
-
|
|
82
|
+
|
|
84
83
|
# Initialize current file
|
|
85
84
|
self._rotate_file()
|
|
86
|
-
|
|
85
|
+
|
|
87
86
|
self._initialized = True
|
|
88
|
-
self.logger.info(
|
|
87
|
+
self.logger.info(
|
|
88
|
+
f"Dead letter consumer initialized (output: {self.output_dir})"
|
|
89
|
+
)
|
|
89
90
|
return True
|
|
90
|
-
|
|
91
|
+
|
|
91
92
|
except Exception as e:
|
|
92
93
|
self.logger.error(f"Failed to initialize dead letter consumer: {e}")
|
|
93
94
|
return False
|
|
94
|
-
|
|
95
|
+
|
|
95
96
|
async def consume(self, event: Event) -> bool:
|
|
96
97
|
"""Store a failed event."""
|
|
97
98
|
if not self._initialized:
|
|
98
99
|
return False
|
|
99
|
-
|
|
100
|
+
|
|
100
101
|
try:
|
|
101
102
|
# Serialize event
|
|
102
103
|
event_data = self._serialize_event(event)
|
|
103
104
|
event_json = json.dumps(event_data) + "\n"
|
|
104
105
|
event_bytes = event_json.encode("utf-8")
|
|
105
|
-
|
|
106
|
+
|
|
106
107
|
# Check if rotation needed
|
|
107
108
|
if self._current_file_size + len(event_bytes) > self.max_file_size:
|
|
108
109
|
self._rotate_file()
|
|
109
|
-
|
|
110
|
+
|
|
110
111
|
# Write to file
|
|
111
112
|
with open(self._current_file, "a") as f:
|
|
112
113
|
f.write(event_json)
|
|
113
|
-
|
|
114
|
+
|
|
114
115
|
# Update metrics
|
|
115
116
|
self._current_file_size += len(event_bytes)
|
|
116
117
|
self._metrics["events_stored"] += 1
|
|
117
118
|
self._metrics["total_size_bytes"] += len(event_bytes)
|
|
118
|
-
|
|
119
|
+
|
|
119
120
|
self.logger.debug(
|
|
120
121
|
f"Stored failed event: {event.topic}/{event.type} "
|
|
121
122
|
f"(reason: {event.metadata.error_messages if event.metadata else 'unknown'})"
|
|
122
123
|
)
|
|
123
|
-
|
|
124
|
+
|
|
124
125
|
return True
|
|
125
|
-
|
|
126
|
+
|
|
126
127
|
except Exception as e:
|
|
127
128
|
self.logger.error(f"Error storing failed event: {e}")
|
|
128
129
|
return False
|
|
129
|
-
|
|
130
|
+
|
|
130
131
|
async def consume_batch(self, events: List[Event]) -> int:
|
|
131
132
|
"""Store multiple failed events."""
|
|
132
133
|
successful = 0
|
|
@@ -134,14 +135,14 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
134
135
|
if await self.consume(event):
|
|
135
136
|
successful += 1
|
|
136
137
|
return successful
|
|
137
|
-
|
|
138
|
+
|
|
138
139
|
async def shutdown(self) -> None:
|
|
139
140
|
"""Shutdown the consumer."""
|
|
140
141
|
self.logger.info(
|
|
141
142
|
f"Dead letter consumer shutdown - stored {self._metrics['events_stored']} events"
|
|
142
143
|
)
|
|
143
144
|
self._initialized = False
|
|
144
|
-
|
|
145
|
+
|
|
145
146
|
async def replay_events(
|
|
146
147
|
self,
|
|
147
148
|
start_time: Optional[datetime] = None,
|
|
@@ -150,56 +151,58 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
150
151
|
) -> List[Event]:
|
|
151
152
|
"""
|
|
152
153
|
Replay stored events for reprocessing.
|
|
153
|
-
|
|
154
|
+
|
|
154
155
|
Args:
|
|
155
156
|
start_time: Start of time range
|
|
156
157
|
end_time: End of time range
|
|
157
158
|
topic_filter: Topic pattern to filter
|
|
158
|
-
|
|
159
|
+
|
|
159
160
|
Returns:
|
|
160
161
|
List of events matching criteria
|
|
161
162
|
"""
|
|
162
163
|
replayed_events = []
|
|
163
|
-
|
|
164
|
+
|
|
164
165
|
# Find files in time range
|
|
165
166
|
for file_path in sorted(self.output_dir.glob("dead-letter-*.jsonl")):
|
|
166
167
|
try:
|
|
167
|
-
with open(file_path
|
|
168
|
+
with open(file_path) as f:
|
|
168
169
|
for line in f:
|
|
169
170
|
event_data = json.loads(line)
|
|
170
|
-
|
|
171
|
+
|
|
171
172
|
# Apply filters
|
|
172
173
|
event_time = datetime.fromisoformat(event_data["timestamp"])
|
|
173
|
-
|
|
174
|
+
|
|
174
175
|
if start_time and event_time < start_time:
|
|
175
176
|
continue
|
|
176
177
|
if end_time and event_time > end_time:
|
|
177
178
|
continue
|
|
178
|
-
if topic_filter and not event_data["topic"].startswith(
|
|
179
|
+
if topic_filter and not event_data["topic"].startswith(
|
|
180
|
+
topic_filter
|
|
181
|
+
):
|
|
179
182
|
continue
|
|
180
|
-
|
|
183
|
+
|
|
181
184
|
# Reconstruct event
|
|
182
185
|
event = self._deserialize_event(event_data)
|
|
183
186
|
replayed_events.append(event)
|
|
184
|
-
|
|
187
|
+
|
|
185
188
|
except Exception as e:
|
|
186
189
|
self.logger.error(f"Error replaying events from {file_path}: {e}")
|
|
187
|
-
|
|
190
|
+
|
|
188
191
|
self._metrics["events_replayed"] += len(replayed_events)
|
|
189
192
|
self.logger.info(f"Replayed {len(replayed_events)} events")
|
|
190
|
-
|
|
193
|
+
|
|
191
194
|
return replayed_events
|
|
192
|
-
|
|
195
|
+
|
|
193
196
|
@property
|
|
194
197
|
def config(self) -> ConsumerConfig:
|
|
195
198
|
"""Get consumer configuration."""
|
|
196
199
|
return self._config
|
|
197
|
-
|
|
200
|
+
|
|
198
201
|
@property
|
|
199
202
|
def is_healthy(self) -> bool:
|
|
200
203
|
"""Check if consumer is healthy."""
|
|
201
204
|
return self._initialized and self._current_file is not None
|
|
202
|
-
|
|
205
|
+
|
|
203
206
|
def get_metrics(self) -> Dict[str, Any]:
|
|
204
207
|
"""Get consumer metrics."""
|
|
205
208
|
return {
|
|
@@ -207,30 +210,27 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
207
210
|
"current_file": str(self._current_file) if self._current_file else None,
|
|
208
211
|
"current_file_size": self._current_file_size,
|
|
209
212
|
}
|
|
210
|
-
|
|
213
|
+
|
|
211
214
|
def _should_store(self, event: Event) -> bool:
|
|
212
215
|
"""
|
|
213
216
|
Determine if an event should be stored.
|
|
214
|
-
|
|
217
|
+
|
|
215
218
|
Only store events that have actually failed processing.
|
|
216
219
|
"""
|
|
217
220
|
if not event.metadata:
|
|
218
221
|
return False
|
|
219
|
-
|
|
222
|
+
|
|
220
223
|
# Store if any consumers failed
|
|
221
224
|
if event.metadata.consumers_failed:
|
|
222
225
|
return True
|
|
223
|
-
|
|
226
|
+
|
|
224
227
|
# Store if max retries exceeded
|
|
225
228
|
if event.metadata.retry_count >= event.metadata.max_retries:
|
|
226
229
|
return True
|
|
227
|
-
|
|
230
|
+
|
|
228
231
|
# Store if event has error messages
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
return False
|
|
233
|
-
|
|
232
|
+
return bool(event.metadata.error_messages)
|
|
233
|
+
|
|
234
234
|
def _serialize_event(self, event: Event) -> Dict[str, Any]:
|
|
235
235
|
"""Serialize an event for storage."""
|
|
236
236
|
return {
|
|
@@ -242,17 +242,25 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
242
242
|
"data": event.data,
|
|
243
243
|
"correlation_id": event.correlation_id,
|
|
244
244
|
"priority": event.priority.name,
|
|
245
|
-
"metadata":
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
245
|
+
"metadata": (
|
|
246
|
+
{
|
|
247
|
+
"retry_count": event.metadata.retry_count if event.metadata else 0,
|
|
248
|
+
"consumers_failed": (
|
|
249
|
+
list(event.metadata.consumers_failed) if event.metadata else []
|
|
250
|
+
),
|
|
251
|
+
"error_messages": (
|
|
252
|
+
event.metadata.error_messages if event.metadata else []
|
|
253
|
+
),
|
|
254
|
+
}
|
|
255
|
+
if event.metadata
|
|
256
|
+
else None
|
|
257
|
+
),
|
|
250
258
|
}
|
|
251
|
-
|
|
259
|
+
|
|
252
260
|
def _deserialize_event(self, data: Dict[str, Any]) -> Event:
|
|
253
261
|
"""Deserialize an event from storage."""
|
|
254
262
|
from ..core import EventMetadata, EventPriority
|
|
255
|
-
|
|
263
|
+
|
|
256
264
|
# Reconstruct metadata
|
|
257
265
|
metadata = None
|
|
258
266
|
if data.get("metadata"):
|
|
@@ -261,7 +269,7 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
261
269
|
consumers_failed=set(data["metadata"].get("consumers_failed", [])),
|
|
262
270
|
error_messages=data["metadata"].get("error_messages", []),
|
|
263
271
|
)
|
|
264
|
-
|
|
272
|
+
|
|
265
273
|
return Event(
|
|
266
274
|
id=data["id"],
|
|
267
275
|
topic=data["topic"],
|
|
@@ -273,24 +281,24 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
273
281
|
correlation_id=data.get("correlation_id"),
|
|
274
282
|
priority=EventPriority[data.get("priority", "NORMAL")],
|
|
275
283
|
)
|
|
276
|
-
|
|
284
|
+
|
|
277
285
|
def _rotate_file(self) -> None:
|
|
278
286
|
"""Rotate to a new output file."""
|
|
279
287
|
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
|
280
288
|
self._current_file = self.output_dir / f"dead-letter-{timestamp}.jsonl"
|
|
281
289
|
self._current_file_size = 0
|
|
282
290
|
self._metrics["files_created"] += 1
|
|
283
|
-
|
|
291
|
+
|
|
284
292
|
self.logger.debug(f"Rotated to new file: {self._current_file}")
|
|
285
|
-
|
|
293
|
+
|
|
286
294
|
async def _cleanup_old_files(self) -> None:
|
|
287
295
|
"""Remove files older than retention period."""
|
|
288
296
|
cutoff_time = datetime.now().timestamp() - (self.retention_days * 86400)
|
|
289
|
-
|
|
297
|
+
|
|
290
298
|
for file_path in self.output_dir.glob("dead-letter-*.jsonl"):
|
|
291
299
|
try:
|
|
292
300
|
if file_path.stat().st_mtime < cutoff_time:
|
|
293
301
|
file_path.unlink()
|
|
294
302
|
self.logger.info(f"Removed old dead letter file: {file_path}")
|
|
295
303
|
except Exception as e:
|
|
296
|
-
self.logger.error(f"Error removing old file {file_path}: {e}")
|
|
304
|
+
self.logger.error(f"Error removing old file {file_path}: {e}")
|
|
@@ -6,7 +6,7 @@ Logs events for debugging and monitoring purposes.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
|
-
from typing import Any, Dict, List
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
10
|
|
|
11
11
|
from claude_mpm.core.logging_config import get_logger
|
|
12
12
|
|
|
@@ -17,25 +17,25 @@ from ..interfaces import ConsumerConfig, ConsumerPriority, IEventConsumer
|
|
|
17
17
|
class LoggingConsumer(IEventConsumer):
|
|
18
18
|
"""
|
|
19
19
|
Logs events for debugging and monitoring.
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
Features:
|
|
22
22
|
- Configurable log levels per topic
|
|
23
23
|
- Structured logging with JSON support
|
|
24
24
|
- Event filtering
|
|
25
25
|
- Performance metrics
|
|
26
26
|
"""
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
def __init__(
|
|
29
29
|
self,
|
|
30
30
|
log_level: str = "INFO",
|
|
31
|
-
topics: List[str] = None,
|
|
31
|
+
topics: Optional[List[str]] = None,
|
|
32
32
|
format_json: bool = True,
|
|
33
33
|
include_data: bool = True,
|
|
34
34
|
max_data_length: int = 1000,
|
|
35
35
|
):
|
|
36
36
|
"""
|
|
37
37
|
Initialize logging consumer.
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
Args:
|
|
40
40
|
log_level: Default log level (DEBUG, INFO, WARNING, ERROR)
|
|
41
41
|
topics: Topics to log (None = all)
|
|
@@ -44,30 +44,30 @@ class LoggingConsumer(IEventConsumer):
|
|
|
44
44
|
max_data_length: Maximum data length to log
|
|
45
45
|
"""
|
|
46
46
|
self.logger = get_logger("EventLogger")
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
# Configuration
|
|
49
49
|
self.log_level = log_level
|
|
50
50
|
self.format_json = format_json
|
|
51
51
|
self.include_data = include_data
|
|
52
52
|
self.max_data_length = max_data_length
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
# State
|
|
55
55
|
self._initialized = False
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
# Metrics
|
|
58
58
|
self._metrics = {
|
|
59
59
|
"events_logged": 0,
|
|
60
60
|
"events_filtered": 0,
|
|
61
61
|
"errors": 0,
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
# Consumer configuration
|
|
65
65
|
self._config = ConsumerConfig(
|
|
66
66
|
name="LoggingConsumer",
|
|
67
67
|
topics=topics or ["**"],
|
|
68
68
|
priority=ConsumerPriority.LOW, # Log after other processing
|
|
69
69
|
)
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
async def initialize(self) -> bool:
|
|
72
72
|
"""Initialize the logging consumer."""
|
|
73
73
|
self._initialized = True
|
|
@@ -76,30 +76,30 @@ class LoggingConsumer(IEventConsumer):
|
|
|
76
76
|
f"topics={self._config.topics})"
|
|
77
77
|
)
|
|
78
78
|
return True
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
async def consume(self, event: Event) -> bool:
|
|
81
81
|
"""Log a single event."""
|
|
82
82
|
if not self._initialized:
|
|
83
83
|
return False
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
try:
|
|
86
86
|
# Format log message
|
|
87
87
|
message = self._format_event(event)
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
# Determine log level
|
|
90
90
|
level = self._get_log_level(event)
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
# Log the event
|
|
93
93
|
getattr(self.logger, level.lower())(message)
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
self._metrics["events_logged"] += 1
|
|
96
96
|
return True
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
except Exception as e:
|
|
99
99
|
self.logger.error(f"Error logging event: {e}")
|
|
100
100
|
self._metrics["errors"] += 1
|
|
101
101
|
return False
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
async def consume_batch(self, events: List[Event]) -> int:
|
|
104
104
|
"""Log multiple events."""
|
|
105
105
|
successful = 0
|
|
@@ -107,26 +107,28 @@ class LoggingConsumer(IEventConsumer):
|
|
|
107
107
|
if await self.consume(event):
|
|
108
108
|
successful += 1
|
|
109
109
|
return successful
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
async def shutdown(self) -> None:
|
|
112
112
|
"""Shutdown the consumer."""
|
|
113
|
-
self.logger.info(
|
|
113
|
+
self.logger.info(
|
|
114
|
+
f"Shutting down logging consumer (logged {self._metrics['events_logged']} events)"
|
|
115
|
+
)
|
|
114
116
|
self._initialized = False
|
|
115
|
-
|
|
117
|
+
|
|
116
118
|
@property
|
|
117
119
|
def config(self) -> ConsumerConfig:
|
|
118
120
|
"""Get consumer configuration."""
|
|
119
121
|
return self._config
|
|
120
|
-
|
|
122
|
+
|
|
121
123
|
@property
|
|
122
124
|
def is_healthy(self) -> bool:
|
|
123
125
|
"""Check if consumer is healthy."""
|
|
124
126
|
return self._initialized
|
|
125
|
-
|
|
127
|
+
|
|
126
128
|
def get_metrics(self) -> Dict[str, Any]:
|
|
127
129
|
"""Get consumer metrics."""
|
|
128
130
|
return self._metrics
|
|
129
|
-
|
|
131
|
+
|
|
130
132
|
def _format_event(self, event: Event) -> str:
|
|
131
133
|
"""Format an event for logging."""
|
|
132
134
|
# Build base message
|
|
@@ -134,20 +136,20 @@ class LoggingConsumer(IEventConsumer):
|
|
|
134
136
|
f"[{event.topic}] {event.type} "
|
|
135
137
|
f"(id={event.id[:8]}, source={event.source})"
|
|
136
138
|
)
|
|
137
|
-
|
|
139
|
+
|
|
138
140
|
# Add data if configured
|
|
139
141
|
if self.include_data and event.data:
|
|
140
142
|
if self.format_json:
|
|
141
143
|
data_str = json.dumps(event.data, indent=2)
|
|
142
144
|
else:
|
|
143
145
|
data_str = str(event.data)
|
|
144
|
-
|
|
146
|
+
|
|
145
147
|
# Truncate if too long
|
|
146
148
|
if len(data_str) > self.max_data_length:
|
|
147
|
-
data_str = data_str[:self.max_data_length] + "..."
|
|
148
|
-
|
|
149
|
+
data_str = data_str[: self.max_data_length] + "..."
|
|
150
|
+
|
|
149
151
|
message += f"\n{data_str}"
|
|
150
|
-
|
|
152
|
+
|
|
151
153
|
# Add metadata if present
|
|
152
154
|
if event.metadata:
|
|
153
155
|
meta_info = []
|
|
@@ -155,29 +157,29 @@ class LoggingConsumer(IEventConsumer):
|
|
|
155
157
|
meta_info.append(f"retries={event.metadata.retry_count}")
|
|
156
158
|
if event.metadata.consumers_failed:
|
|
157
159
|
meta_info.append(f"failed={event.metadata.consumers_failed}")
|
|
158
|
-
|
|
160
|
+
|
|
159
161
|
if meta_info:
|
|
160
162
|
message += f" [{', '.join(meta_info)}]"
|
|
161
|
-
|
|
163
|
+
|
|
162
164
|
return message
|
|
163
|
-
|
|
165
|
+
|
|
164
166
|
def _get_log_level(self, event: Event) -> str:
|
|
165
167
|
"""Determine log level for an event."""
|
|
166
168
|
# Use ERROR for failed events
|
|
167
169
|
if event.metadata and event.metadata.consumers_failed:
|
|
168
170
|
return "ERROR"
|
|
169
|
-
|
|
171
|
+
|
|
170
172
|
# Use WARNING for retried events
|
|
171
173
|
if event.metadata and event.metadata.retry_count > 0:
|
|
172
174
|
return "WARNING"
|
|
173
|
-
|
|
175
|
+
|
|
174
176
|
# Use configured level for specific topics
|
|
175
177
|
if event.topic.startswith("error."):
|
|
176
178
|
return "ERROR"
|
|
177
|
-
|
|
179
|
+
if event.topic.startswith("warning."):
|
|
178
180
|
return "WARNING"
|
|
179
|
-
|
|
181
|
+
if event.topic.startswith("debug."):
|
|
180
182
|
return "DEBUG"
|
|
181
|
-
|
|
183
|
+
|
|
182
184
|
# Default to configured level
|
|
183
|
-
return self.log_level
|
|
185
|
+
return self.log_level
|