omnibase_infra 0.2.6__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.
- omnibase_infra/__init__.py +101 -0
- omnibase_infra/adapters/adapter_onex_tool_execution.py +451 -0
- omnibase_infra/capabilities/__init__.py +15 -0
- omnibase_infra/capabilities/capability_inference_rules.py +211 -0
- omnibase_infra/capabilities/contract_capability_extractor.py +221 -0
- omnibase_infra/capabilities/intent_type_extractor.py +160 -0
- omnibase_infra/cli/__init__.py +1 -0
- omnibase_infra/cli/commands.py +216 -0
- omnibase_infra/clients/__init__.py +0 -0
- omnibase_infra/configs/widget_mapping.yaml +176 -0
- omnibase_infra/constants_topic_patterns.py +26 -0
- omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +264 -0
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +141 -0
- omnibase_infra/decorators/__init__.py +29 -0
- omnibase_infra/decorators/allow_any.py +109 -0
- omnibase_infra/dlq/__init__.py +90 -0
- omnibase_infra/dlq/constants_dlq.py +57 -0
- omnibase_infra/dlq/models/__init__.py +26 -0
- omnibase_infra/dlq/models/enum_replay_status.py +37 -0
- omnibase_infra/dlq/models/model_dlq_replay_record.py +135 -0
- omnibase_infra/dlq/models/model_dlq_tracking_config.py +184 -0
- omnibase_infra/dlq/service_dlq_tracking.py +611 -0
- omnibase_infra/enums/__init__.py +132 -0
- omnibase_infra/enums/enum_any_type_violation.py +104 -0
- omnibase_infra/enums/enum_backend_type.py +27 -0
- omnibase_infra/enums/enum_capture_outcome.py +42 -0
- omnibase_infra/enums/enum_capture_state.py +88 -0
- omnibase_infra/enums/enum_chain_violation_type.py +119 -0
- omnibase_infra/enums/enum_circuit_state.py +51 -0
- omnibase_infra/enums/enum_confirmation_event_type.py +27 -0
- omnibase_infra/enums/enum_consumer_group_purpose.py +92 -0
- omnibase_infra/enums/enum_contract_type.py +84 -0
- omnibase_infra/enums/enum_dedupe_strategy.py +46 -0
- omnibase_infra/enums/enum_dispatch_status.py +191 -0
- omnibase_infra/enums/enum_environment.py +46 -0
- omnibase_infra/enums/enum_execution_shape_violation.py +103 -0
- omnibase_infra/enums/enum_handler_error_type.py +111 -0
- omnibase_infra/enums/enum_handler_loader_error.py +178 -0
- omnibase_infra/enums/enum_handler_source_mode.py +86 -0
- omnibase_infra/enums/enum_handler_source_type.py +87 -0
- omnibase_infra/enums/enum_handler_type.py +77 -0
- omnibase_infra/enums/enum_handler_type_category.py +61 -0
- omnibase_infra/enums/enum_infra_transport_type.py +73 -0
- omnibase_infra/enums/enum_introspection_reason.py +154 -0
- omnibase_infra/enums/enum_kafka_acks.py +99 -0
- omnibase_infra/enums/enum_message_category.py +213 -0
- omnibase_infra/enums/enum_node_archetype.py +74 -0
- omnibase_infra/enums/enum_node_output_type.py +185 -0
- omnibase_infra/enums/enum_non_retryable_error_category.py +224 -0
- omnibase_infra/enums/enum_policy_type.py +32 -0
- omnibase_infra/enums/enum_registration_state.py +261 -0
- omnibase_infra/enums/enum_registration_status.py +33 -0
- omnibase_infra/enums/enum_registry_response_status.py +28 -0
- omnibase_infra/enums/enum_response_status.py +26 -0
- omnibase_infra/enums/enum_retry_error_category.py +98 -0
- omnibase_infra/enums/enum_security_rule_id.py +103 -0
- omnibase_infra/enums/enum_selection_strategy.py +91 -0
- omnibase_infra/enums/enum_topic_standard.py +42 -0
- omnibase_infra/enums/enum_validation_severity.py +78 -0
- omnibase_infra/errors/__init__.py +160 -0
- omnibase_infra/errors/error_architecture_violation.py +152 -0
- omnibase_infra/errors/error_binding_resolution.py +128 -0
- omnibase_infra/errors/error_chain_propagation.py +188 -0
- omnibase_infra/errors/error_compute_registry.py +95 -0
- omnibase_infra/errors/error_consul.py +132 -0
- omnibase_infra/errors/error_container_wiring.py +243 -0
- omnibase_infra/errors/error_event_bus_registry.py +105 -0
- omnibase_infra/errors/error_infra.py +610 -0
- omnibase_infra/errors/error_message_type_registry.py +101 -0
- omnibase_infra/errors/error_policy_registry.py +115 -0
- omnibase_infra/errors/error_vault.py +123 -0
- omnibase_infra/event_bus/__init__.py +72 -0
- omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +84 -0
- omnibase_infra/event_bus/event_bus_inmemory.py +797 -0
- omnibase_infra/event_bus/event_bus_kafka.py +1716 -0
- omnibase_infra/event_bus/mixin_kafka_broadcast.py +180 -0
- omnibase_infra/event_bus/mixin_kafka_dlq.py +771 -0
- omnibase_infra/event_bus/models/__init__.py +29 -0
- omnibase_infra/event_bus/models/config/__init__.py +20 -0
- omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +693 -0
- omnibase_infra/event_bus/models/model_dlq_event.py +206 -0
- omnibase_infra/event_bus/models/model_dlq_metrics.py +304 -0
- omnibase_infra/event_bus/models/model_event_headers.py +115 -0
- omnibase_infra/event_bus/models/model_event_message.py +60 -0
- omnibase_infra/event_bus/testing/__init__.py +26 -0
- omnibase_infra/event_bus/testing/adapter_protocol_event_publisher_inmemory.py +418 -0
- omnibase_infra/event_bus/testing/model_publisher_metrics.py +64 -0
- omnibase_infra/event_bus/topic_constants.py +376 -0
- omnibase_infra/handlers/__init__.py +82 -0
- omnibase_infra/handlers/filesystem/__init__.py +48 -0
- omnibase_infra/handlers/filesystem/enum_file_system_operation.py +35 -0
- omnibase_infra/handlers/filesystem/model_file_system_request.py +298 -0
- omnibase_infra/handlers/filesystem/model_file_system_result.py +166 -0
- omnibase_infra/handlers/handler_consul.py +795 -0
- omnibase_infra/handlers/handler_db.py +1046 -0
- omnibase_infra/handlers/handler_filesystem.py +1478 -0
- omnibase_infra/handlers/handler_graph.py +2015 -0
- omnibase_infra/handlers/handler_http.py +926 -0
- omnibase_infra/handlers/handler_intent.py +387 -0
- omnibase_infra/handlers/handler_manifest_persistence.contract.yaml +184 -0
- omnibase_infra/handlers/handler_manifest_persistence.py +1539 -0
- omnibase_infra/handlers/handler_mcp.py +1430 -0
- omnibase_infra/handlers/handler_qdrant.py +1076 -0
- omnibase_infra/handlers/handler_vault.py +428 -0
- omnibase_infra/handlers/mcp/__init__.py +19 -0
- omnibase_infra/handlers/mcp/adapter_onex_to_mcp.py +446 -0
- omnibase_infra/handlers/mcp/protocols.py +178 -0
- omnibase_infra/handlers/mcp/transport_streamable_http.py +352 -0
- omnibase_infra/handlers/mixins/__init__.py +47 -0
- omnibase_infra/handlers/mixins/mixin_consul_initialization.py +349 -0
- omnibase_infra/handlers/mixins/mixin_consul_kv.py +338 -0
- omnibase_infra/handlers/mixins/mixin_consul_service.py +542 -0
- omnibase_infra/handlers/mixins/mixin_consul_topic_index.py +585 -0
- omnibase_infra/handlers/mixins/mixin_vault_initialization.py +338 -0
- omnibase_infra/handlers/mixins/mixin_vault_retry.py +412 -0
- omnibase_infra/handlers/mixins/mixin_vault_secrets.py +450 -0
- omnibase_infra/handlers/mixins/mixin_vault_token.py +365 -0
- omnibase_infra/handlers/models/__init__.py +286 -0
- omnibase_infra/handlers/models/consul/__init__.py +81 -0
- omnibase_infra/handlers/models/consul/enum_consul_operation_type.py +57 -0
- omnibase_infra/handlers/models/consul/model_consul_deregister_payload.py +51 -0
- omnibase_infra/handlers/models/consul/model_consul_handler_config.py +153 -0
- omnibase_infra/handlers/models/consul/model_consul_handler_payload.py +89 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_found_payload.py +55 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_not_found_payload.py +49 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_recurse_payload.py +50 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_item.py +33 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_put_payload.py +41 -0
- omnibase_infra/handlers/models/consul/model_consul_register_payload.py +53 -0
- omnibase_infra/handlers/models/consul/model_consul_retry_config.py +66 -0
- omnibase_infra/handlers/models/consul/model_payload_consul.py +66 -0
- omnibase_infra/handlers/models/consul/registry_payload_consul.py +214 -0
- omnibase_infra/handlers/models/graph/__init__.py +35 -0
- omnibase_infra/handlers/models/graph/enum_graph_operation_type.py +20 -0
- omnibase_infra/handlers/models/graph/model_graph_execute_payload.py +38 -0
- omnibase_infra/handlers/models/graph/model_graph_handler_config.py +54 -0
- omnibase_infra/handlers/models/graph/model_graph_handler_payload.py +44 -0
- omnibase_infra/handlers/models/graph/model_graph_query_payload.py +40 -0
- omnibase_infra/handlers/models/graph/model_graph_record.py +22 -0
- omnibase_infra/handlers/models/http/__init__.py +50 -0
- omnibase_infra/handlers/models/http/enum_http_operation_type.py +29 -0
- omnibase_infra/handlers/models/http/model_http_body_content.py +45 -0
- omnibase_infra/handlers/models/http/model_http_get_payload.py +88 -0
- omnibase_infra/handlers/models/http/model_http_handler_payload.py +90 -0
- omnibase_infra/handlers/models/http/model_http_post_payload.py +88 -0
- omnibase_infra/handlers/models/http/model_payload_http.py +66 -0
- omnibase_infra/handlers/models/http/registry_payload_http.py +212 -0
- omnibase_infra/handlers/models/mcp/__init__.py +23 -0
- omnibase_infra/handlers/models/mcp/enum_mcp_operation_type.py +24 -0
- omnibase_infra/handlers/models/mcp/model_mcp_handler_config.py +40 -0
- omnibase_infra/handlers/models/mcp/model_mcp_tool_call.py +32 -0
- omnibase_infra/handlers/models/mcp/model_mcp_tool_result.py +45 -0
- omnibase_infra/handlers/models/model_consul_handler_response.py +96 -0
- omnibase_infra/handlers/models/model_db_describe_response.py +83 -0
- omnibase_infra/handlers/models/model_db_query_payload.py +95 -0
- omnibase_infra/handlers/models/model_db_query_response.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_config.py +98 -0
- omnibase_infra/handlers/models/model_filesystem_delete_payload.py +54 -0
- omnibase_infra/handlers/models/model_filesystem_delete_result.py +77 -0
- omnibase_infra/handlers/models/model_filesystem_directory_entry.py +75 -0
- omnibase_infra/handlers/models/model_filesystem_ensure_directory_payload.py +54 -0
- omnibase_infra/handlers/models/model_filesystem_ensure_directory_result.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_list_directory_payload.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_list_directory_result.py +68 -0
- omnibase_infra/handlers/models/model_filesystem_read_payload.py +62 -0
- omnibase_infra/handlers/models/model_filesystem_read_result.py +61 -0
- omnibase_infra/handlers/models/model_filesystem_write_payload.py +70 -0
- omnibase_infra/handlers/models/model_filesystem_write_result.py +55 -0
- omnibase_infra/handlers/models/model_graph_handler_response.py +98 -0
- omnibase_infra/handlers/models/model_handler_response.py +103 -0
- omnibase_infra/handlers/models/model_http_handler_response.py +101 -0
- omnibase_infra/handlers/models/model_manifest_metadata.py +75 -0
- omnibase_infra/handlers/models/model_manifest_persistence_config.py +62 -0
- omnibase_infra/handlers/models/model_manifest_query_payload.py +90 -0
- omnibase_infra/handlers/models/model_manifest_query_result.py +97 -0
- omnibase_infra/handlers/models/model_manifest_retrieve_payload.py +44 -0
- omnibase_infra/handlers/models/model_manifest_retrieve_result.py +98 -0
- omnibase_infra/handlers/models/model_manifest_store_payload.py +47 -0
- omnibase_infra/handlers/models/model_manifest_store_result.py +67 -0
- omnibase_infra/handlers/models/model_operation_context.py +187 -0
- omnibase_infra/handlers/models/model_qdrant_handler_response.py +98 -0
- omnibase_infra/handlers/models/model_retry_state.py +162 -0
- omnibase_infra/handlers/models/model_vault_handler_response.py +98 -0
- omnibase_infra/handlers/models/qdrant/__init__.py +44 -0
- omnibase_infra/handlers/models/qdrant/enum_qdrant_operation_type.py +26 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_collection_payload.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_delete_payload.py +36 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_handler_config.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_handler_payload.py +54 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_search_payload.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_search_result.py +30 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_upsert_payload.py +36 -0
- omnibase_infra/handlers/models/vault/__init__.py +69 -0
- omnibase_infra/handlers/models/vault/enum_vault_operation_type.py +35 -0
- omnibase_infra/handlers/models/vault/model_payload_vault.py +66 -0
- omnibase_infra/handlers/models/vault/model_vault_delete_payload.py +57 -0
- omnibase_infra/handlers/models/vault/model_vault_handler_config.py +148 -0
- omnibase_infra/handlers/models/vault/model_vault_handler_payload.py +101 -0
- omnibase_infra/handlers/models/vault/model_vault_list_payload.py +58 -0
- omnibase_infra/handlers/models/vault/model_vault_renew_token_payload.py +67 -0
- omnibase_infra/handlers/models/vault/model_vault_retry_config.py +66 -0
- omnibase_infra/handlers/models/vault/model_vault_secret_payload.py +106 -0
- omnibase_infra/handlers/models/vault/model_vault_write_payload.py +66 -0
- omnibase_infra/handlers/models/vault/registry_payload_vault.py +213 -0
- omnibase_infra/handlers/registration_storage/__init__.py +43 -0
- omnibase_infra/handlers/registration_storage/handler_registration_storage_mock.py +392 -0
- omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +922 -0
- omnibase_infra/handlers/registration_storage/models/__init__.py +23 -0
- omnibase_infra/handlers/registration_storage/models/model_delete_registration_request.py +58 -0
- omnibase_infra/handlers/registration_storage/models/model_update_registration_request.py +73 -0
- omnibase_infra/handlers/registration_storage/protocol_registration_persistence.py +191 -0
- omnibase_infra/handlers/service_discovery/__init__.py +43 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +1051 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_mock.py +258 -0
- omnibase_infra/handlers/service_discovery/models/__init__.py +22 -0
- omnibase_infra/handlers/service_discovery/models/model_discovery_result.py +64 -0
- omnibase_infra/handlers/service_discovery/models/model_registration_result.py +138 -0
- omnibase_infra/handlers/service_discovery/models/model_service_info.py +109 -0
- omnibase_infra/handlers/service_discovery/protocol_discovery_operations.py +170 -0
- omnibase_infra/idempotency/__init__.py +94 -0
- omnibase_infra/idempotency/models/__init__.py +43 -0
- omnibase_infra/idempotency/models/model_idempotency_check_result.py +85 -0
- omnibase_infra/idempotency/models/model_idempotency_guard_config.py +130 -0
- omnibase_infra/idempotency/models/model_idempotency_record.py +86 -0
- omnibase_infra/idempotency/models/model_idempotency_store_health_check_result.py +81 -0
- omnibase_infra/idempotency/models/model_idempotency_store_metrics.py +140 -0
- omnibase_infra/idempotency/models/model_postgres_idempotency_store_config.py +299 -0
- omnibase_infra/idempotency/protocol_idempotency_store.py +184 -0
- omnibase_infra/idempotency/store_inmemory.py +265 -0
- omnibase_infra/idempotency/store_postgres.py +923 -0
- omnibase_infra/infrastructure/__init__.py +0 -0
- omnibase_infra/migrations/001_create_event_ledger.sql +166 -0
- omnibase_infra/migrations/001_drop_event_ledger.sql +18 -0
- omnibase_infra/mixins/__init__.py +71 -0
- omnibase_infra/mixins/mixin_async_circuit_breaker.py +656 -0
- omnibase_infra/mixins/mixin_dict_like_accessors.py +146 -0
- omnibase_infra/mixins/mixin_envelope_extraction.py +119 -0
- omnibase_infra/mixins/mixin_node_introspection.py +2670 -0
- omnibase_infra/mixins/mixin_retry_execution.py +386 -0
- omnibase_infra/mixins/protocol_circuit_breaker_aware.py +133 -0
- omnibase_infra/models/__init__.py +144 -0
- omnibase_infra/models/bindings/__init__.py +59 -0
- omnibase_infra/models/bindings/constants.py +144 -0
- omnibase_infra/models/bindings/model_binding_resolution_result.py +103 -0
- omnibase_infra/models/bindings/model_operation_binding.py +44 -0
- omnibase_infra/models/bindings/model_operation_bindings_subcontract.py +152 -0
- omnibase_infra/models/bindings/model_parsed_binding.py +52 -0
- omnibase_infra/models/corpus/__init__.py +17 -0
- omnibase_infra/models/corpus/model_capture_config.py +133 -0
- omnibase_infra/models/corpus/model_capture_result.py +86 -0
- omnibase_infra/models/discovery/__init__.py +42 -0
- omnibase_infra/models/discovery/model_dependency_spec.py +319 -0
- omnibase_infra/models/discovery/model_discovered_capabilities.py +50 -0
- omnibase_infra/models/discovery/model_introspection_config.py +330 -0
- omnibase_infra/models/discovery/model_introspection_performance_metrics.py +169 -0
- omnibase_infra/models/discovery/model_introspection_task_config.py +116 -0
- omnibase_infra/models/dispatch/__init__.py +155 -0
- omnibase_infra/models/dispatch/model_debug_trace_snapshot.py +114 -0
- omnibase_infra/models/dispatch/model_dispatch_context.py +439 -0
- omnibase_infra/models/dispatch/model_dispatch_error.py +336 -0
- omnibase_infra/models/dispatch/model_dispatch_log_context.py +400 -0
- omnibase_infra/models/dispatch/model_dispatch_metadata.py +228 -0
- omnibase_infra/models/dispatch/model_dispatch_metrics.py +496 -0
- omnibase_infra/models/dispatch/model_dispatch_outcome.py +317 -0
- omnibase_infra/models/dispatch/model_dispatch_outputs.py +231 -0
- omnibase_infra/models/dispatch/model_dispatch_result.py +436 -0
- omnibase_infra/models/dispatch/model_dispatch_route.py +279 -0
- omnibase_infra/models/dispatch/model_dispatcher_metrics.py +275 -0
- omnibase_infra/models/dispatch/model_dispatcher_registration.py +352 -0
- omnibase_infra/models/dispatch/model_materialized_dispatch.py +141 -0
- omnibase_infra/models/dispatch/model_parsed_topic.py +135 -0
- omnibase_infra/models/dispatch/model_topic_parser.py +725 -0
- omnibase_infra/models/dispatch/model_tracing_context.py +285 -0
- omnibase_infra/models/errors/__init__.py +45 -0
- omnibase_infra/models/errors/model_handler_validation_error.py +594 -0
- omnibase_infra/models/errors/model_infra_error_context.py +99 -0
- omnibase_infra/models/errors/model_message_type_registry_error_context.py +71 -0
- omnibase_infra/models/errors/model_timeout_error_context.py +110 -0
- omnibase_infra/models/handlers/__init__.py +80 -0
- omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
- omnibase_infra/models/handlers/model_contract_discovery_result.py +82 -0
- omnibase_infra/models/handlers/model_handler_descriptor.py +200 -0
- omnibase_infra/models/handlers/model_handler_identifier.py +215 -0
- omnibase_infra/models/handlers/model_handler_source_config.py +220 -0
- omnibase_infra/models/health/__init__.py +9 -0
- omnibase_infra/models/health/model_health_check_result.py +40 -0
- omnibase_infra/models/lifecycle/__init__.py +39 -0
- omnibase_infra/models/logging/__init__.py +51 -0
- omnibase_infra/models/logging/model_log_context.py +756 -0
- omnibase_infra/models/mcp/__init__.py +15 -0
- omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
- omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
- omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
- omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
- omnibase_infra/models/model_node_identity.py +126 -0
- omnibase_infra/models/model_retry_error_classification.py +78 -0
- omnibase_infra/models/projection/__init__.py +43 -0
- omnibase_infra/models/projection/model_capability_fields.py +112 -0
- omnibase_infra/models/projection/model_registration_projection.py +434 -0
- omnibase_infra/models/projection/model_registration_snapshot.py +322 -0
- omnibase_infra/models/projection/model_sequence_info.py +182 -0
- omnibase_infra/models/projection/model_snapshot_topic_config.py +591 -0
- omnibase_infra/models/projectors/__init__.py +41 -0
- omnibase_infra/models/projectors/model_projector_column.py +289 -0
- omnibase_infra/models/projectors/model_projector_discovery_result.py +65 -0
- omnibase_infra/models/projectors/model_projector_index.py +270 -0
- omnibase_infra/models/projectors/model_projector_schema.py +415 -0
- omnibase_infra/models/projectors/model_projector_validation_error.py +63 -0
- omnibase_infra/models/projectors/util_sql_identifiers.py +115 -0
- omnibase_infra/models/registration/__init__.py +68 -0
- omnibase_infra/models/registration/commands/__init__.py +15 -0
- omnibase_infra/models/registration/commands/model_node_registration_acked.py +108 -0
- omnibase_infra/models/registration/events/__init__.py +56 -0
- omnibase_infra/models/registration/events/model_node_became_active.py +103 -0
- omnibase_infra/models/registration/events/model_node_liveness_expired.py +103 -0
- omnibase_infra/models/registration/events/model_node_registration_accepted.py +98 -0
- omnibase_infra/models/registration/events/model_node_registration_ack_received.py +98 -0
- omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py +112 -0
- omnibase_infra/models/registration/events/model_node_registration_initiated.py +107 -0
- omnibase_infra/models/registration/events/model_node_registration_rejected.py +104 -0
- omnibase_infra/models/registration/model_event_bus_topic_entry.py +59 -0
- omnibase_infra/models/registration/model_introspection_metrics.py +253 -0
- omnibase_infra/models/registration/model_node_capabilities.py +190 -0
- omnibase_infra/models/registration/model_node_event_bus_config.py +99 -0
- omnibase_infra/models/registration/model_node_heartbeat_event.py +126 -0
- omnibase_infra/models/registration/model_node_introspection_event.py +195 -0
- omnibase_infra/models/registration/model_node_metadata.py +79 -0
- omnibase_infra/models/registration/model_node_registration.py +162 -0
- omnibase_infra/models/registration/model_node_registration_record.py +162 -0
- omnibase_infra/models/registry/__init__.py +29 -0
- omnibase_infra/models/registry/model_domain_constraint.py +202 -0
- omnibase_infra/models/registry/model_message_type_entry.py +271 -0
- omnibase_infra/models/resilience/__init__.py +9 -0
- omnibase_infra/models/resilience/model_circuit_breaker_config.py +227 -0
- omnibase_infra/models/routing/__init__.py +25 -0
- omnibase_infra/models/routing/model_routing_entry.py +52 -0
- omnibase_infra/models/routing/model_routing_subcontract.py +70 -0
- omnibase_infra/models/runtime/__init__.py +49 -0
- omnibase_infra/models/runtime/model_contract_security_config.py +41 -0
- omnibase_infra/models/runtime/model_discovery_error.py +81 -0
- omnibase_infra/models/runtime/model_discovery_result.py +162 -0
- omnibase_infra/models/runtime/model_discovery_warning.py +74 -0
- omnibase_infra/models/runtime/model_failed_plugin_load.py +63 -0
- omnibase_infra/models/runtime/model_handler_contract.py +296 -0
- omnibase_infra/models/runtime/model_loaded_handler.py +129 -0
- omnibase_infra/models/runtime/model_plugin_load_context.py +93 -0
- omnibase_infra/models/runtime/model_plugin_load_summary.py +124 -0
- omnibase_infra/models/security/__init__.py +50 -0
- omnibase_infra/models/security/classification_levels.py +99 -0
- omnibase_infra/models/security/model_environment_policy.py +145 -0
- omnibase_infra/models/security/model_handler_security_policy.py +107 -0
- omnibase_infra/models/security/model_security_error.py +81 -0
- omnibase_infra/models/security/model_security_validation_result.py +328 -0
- omnibase_infra/models/security/model_security_warning.py +67 -0
- omnibase_infra/models/snapshot/__init__.py +27 -0
- omnibase_infra/models/snapshot/model_field_change.py +65 -0
- omnibase_infra/models/snapshot/model_snapshot.py +270 -0
- omnibase_infra/models/snapshot/model_snapshot_diff.py +203 -0
- omnibase_infra/models/snapshot/model_subject_ref.py +81 -0
- omnibase_infra/models/types/__init__.py +71 -0
- omnibase_infra/models/validation/__init__.py +89 -0
- omnibase_infra/models/validation/model_any_type_validation_result.py +118 -0
- omnibase_infra/models/validation/model_any_type_violation.py +141 -0
- omnibase_infra/models/validation/model_category_match_result.py +345 -0
- omnibase_infra/models/validation/model_chain_violation.py +166 -0
- omnibase_infra/models/validation/model_coverage_metrics.py +316 -0
- omnibase_infra/models/validation/model_execution_shape_rule.py +159 -0
- omnibase_infra/models/validation/model_execution_shape_validation.py +208 -0
- omnibase_infra/models/validation/model_execution_shape_validation_result.py +294 -0
- omnibase_infra/models/validation/model_execution_shape_violation.py +122 -0
- omnibase_infra/models/validation/model_localhandler_validation_result.py +139 -0
- omnibase_infra/models/validation/model_localhandler_violation.py +100 -0
- omnibase_infra/models/validation/model_output_validation_params.py +74 -0
- omnibase_infra/models/validation/model_validate_and_raise_params.py +84 -0
- omnibase_infra/models/validation/model_validation_error_params.py +84 -0
- omnibase_infra/models/validation/model_validation_outcome.py +287 -0
- omnibase_infra/nodes/__init__.py +57 -0
- omnibase_infra/nodes/architecture_validator/__init__.py +79 -0
- omnibase_infra/nodes/architecture_validator/contract.yaml +252 -0
- omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +203 -0
- omnibase_infra/nodes/architecture_validator/mixins/__init__.py +16 -0
- omnibase_infra/nodes/architecture_validator/mixins/mixin_file_path_rule.py +92 -0
- omnibase_infra/nodes/architecture_validator/models/__init__.py +36 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_request.py +56 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_result.py +311 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_violation.py +163 -0
- omnibase_infra/nodes/architecture_validator/models/model_rule_check_result.py +265 -0
- omnibase_infra/nodes/architecture_validator/models/model_validation_request.py +105 -0
- omnibase_infra/nodes/architecture_validator/models/model_validation_result.py +314 -0
- omnibase_infra/nodes/architecture_validator/node.py +262 -0
- omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +383 -0
- omnibase_infra/nodes/architecture_validator/protocols/__init__.py +9 -0
- omnibase_infra/nodes/architecture_validator/protocols/protocol_architecture_rule.py +225 -0
- omnibase_infra/nodes/architecture_validator/registry/__init__.py +28 -0
- omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +106 -0
- omnibase_infra/nodes/architecture_validator/validators/__init__.py +104 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_direct_dispatch.py +422 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_handler_publishing.py +481 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_orchestrator_fsm.py +491 -0
- omnibase_infra/nodes/contract_registry_reducer/__init__.py +29 -0
- omnibase_infra/nodes/contract_registry_reducer/contract.yaml +255 -0
- omnibase_infra/nodes/contract_registry_reducer/models/__init__.py +38 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_contract_registry_state.py +266 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_cleanup_topic_references.py +55 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_deactivate_contract.py +58 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_mark_stale.py +49 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_heartbeat.py +71 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_topic.py +66 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_upsert_contract.py +92 -0
- omnibase_infra/nodes/contract_registry_reducer/node.py +121 -0
- omnibase_infra/nodes/contract_registry_reducer/reducer.py +784 -0
- omnibase_infra/nodes/contract_registry_reducer/registry/__init__.py +9 -0
- omnibase_infra/nodes/contract_registry_reducer/registry/registry_infra_contract_registry_reducer.py +101 -0
- omnibase_infra/nodes/effects/README.md +358 -0
- omnibase_infra/nodes/effects/__init__.py +26 -0
- omnibase_infra/nodes/effects/contract.yaml +167 -0
- omnibase_infra/nodes/effects/models/__init__.py +32 -0
- omnibase_infra/nodes/effects/models/model_backend_result.py +190 -0
- omnibase_infra/nodes/effects/models/model_effect_idempotency_config.py +92 -0
- omnibase_infra/nodes/effects/models/model_registry_request.py +132 -0
- omnibase_infra/nodes/effects/models/model_registry_response.py +263 -0
- omnibase_infra/nodes/effects/protocol_consul_client.py +89 -0
- omnibase_infra/nodes/effects/protocol_effect_idempotency_store.py +143 -0
- omnibase_infra/nodes/effects/protocol_postgres_adapter.py +96 -0
- omnibase_infra/nodes/effects/registry_effect.py +525 -0
- omnibase_infra/nodes/effects/store_effect_idempotency_inmemory.py +425 -0
- omnibase_infra/nodes/handlers/consul/contract.yaml +85 -0
- omnibase_infra/nodes/handlers/db/contract.yaml +72 -0
- omnibase_infra/nodes/handlers/graph/contract.yaml +127 -0
- omnibase_infra/nodes/handlers/http/contract.yaml +74 -0
- omnibase_infra/nodes/handlers/intent/contract.yaml +66 -0
- omnibase_infra/nodes/handlers/mcp/contract.yaml +69 -0
- omnibase_infra/nodes/handlers/vault/contract.yaml +91 -0
- omnibase_infra/nodes/node_intent_storage_effect/__init__.py +50 -0
- omnibase_infra/nodes/node_intent_storage_effect/contract.yaml +194 -0
- omnibase_infra/nodes/node_intent_storage_effect/models/__init__.py +24 -0
- omnibase_infra/nodes/node_intent_storage_effect/models/model_intent_storage_input.py +141 -0
- omnibase_infra/nodes/node_intent_storage_effect/models/model_intent_storage_output.py +130 -0
- omnibase_infra/nodes/node_intent_storage_effect/node.py +94 -0
- omnibase_infra/nodes/node_intent_storage_effect/registry/__init__.py +35 -0
- omnibase_infra/nodes/node_intent_storage_effect/registry/registry_infra_intent_storage.py +294 -0
- omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +50 -0
- omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +104 -0
- omnibase_infra/nodes/node_ledger_projection_compute/node.py +284 -0
- omnibase_infra/nodes/node_ledger_projection_compute/registry/__init__.py +29 -0
- omnibase_infra/nodes/node_ledger_projection_compute/registry/registry_infra_ledger_projection.py +118 -0
- omnibase_infra/nodes/node_ledger_write_effect/__init__.py +82 -0
- omnibase_infra/nodes/node_ledger_write_effect/contract.yaml +200 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/__init__.py +22 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_append.py +372 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_query.py +597 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/__init__.py +31 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_append_result.py +54 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_entry.py +92 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query.py +53 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query_result.py +41 -0
- omnibase_infra/nodes/node_ledger_write_effect/node.py +89 -0
- omnibase_infra/nodes/node_ledger_write_effect/protocols/__init__.py +13 -0
- omnibase_infra/nodes/node_ledger_write_effect/protocols/protocol_ledger_persistence.py +127 -0
- omnibase_infra/nodes/node_ledger_write_effect/registry/__init__.py +9 -0
- omnibase_infra/nodes/node_ledger_write_effect/registry/registry_infra_ledger_write.py +121 -0
- omnibase_infra/nodes/node_registration_orchestrator/README.md +542 -0
- omnibase_infra/nodes/node_registration_orchestrator/__init__.py +120 -0
- omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +482 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/__init__.py +53 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_introspected.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_registration_acked.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_runtime_tick.py +373 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py +62 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +694 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py +458 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py +364 -0
- omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +544 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/__init__.py +75 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_intent_payload.py +194 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_registration_intent.py +67 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_intent_execution_result.py +50 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_node_liveness_expired.py +107 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_config.py +67 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_input.py +41 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_output.py +166 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +235 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_upsert_intent.py +68 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_execution_result.py +384 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_state.py +60 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_registration_intent.py +177 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_registry_intent.py +247 -0
- omnibase_infra/nodes/node_registration_orchestrator/node.py +195 -0
- omnibase_infra/nodes/node_registration_orchestrator/plugin.py +909 -0
- omnibase_infra/nodes/node_registration_orchestrator/protocols.py +439 -0
- omnibase_infra/nodes/node_registration_orchestrator/registry/__init__.py +41 -0
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +528 -0
- omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +393 -0
- omnibase_infra/nodes/node_registration_orchestrator/wiring.py +743 -0
- omnibase_infra/nodes/node_registration_reducer/__init__.py +15 -0
- omnibase_infra/nodes/node_registration_reducer/contract.yaml +301 -0
- omnibase_infra/nodes/node_registration_reducer/models/__init__.py +38 -0
- omnibase_infra/nodes/node_registration_reducer/models/model_validation_result.py +113 -0
- omnibase_infra/nodes/node_registration_reducer/node.py +139 -0
- omnibase_infra/nodes/node_registration_reducer/registry/__init__.py +9 -0
- omnibase_infra/nodes/node_registration_reducer/registry/registry_infra_node_registration_reducer.py +79 -0
- omnibase_infra/nodes/node_registration_storage_effect/__init__.py +41 -0
- omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +220 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/__init__.py +44 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_delete_result.py +132 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_record.py +199 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_update.py +155 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_details.py +123 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_result.py +117 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_query.py +100 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_result.py +136 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_upsert_result.py +127 -0
- omnibase_infra/nodes/node_registration_storage_effect/node.py +112 -0
- omnibase_infra/nodes/node_registration_storage_effect/protocols/__init__.py +22 -0
- omnibase_infra/nodes/node_registration_storage_effect/protocols/protocol_registration_persistence.py +333 -0
- omnibase_infra/nodes/node_registration_storage_effect/registry/__init__.py +23 -0
- omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +215 -0
- omnibase_infra/nodes/node_registry_effect/__init__.py +85 -0
- omnibase_infra/nodes/node_registry_effect/contract.yaml +677 -0
- omnibase_infra/nodes/node_registry_effect/handlers/__init__.py +70 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_deregister.py +211 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_register.py +212 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +417 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_deactivate.py +215 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_upsert.py +208 -0
- omnibase_infra/nodes/node_registry_effect/models/__init__.py +43 -0
- omnibase_infra/nodes/node_registry_effect/models/model_partial_retry_request.py +92 -0
- omnibase_infra/nodes/node_registry_effect/node.py +165 -0
- omnibase_infra/nodes/node_registry_effect/registry/__init__.py +27 -0
- omnibase_infra/nodes/node_registry_effect/registry/registry_infra_registry_effect.py +196 -0
- omnibase_infra/nodes/node_service_discovery_effect/__init__.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/contract.yaml +246 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/__init__.py +67 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/enum_health_status.py +72 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/enum_service_discovery_operation.py +58 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_query.py +99 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_result.py +98 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_health_check_config.py +121 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_query_metadata.py +63 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_registration_result.py +130 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_details.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_result.py +119 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_info.py +106 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_registration.py +121 -0
- omnibase_infra/nodes/node_service_discovery_effect/node.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/protocols/__init__.py +14 -0
- omnibase_infra/nodes/node_service_discovery_effect/protocols/protocol_discovery_operations.py +279 -0
- omnibase_infra/nodes/node_service_discovery_effect/registry/__init__.py +13 -0
- omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +222 -0
- omnibase_infra/nodes/reducers/__init__.py +30 -0
- omnibase_infra/nodes/reducers/models/__init__.py +37 -0
- omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +87 -0
- omnibase_infra/nodes/reducers/models/model_payload_ledger_append.py +133 -0
- omnibase_infra/nodes/reducers/models/model_payload_postgres_upsert_registration.py +60 -0
- omnibase_infra/nodes/reducers/models/model_registration_confirmation.py +166 -0
- omnibase_infra/nodes/reducers/models/model_registration_state.py +433 -0
- omnibase_infra/nodes/reducers/registration_reducer.py +1138 -0
- omnibase_infra/observability/__init__.py +143 -0
- omnibase_infra/observability/constants_metrics.py +91 -0
- omnibase_infra/observability/factory_observability_sink.py +525 -0
- omnibase_infra/observability/handlers/__init__.py +118 -0
- omnibase_infra/observability/handlers/handler_logging_structured.py +967 -0
- omnibase_infra/observability/handlers/handler_metrics_prometheus.py +1120 -0
- omnibase_infra/observability/handlers/model_logging_handler_config.py +71 -0
- omnibase_infra/observability/handlers/model_logging_handler_response.py +77 -0
- omnibase_infra/observability/handlers/model_metrics_handler_config.py +172 -0
- omnibase_infra/observability/handlers/model_metrics_handler_payload.py +135 -0
- omnibase_infra/observability/handlers/model_metrics_handler_response.py +101 -0
- omnibase_infra/observability/hooks/__init__.py +74 -0
- omnibase_infra/observability/hooks/hook_observability.py +1223 -0
- omnibase_infra/observability/models/__init__.py +30 -0
- omnibase_infra/observability/models/enum_required_log_context_key.py +77 -0
- omnibase_infra/observability/models/model_buffered_log_entry.py +117 -0
- omnibase_infra/observability/models/model_logging_sink_config.py +73 -0
- omnibase_infra/observability/models/model_metrics_sink_config.py +156 -0
- omnibase_infra/observability/sinks/__init__.py +69 -0
- omnibase_infra/observability/sinks/sink_logging_structured.py +809 -0
- omnibase_infra/observability/sinks/sink_metrics_prometheus.py +710 -0
- omnibase_infra/plugins/__init__.py +27 -0
- omnibase_infra/plugins/examples/__init__.py +28 -0
- omnibase_infra/plugins/examples/plugin_json_normalizer.py +271 -0
- omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +210 -0
- omnibase_infra/plugins/models/__init__.py +21 -0
- omnibase_infra/plugins/models/model_plugin_context.py +76 -0
- omnibase_infra/plugins/models/model_plugin_input_data.py +58 -0
- omnibase_infra/plugins/models/model_plugin_output_data.py +62 -0
- omnibase_infra/plugins/plugin_compute_base.py +449 -0
- omnibase_infra/projectors/__init__.py +30 -0
- omnibase_infra/projectors/contracts/__init__.py +63 -0
- omnibase_infra/projectors/contracts/registration_projector.yaml +370 -0
- omnibase_infra/projectors/projection_reader_registration.py +1559 -0
- omnibase_infra/projectors/snapshot_publisher_registration.py +1329 -0
- omnibase_infra/protocols/__init__.py +104 -0
- omnibase_infra/protocols/protocol_capability_projection.py +253 -0
- omnibase_infra/protocols/protocol_capability_query.py +251 -0
- omnibase_infra/protocols/protocol_container_aware.py +200 -0
- omnibase_infra/protocols/protocol_dispatch_engine.py +152 -0
- omnibase_infra/protocols/protocol_event_bus_like.py +127 -0
- omnibase_infra/protocols/protocol_event_projector.py +96 -0
- omnibase_infra/protocols/protocol_idempotency_store.py +142 -0
- omnibase_infra/protocols/protocol_message_dispatcher.py +247 -0
- omnibase_infra/protocols/protocol_message_type_registry.py +306 -0
- omnibase_infra/protocols/protocol_plugin_compute.py +368 -0
- omnibase_infra/protocols/protocol_projector_schema_validator.py +82 -0
- omnibase_infra/protocols/protocol_registry_metrics.py +215 -0
- omnibase_infra/protocols/protocol_snapshot_publisher.py +396 -0
- omnibase_infra/protocols/protocol_snapshot_store.py +567 -0
- omnibase_infra/runtime/__init__.py +445 -0
- omnibase_infra/runtime/binding_config_resolver.py +2771 -0
- omnibase_infra/runtime/binding_resolver.py +753 -0
- omnibase_infra/runtime/chain_aware_dispatch.py +467 -0
- omnibase_infra/runtime/constants_notification.py +75 -0
- omnibase_infra/runtime/constants_security.py +70 -0
- omnibase_infra/runtime/contract_handler_discovery.py +587 -0
- omnibase_infra/runtime/contract_loaders/__init__.py +51 -0
- omnibase_infra/runtime/contract_loaders/handler_routing_loader.py +464 -0
- omnibase_infra/runtime/contract_loaders/operation_bindings_loader.py +789 -0
- omnibase_infra/runtime/dispatch_context_enforcer.py +427 -0
- omnibase_infra/runtime/emit_daemon/__init__.py +97 -0
- omnibase_infra/runtime/emit_daemon/cli.py +844 -0
- omnibase_infra/runtime/emit_daemon/client.py +811 -0
- omnibase_infra/runtime/emit_daemon/config.py +535 -0
- omnibase_infra/runtime/emit_daemon/daemon.py +812 -0
- omnibase_infra/runtime/emit_daemon/event_registry.py +477 -0
- omnibase_infra/runtime/emit_daemon/model_daemon_request.py +139 -0
- omnibase_infra/runtime/emit_daemon/model_daemon_response.py +191 -0
- omnibase_infra/runtime/emit_daemon/queue.py +618 -0
- omnibase_infra/runtime/enums/__init__.py +18 -0
- omnibase_infra/runtime/enums/enum_config_ref_scheme.py +33 -0
- omnibase_infra/runtime/enums/enum_scheduler_status.py +170 -0
- omnibase_infra/runtime/envelope_validator.py +179 -0
- omnibase_infra/runtime/event_bus_subcontract_wiring.py +466 -0
- omnibase_infra/runtime/handler_bootstrap_source.py +507 -0
- omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
- omnibase_infra/runtime/handler_contract_source.py +750 -0
- omnibase_infra/runtime/handler_identity.py +81 -0
- omnibase_infra/runtime/handler_plugin_loader.py +2046 -0
- omnibase_infra/runtime/handler_registry.py +329 -0
- omnibase_infra/runtime/handler_source_resolver.py +367 -0
- omnibase_infra/runtime/invocation_security_enforcer.py +427 -0
- omnibase_infra/runtime/kafka_contract_source.py +984 -0
- omnibase_infra/runtime/kernel.py +40 -0
- omnibase_infra/runtime/mixin_policy_validation.py +522 -0
- omnibase_infra/runtime/mixin_semver_cache.py +402 -0
- omnibase_infra/runtime/mixins/__init__.py +24 -0
- omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
- omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +778 -0
- omnibase_infra/runtime/models/__init__.py +229 -0
- omnibase_infra/runtime/models/model_batch_lifecycle_result.py +217 -0
- omnibase_infra/runtime/models/model_binding_config.py +168 -0
- omnibase_infra/runtime/models/model_binding_config_cache_stats.py +135 -0
- omnibase_infra/runtime/models/model_binding_config_resolver_config.py +329 -0
- omnibase_infra/runtime/models/model_cached_secret.py +138 -0
- omnibase_infra/runtime/models/model_compute_key.py +138 -0
- omnibase_infra/runtime/models/model_compute_registration.py +97 -0
- omnibase_infra/runtime/models/model_config_cache_entry.py +61 -0
- omnibase_infra/runtime/models/model_config_ref.py +331 -0
- omnibase_infra/runtime/models/model_config_ref_parse_result.py +125 -0
- omnibase_infra/runtime/models/model_contract_load_result.py +224 -0
- omnibase_infra/runtime/models/model_domain_plugin_config.py +92 -0
- omnibase_infra/runtime/models/model_domain_plugin_result.py +270 -0
- omnibase_infra/runtime/models/model_duplicate_response.py +54 -0
- omnibase_infra/runtime/models/model_enabled_protocols_config.py +61 -0
- omnibase_infra/runtime/models/model_event_bus_config.py +54 -0
- omnibase_infra/runtime/models/model_failed_component.py +55 -0
- omnibase_infra/runtime/models/model_health_check_response.py +168 -0
- omnibase_infra/runtime/models/model_health_check_result.py +229 -0
- omnibase_infra/runtime/models/model_lifecycle_result.py +245 -0
- omnibase_infra/runtime/models/model_logging_config.py +42 -0
- omnibase_infra/runtime/models/model_optional_correlation_id.py +167 -0
- omnibase_infra/runtime/models/model_optional_string.py +94 -0
- omnibase_infra/runtime/models/model_optional_uuid.py +110 -0
- omnibase_infra/runtime/models/model_policy_context.py +100 -0
- omnibase_infra/runtime/models/model_policy_key.py +138 -0
- omnibase_infra/runtime/models/model_policy_registration.py +139 -0
- omnibase_infra/runtime/models/model_policy_result.py +103 -0
- omnibase_infra/runtime/models/model_policy_type_filter.py +157 -0
- omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
- omnibase_infra/runtime/models/model_projector_plugin_loader_config.py +47 -0
- omnibase_infra/runtime/models/model_protocol_registration_config.py +65 -0
- omnibase_infra/runtime/models/model_retry_policy.py +105 -0
- omnibase_infra/runtime/models/model_runtime_config.py +150 -0
- omnibase_infra/runtime/models/model_runtime_contract_config.py +268 -0
- omnibase_infra/runtime/models/model_runtime_scheduler_config.py +625 -0
- omnibase_infra/runtime/models/model_runtime_scheduler_metrics.py +233 -0
- omnibase_infra/runtime/models/model_runtime_tick.py +193 -0
- omnibase_infra/runtime/models/model_secret_cache_stats.py +82 -0
- omnibase_infra/runtime/models/model_secret_mapping.py +63 -0
- omnibase_infra/runtime/models/model_secret_resolver_config.py +107 -0
- omnibase_infra/runtime/models/model_secret_resolver_metrics.py +111 -0
- omnibase_infra/runtime/models/model_secret_source_info.py +72 -0
- omnibase_infra/runtime/models/model_secret_source_spec.py +66 -0
- omnibase_infra/runtime/models/model_security_config.py +109 -0
- omnibase_infra/runtime/models/model_shutdown_batch_result.py +75 -0
- omnibase_infra/runtime/models/model_shutdown_config.py +94 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
- omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
- omnibase_infra/runtime/projector_plugin_loader.py +1462 -0
- omnibase_infra/runtime/projector_schema_manager.py +565 -0
- omnibase_infra/runtime/projector_shell.py +1330 -0
- omnibase_infra/runtime/protocol_contract_descriptor.py +92 -0
- omnibase_infra/runtime/protocol_contract_source.py +92 -0
- omnibase_infra/runtime/protocol_domain_plugin.py +474 -0
- omnibase_infra/runtime/protocol_handler_discovery.py +221 -0
- omnibase_infra/runtime/protocol_handler_plugin_loader.py +327 -0
- omnibase_infra/runtime/protocol_lifecycle_executor.py +435 -0
- omnibase_infra/runtime/protocol_policy.py +366 -0
- omnibase_infra/runtime/protocols/__init__.py +37 -0
- omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py +468 -0
- omnibase_infra/runtime/publisher_topic_scoped.py +294 -0
- omnibase_infra/runtime/registry/__init__.py +93 -0
- omnibase_infra/runtime/registry/mixin_message_type_query.py +326 -0
- omnibase_infra/runtime/registry/mixin_message_type_registration.py +354 -0
- omnibase_infra/runtime/registry/registry_event_bus_binding.py +268 -0
- omnibase_infra/runtime/registry/registry_message_type.py +542 -0
- omnibase_infra/runtime/registry/registry_protocol_binding.py +445 -0
- omnibase_infra/runtime/registry_compute.py +1143 -0
- omnibase_infra/runtime/registry_contract_source.py +693 -0
- omnibase_infra/runtime/registry_dispatcher.py +678 -0
- omnibase_infra/runtime/registry_policy.py +1185 -0
- omnibase_infra/runtime/runtime_contract_config_loader.py +406 -0
- omnibase_infra/runtime/runtime_scheduler.py +1070 -0
- omnibase_infra/runtime/secret_resolver.py +2112 -0
- omnibase_infra/runtime/security_metadata_validator.py +776 -0
- omnibase_infra/runtime/service_kernel.py +1651 -0
- omnibase_infra/runtime/service_message_dispatch_engine.py +2350 -0
- omnibase_infra/runtime/service_runtime_host_process.py +3493 -0
- omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
- omnibase_infra/runtime/transition_notification_publisher.py +765 -0
- omnibase_infra/runtime/util_container_wiring.py +1124 -0
- omnibase_infra/runtime/util_validation.py +314 -0
- omnibase_infra/runtime/util_version.py +98 -0
- omnibase_infra/runtime/util_wiring.py +723 -0
- omnibase_infra/schemas/schema_registration_projection.sql +320 -0
- omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
- omnibase_infra/services/__init__.py +89 -0
- omnibase_infra/services/corpus_capture.py +684 -0
- omnibase_infra/services/mcp/__init__.py +31 -0
- omnibase_infra/services/mcp/mcp_server_lifecycle.py +449 -0
- omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
- omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
- omnibase_infra/services/mcp/service_mcp_tool_sync.py +565 -0
- omnibase_infra/services/registry_api/__init__.py +40 -0
- omnibase_infra/services/registry_api/main.py +261 -0
- omnibase_infra/services/registry_api/models/__init__.py +66 -0
- omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
- omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
- omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
- omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
- omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
- omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
- omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
- omnibase_infra/services/registry_api/models/model_warning.py +49 -0
- omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
- omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
- omnibase_infra/services/registry_api/routes.py +371 -0
- omnibase_infra/services/registry_api/service.py +837 -0
- omnibase_infra/services/service_capability_query.py +945 -0
- omnibase_infra/services/service_health.py +898 -0
- omnibase_infra/services/service_node_selector.py +530 -0
- omnibase_infra/services/service_timeout_emitter.py +699 -0
- omnibase_infra/services/service_timeout_scanner.py +394 -0
- omnibase_infra/services/session/__init__.py +56 -0
- omnibase_infra/services/session/config_consumer.py +137 -0
- omnibase_infra/services/session/config_store.py +139 -0
- omnibase_infra/services/session/consumer.py +1007 -0
- omnibase_infra/services/session/protocol_session_aggregator.py +117 -0
- omnibase_infra/services/session/store.py +997 -0
- omnibase_infra/services/snapshot/__init__.py +31 -0
- omnibase_infra/services/snapshot/service_snapshot.py +647 -0
- omnibase_infra/services/snapshot/store_inmemory.py +637 -0
- omnibase_infra/services/snapshot/store_postgres.py +1279 -0
- omnibase_infra/shared/__init__.py +8 -0
- omnibase_infra/testing/__init__.py +10 -0
- omnibase_infra/testing/utils.py +23 -0
- omnibase_infra/topics/__init__.py +45 -0
- omnibase_infra/topics/platform_topic_suffixes.py +140 -0
- omnibase_infra/topics/util_topic_composition.py +95 -0
- omnibase_infra/types/__init__.py +48 -0
- omnibase_infra/types/type_cache_info.py +49 -0
- omnibase_infra/types/type_dsn.py +173 -0
- omnibase_infra/types/type_infra_aliases.py +60 -0
- omnibase_infra/types/typed_dict/__init__.py +29 -0
- omnibase_infra/types/typed_dict/typed_dict_envelope_build_params.py +115 -0
- omnibase_infra/types/typed_dict/typed_dict_introspection_cache.py +128 -0
- omnibase_infra/types/typed_dict/typed_dict_performance_metrics_cache.py +140 -0
- omnibase_infra/types/typed_dict_capabilities.py +64 -0
- omnibase_infra/utils/__init__.py +117 -0
- omnibase_infra/utils/correlation.py +208 -0
- omnibase_infra/utils/util_atomic_file.py +261 -0
- omnibase_infra/utils/util_consumer_group.py +232 -0
- omnibase_infra/utils/util_datetime.py +372 -0
- omnibase_infra/utils/util_db_transaction.py +239 -0
- omnibase_infra/utils/util_dsn_validation.py +333 -0
- omnibase_infra/utils/util_env_parsing.py +264 -0
- omnibase_infra/utils/util_error_sanitization.py +457 -0
- omnibase_infra/utils/util_pydantic_validators.py +477 -0
- omnibase_infra/utils/util_retry_optimistic.py +281 -0
- omnibase_infra/utils/util_semver.py +233 -0
- omnibase_infra/validation/__init__.py +307 -0
- omnibase_infra/validation/contracts/security.validation.yaml +114 -0
- omnibase_infra/validation/enums/__init__.py +11 -0
- omnibase_infra/validation/enums/enum_contract_violation_severity.py +13 -0
- omnibase_infra/validation/infra_validators.py +1514 -0
- omnibase_infra/validation/linter_contract.py +907 -0
- omnibase_infra/validation/mixin_any_type_classification.py +120 -0
- omnibase_infra/validation/mixin_any_type_exemption.py +580 -0
- omnibase_infra/validation/mixin_any_type_reporting.py +106 -0
- omnibase_infra/validation/mixin_execution_shape_violation_checks.py +596 -0
- omnibase_infra/validation/mixin_node_archetype_detection.py +254 -0
- omnibase_infra/validation/models/__init__.py +15 -0
- omnibase_infra/validation/models/model_contract_lint_result.py +101 -0
- omnibase_infra/validation/models/model_contract_violation.py +41 -0
- omnibase_infra/validation/service_validation_aggregator.py +395 -0
- omnibase_infra/validation/validation_exemptions.yaml +2033 -0
- omnibase_infra/validation/validator_any_type.py +715 -0
- omnibase_infra/validation/validator_chain_propagation.py +839 -0
- omnibase_infra/validation/validator_execution_shape.py +465 -0
- omnibase_infra/validation/validator_localhandler.py +261 -0
- omnibase_infra/validation/validator_registration_security.py +410 -0
- omnibase_infra/validation/validator_routing_coverage.py +1020 -0
- omnibase_infra/validation/validator_runtime_shape.py +915 -0
- omnibase_infra/validation/validator_security.py +513 -0
- omnibase_infra/validation/validator_topic_category.py +1152 -0
- omnibase_infra-0.2.6.dist-info/METADATA +197 -0
- omnibase_infra-0.2.6.dist-info/RECORD +833 -0
- omnibase_infra-0.2.6.dist-info/WHEEL +4 -0
- omnibase_infra-0.2.6.dist-info/entry_points.txt +5 -0
- omnibase_infra-0.2.6.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,809 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Structured logging sink implementation using structlog.
|
|
4
|
+
|
|
5
|
+
This module provides a structured logging sink that implements the
|
|
6
|
+
ProtocolHotPathLoggingSink protocol. It buffers log entries in memory
|
|
7
|
+
and flushes them to structlog with JSON formatting.
|
|
8
|
+
|
|
9
|
+
Output Format Policy:
|
|
10
|
+
**JSON-Only Recommended for Production**
|
|
11
|
+
|
|
12
|
+
The sink supports two output formats controlled by the ``output_format`` parameter:
|
|
13
|
+
|
|
14
|
+
- **json** (default): Machine-readable JSON format for production environments.
|
|
15
|
+
Each log line is a complete JSON object suitable for ingestion by log
|
|
16
|
+
aggregators (ELK, Loki, Datadog, etc.). This format guarantees:
|
|
17
|
+
|
|
18
|
+
- Valid JSON on every line (parseable by ``json.loads()``)
|
|
19
|
+
- Consistent field ordering for diffing/comparison
|
|
20
|
+
- UTF-8 encoding with proper escaping
|
|
21
|
+
- No control characters or newlines within values
|
|
22
|
+
|
|
23
|
+
- **console**: Human-readable colored output for local development only.
|
|
24
|
+
This format is NOT suitable for log aggregation and may produce output
|
|
25
|
+
that is not valid JSON.
|
|
26
|
+
|
|
27
|
+
**stdlib Logger Integration**:
|
|
28
|
+
The sink uses structlog's PrintLogger (writes to stdout) by default.
|
|
29
|
+
For integration with Python's stdlib logging:
|
|
30
|
+
|
|
31
|
+
1. Configure structlog's stdlib integration at application startup
|
|
32
|
+
2. Use structlog.wrap_logger() with a stdlib LoggerFactory
|
|
33
|
+
3. This sink avoids structlog.configure() to prevent global state conflicts
|
|
34
|
+
|
|
35
|
+
Example stdlib integration::
|
|
36
|
+
|
|
37
|
+
import logging
|
|
38
|
+
import structlog
|
|
39
|
+
|
|
40
|
+
# Configure stdlib logging
|
|
41
|
+
logging.basicConfig(level=logging.INFO)
|
|
42
|
+
|
|
43
|
+
# Create sink with JSON output
|
|
44
|
+
sink = SinkLoggingStructured(output_format="json")
|
|
45
|
+
|
|
46
|
+
Required Context Keys:
|
|
47
|
+
The sink automatically adds the following keys to every log entry (callers
|
|
48
|
+
should NOT include these as they will be overwritten):
|
|
49
|
+
|
|
50
|
+
- ``original_timestamp``: ISO-8601 timestamp when emit() was called
|
|
51
|
+
- ``level``: Log level string (added by structlog.stdlib.add_log_level)
|
|
52
|
+
- ``timestamp``: ISO-8601 timestamp when flush() was called (added by TimeStamper)
|
|
53
|
+
|
|
54
|
+
**Recommended Context Keys** (callers SHOULD include for observability):
|
|
55
|
+
|
|
56
|
+
- ``correlation_id``: UUID for distributed tracing across services
|
|
57
|
+
- ``node_id``: ONEX node identifier (e.g., "node_registration_orchestrator")
|
|
58
|
+
- ``operation``: Current operation name (e.g., "validate_contract")
|
|
59
|
+
|
|
60
|
+
Missing recommended keys will trigger a warning log at DEBUG level to help
|
|
61
|
+
identify callers that may benefit from adding tracing context.
|
|
62
|
+
|
|
63
|
+
Buffer Management:
|
|
64
|
+
The sink maintains a thread-safe buffer of log entries. When the buffer
|
|
65
|
+
reaches capacity, oldest entries are dropped to make room for new ones
|
|
66
|
+
(drop_oldest policy). This ensures the sink never blocks on emit() due
|
|
67
|
+
to buffer fullness.
|
|
68
|
+
|
|
69
|
+
Thread Safety:
|
|
70
|
+
All buffer operations are protected by a threading.Lock. The emit() method
|
|
71
|
+
acquires the lock briefly to append entries, while flush() acquires the
|
|
72
|
+
lock to copy and clear the buffer before releasing it to perform I/O.
|
|
73
|
+
This design minimizes lock contention in hot paths.
|
|
74
|
+
|
|
75
|
+
Instance Isolation:
|
|
76
|
+
This implementation uses structlog.wrap_logger() instead of structlog.configure()
|
|
77
|
+
to create instance-specific loggers. This design choice ensures:
|
|
78
|
+
|
|
79
|
+
- **No global state modification**: Safe for libraries and multi-tenant apps
|
|
80
|
+
- **Multiple instances can coexist**: Different output formats per instance
|
|
81
|
+
- **No configuration conflicts**: Test environments remain isolated
|
|
82
|
+
- **Thread-safe**: Each instance has its own processor chain
|
|
83
|
+
|
|
84
|
+
WARNING: If your application calls structlog.configure() elsewhere, those
|
|
85
|
+
settings may affect the underlying logger behavior. This sink's wrap_logger()
|
|
86
|
+
approach isolates the processor chain but not the base logger configuration.
|
|
87
|
+
|
|
88
|
+
Fallback Behavior:
|
|
89
|
+
If structlog fails during flush, the sink falls back to writing directly
|
|
90
|
+
to stderr to ensure log entries are never silently lost.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
from __future__ import annotations
|
|
94
|
+
|
|
95
|
+
import json
|
|
96
|
+
import sys
|
|
97
|
+
import threading
|
|
98
|
+
import warnings
|
|
99
|
+
from collections import deque
|
|
100
|
+
from datetime import UTC, datetime
|
|
101
|
+
from typing import Literal
|
|
102
|
+
|
|
103
|
+
# Dependency validation for structlog with clear error message
|
|
104
|
+
_STRUCTLOG_AVAILABLE: bool = False
|
|
105
|
+
_STRUCTLOG_IMPORT_ERROR: str | None = None
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
import structlog
|
|
109
|
+
|
|
110
|
+
_STRUCTLOG_AVAILABLE = True
|
|
111
|
+
except ImportError as e:
|
|
112
|
+
_STRUCTLOG_IMPORT_ERROR = str(e)
|
|
113
|
+
# Provide stub for type checking when structlog is not installed
|
|
114
|
+
structlog = None # type: ignore[assignment]
|
|
115
|
+
|
|
116
|
+
from omnibase_core.enums import EnumLogLevel
|
|
117
|
+
from omnibase_core.types import JsonType
|
|
118
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
119
|
+
from omnibase_infra.errors import ModelInfraErrorContext, ProtocolConfigurationError
|
|
120
|
+
from omnibase_infra.observability.models.enum_required_log_context_key import (
|
|
121
|
+
EnumRequiredLogContextKey,
|
|
122
|
+
)
|
|
123
|
+
from omnibase_infra.observability.models.model_buffered_log_entry import (
|
|
124
|
+
ModelBufferedLogEntry,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Mapping from EnumLogLevel string values to structlog methods
|
|
128
|
+
# This is resolved at flush time, not import time, to avoid import issues
|
|
129
|
+
_STRUCTLOG_LEVEL_MAP: dict[str, str] = {
|
|
130
|
+
"trace": "debug", # structlog doesn't have trace, map to debug
|
|
131
|
+
"debug": "debug",
|
|
132
|
+
"info": "info",
|
|
133
|
+
"warning": "warning",
|
|
134
|
+
"error": "error",
|
|
135
|
+
"critical": "critical",
|
|
136
|
+
"fatal": "critical", # structlog doesn't have fatal, map to critical
|
|
137
|
+
"success": "info", # success maps to info level
|
|
138
|
+
"unknown": "info", # unknown defaults to info
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Default values for required context keys when not provided
|
|
142
|
+
_DEFAULT_CORRELATION_ID = "00000000-0000-0000-0000-000000000000"
|
|
143
|
+
_DEFAULT_NODE_ID = "unknown"
|
|
144
|
+
_DEFAULT_OPERATION = "unknown"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class SinkLoggingStructured:
|
|
148
|
+
"""Structured logging sink implementing ProtocolHotPathLoggingSink.
|
|
149
|
+
|
|
150
|
+
This sink buffers log entries in memory and flushes them to structlog
|
|
151
|
+
with JSON formatting. It's designed for hot-path scenarios where
|
|
152
|
+
synchronous logging without blocking is critical.
|
|
153
|
+
|
|
154
|
+
Buffer Management:
|
|
155
|
+
- Configurable maximum buffer size (default: 1000 entries)
|
|
156
|
+
- When buffer is full, oldest entries are dropped (drop_oldest policy)
|
|
157
|
+
- Thread-safe: all operations use a lock for synchronization
|
|
158
|
+
|
|
159
|
+
Output Formats:
|
|
160
|
+
- json: Machine-readable JSON format (default, recommended for production)
|
|
161
|
+
- console: Human-readable colored console output (development only)
|
|
162
|
+
|
|
163
|
+
JSON Output Guarantee:
|
|
164
|
+
When output_format="json", every log line is guaranteed to be valid JSON:
|
|
165
|
+
- Parseable by json.loads()
|
|
166
|
+
- Single-line format (no embedded newlines)
|
|
167
|
+
- UTF-8 encoded with proper escaping
|
|
168
|
+
- Consistent field ordering
|
|
169
|
+
|
|
170
|
+
Fallback Behavior:
|
|
171
|
+
If structlog fails during flush, entries are written to stderr
|
|
172
|
+
to prevent silent data loss.
|
|
173
|
+
|
|
174
|
+
Attributes:
|
|
175
|
+
max_buffer_size: Maximum number of entries to buffer before dropping.
|
|
176
|
+
output_format: Output format ("json" or "console").
|
|
177
|
+
drop_policy: Buffer overflow policy (only "drop_oldest" supported).
|
|
178
|
+
drop_count: Number of entries dropped due to buffer overflow.
|
|
179
|
+
|
|
180
|
+
Example:
|
|
181
|
+
```python
|
|
182
|
+
from omnibase_core.enums import EnumLogLevel
|
|
183
|
+
|
|
184
|
+
# Create sink with custom buffer size (uses drop_oldest policy)
|
|
185
|
+
sink = SinkLoggingStructured(max_buffer_size=500)
|
|
186
|
+
|
|
187
|
+
# Hot path - emit without blocking
|
|
188
|
+
for item in large_dataset:
|
|
189
|
+
sink.emit(
|
|
190
|
+
EnumLogLevel.DEBUG,
|
|
191
|
+
f"Processed {item}",
|
|
192
|
+
{
|
|
193
|
+
"id": str(item.id),
|
|
194
|
+
"correlation_id": str(correlation_id), # Recommended
|
|
195
|
+
"node_id": "data_processor", # Recommended
|
|
196
|
+
"operation": "process_batch", # Recommended
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Flush when hot path completes
|
|
201
|
+
sink.flush()
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Thread Safety:
|
|
205
|
+
This implementation is THREAD-SAFE. Multiple threads may call emit()
|
|
206
|
+
and flush() concurrently. The lock is held briefly during emit() and
|
|
207
|
+
released before I/O during flush().
|
|
208
|
+
|
|
209
|
+
Global State:
|
|
210
|
+
This implementation intentionally avoids calling structlog.configure(),
|
|
211
|
+
which modifies global state. Instead, each instance uses structlog.wrap_logger()
|
|
212
|
+
to create an instance-specific logger with its own processor chain. This design:
|
|
213
|
+
|
|
214
|
+
- Allows multiple instances with different output formats (json vs console)
|
|
215
|
+
- Prevents configuration conflicts in multi-tenant or test environments
|
|
216
|
+
- Follows library best practices for not modifying global logging config
|
|
217
|
+
|
|
218
|
+
WARNING: If other code in your application calls structlog.configure(),
|
|
219
|
+
that may affect the underlying logger behavior. This sink isolates the
|
|
220
|
+
processor chain via wrap_logger() but cannot isolate base logger config.
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
# Class-level tracking for missing context key warnings
|
|
224
|
+
# Used to warn once per session about missing recommended keys
|
|
225
|
+
_warned_missing_keys: set[str] = set()
|
|
226
|
+
|
|
227
|
+
# Instance tracking for global state conflict detection
|
|
228
|
+
# When multiple instances exist, warn users about potential conflicts
|
|
229
|
+
_instance_count: int = 0
|
|
230
|
+
_warned_multiple_instances: bool = False
|
|
231
|
+
|
|
232
|
+
def __init__(
|
|
233
|
+
self,
|
|
234
|
+
max_buffer_size: int = 1000,
|
|
235
|
+
output_format: str = "json",
|
|
236
|
+
drop_policy: Literal["drop_oldest"] = "drop_oldest",
|
|
237
|
+
warn_on_missing_recommended_keys: bool = True,
|
|
238
|
+
) -> None:
|
|
239
|
+
"""Initialize the structured logging sink.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
max_buffer_size: Maximum number of log entries to buffer.
|
|
243
|
+
When exceeded, oldest entries are dropped. Default: 1000.
|
|
244
|
+
output_format: Output format for log entries.
|
|
245
|
+
- "json": JSON format (default, machine-readable, production-ready)
|
|
246
|
+
- "console": Colored console output (human-readable, dev only)
|
|
247
|
+
drop_policy: Policy for handling buffer overflow. Currently only
|
|
248
|
+
"drop_oldest" is supported, which drops the oldest entries
|
|
249
|
+
when the buffer is full. Default: "drop_oldest".
|
|
250
|
+
warn_on_missing_recommended_keys: If True (default), emit a warning
|
|
251
|
+
to stderr when recommended context keys (correlation_id, node_id,
|
|
252
|
+
operation) are missing. Set to False to suppress these warnings.
|
|
253
|
+
|
|
254
|
+
Raises:
|
|
255
|
+
ProtocolConfigurationError: If structlog is not installed (install with:
|
|
256
|
+
pip install structlog), max_buffer_size is less than 1, or
|
|
257
|
+
output_format is not recognized. Includes correlation_id for
|
|
258
|
+
distributed tracing.
|
|
259
|
+
|
|
260
|
+
Note:
|
|
261
|
+
The drop_oldest policy is implemented using a collections.deque with
|
|
262
|
+
maxlen set to max_buffer_size. When the buffer is full and a new entry
|
|
263
|
+
is added, the deque automatically discards the oldest entry from the
|
|
264
|
+
left side. This provides O(1) performance for both append and drop
|
|
265
|
+
operations.
|
|
266
|
+
"""
|
|
267
|
+
# Validate dependency is available with clear error message
|
|
268
|
+
if not _STRUCTLOG_AVAILABLE:
|
|
269
|
+
context = ModelInfraErrorContext.with_correlation(
|
|
270
|
+
transport_type=EnumInfraTransportType.RUNTIME,
|
|
271
|
+
operation="initialize_logging_sink",
|
|
272
|
+
)
|
|
273
|
+
raise ProtocolConfigurationError(
|
|
274
|
+
"structlog is required for SinkLoggingStructured but is not installed. "
|
|
275
|
+
f"Install with: pip install structlog. "
|
|
276
|
+
f"Original error: {_STRUCTLOG_IMPORT_ERROR}",
|
|
277
|
+
context=context,
|
|
278
|
+
dependency="structlog",
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
if max_buffer_size < 1:
|
|
282
|
+
context = ModelInfraErrorContext.with_correlation(
|
|
283
|
+
transport_type=EnumInfraTransportType.RUNTIME,
|
|
284
|
+
operation="initialize_logging_sink",
|
|
285
|
+
)
|
|
286
|
+
raise ProtocolConfigurationError(
|
|
287
|
+
f"max_buffer_size must be >= 1, got {max_buffer_size}",
|
|
288
|
+
context=context,
|
|
289
|
+
parameter="max_buffer_size",
|
|
290
|
+
value=max_buffer_size,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
if output_format not in ("json", "console"):
|
|
294
|
+
context = ModelInfraErrorContext.with_correlation(
|
|
295
|
+
transport_type=EnumInfraTransportType.RUNTIME,
|
|
296
|
+
operation="initialize_logging_sink",
|
|
297
|
+
)
|
|
298
|
+
raise ProtocolConfigurationError(
|
|
299
|
+
f"output_format must be 'json' or 'console', got '{output_format}'",
|
|
300
|
+
context=context,
|
|
301
|
+
parameter="output_format",
|
|
302
|
+
value=output_format,
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
self._max_buffer_size = max_buffer_size
|
|
306
|
+
self._output_format = output_format
|
|
307
|
+
self._drop_policy: Literal["drop_oldest"] = drop_policy
|
|
308
|
+
self._warn_on_missing_keys = warn_on_missing_recommended_keys
|
|
309
|
+
# Use deque with maxlen to automatically drop oldest entries when full
|
|
310
|
+
self._buffer: deque[ModelBufferedLogEntry] = deque(maxlen=max_buffer_size)
|
|
311
|
+
self._lock = threading.Lock()
|
|
312
|
+
self._drop_count = 0
|
|
313
|
+
self._logger = self._configure_structlog()
|
|
314
|
+
|
|
315
|
+
# Track instances and warn about potential global state conflicts
|
|
316
|
+
self._track_instance_creation()
|
|
317
|
+
|
|
318
|
+
def _configure_structlog(self) -> structlog.BoundLogger:
|
|
319
|
+
"""Configure and return a structlog logger instance.
|
|
320
|
+
|
|
321
|
+
This method creates an instance-specific logger using structlog.wrap_logger()
|
|
322
|
+
instead of structlog.configure(). This is a critical design choice that:
|
|
323
|
+
|
|
324
|
+
1. **Avoids global state**: structlog.configure() modifies module-level state,
|
|
325
|
+
which would cause conflicts when multiple SinkLoggingStructured instances
|
|
326
|
+
exist with different output formats (e.g., JSON for production, console
|
|
327
|
+
for local debugging).
|
|
328
|
+
|
|
329
|
+
2. **Enables library safety**: Library code should never modify global logging
|
|
330
|
+
configuration, as this can unexpectedly affect the host application.
|
|
331
|
+
|
|
332
|
+
3. **Supports testing**: Tests can create multiple instances with different
|
|
333
|
+
configurations without cleanup/teardown concerns.
|
|
334
|
+
|
|
335
|
+
Processor Chain:
|
|
336
|
+
The processor chain is configured per-instance:
|
|
337
|
+
- add_log_level: Adds 'level' key to every log entry
|
|
338
|
+
- TimeStamper: Adds ISO-8601 'timestamp' at flush time
|
|
339
|
+
- StackInfoRenderer: Formats stack traces when present
|
|
340
|
+
- UnicodeDecoder: Ensures proper Unicode handling
|
|
341
|
+
- JSONRenderer or ConsoleRenderer: Final output formatting
|
|
342
|
+
|
|
343
|
+
JSON Output Enforcement:
|
|
344
|
+
When output_format="json", the JSONRenderer ensures:
|
|
345
|
+
- Valid JSON on every line (can be parsed by json.loads)
|
|
346
|
+
- Proper escaping of special characters
|
|
347
|
+
- UTF-8 encoding
|
|
348
|
+
- No embedded newlines (single-line format)
|
|
349
|
+
|
|
350
|
+
Returns:
|
|
351
|
+
Configured structlog BoundLogger instance with instance-specific processors.
|
|
352
|
+
|
|
353
|
+
Note:
|
|
354
|
+
Using wrap_logger() is the recommended pattern for library code that
|
|
355
|
+
should not modify global logging configuration. Each instance gets
|
|
356
|
+
its own processor chain based on its output_format setting. This means
|
|
357
|
+
two instances can coexist: one writing JSON to a file, another writing
|
|
358
|
+
colored console output for debugging.
|
|
359
|
+
|
|
360
|
+
WARNING: structlog.configure() called elsewhere in your application
|
|
361
|
+
may still affect the underlying logger behavior. This sink's approach
|
|
362
|
+
isolates the processor chain but not the base PrintLogger configuration.
|
|
363
|
+
"""
|
|
364
|
+
# Configure processors based on output format
|
|
365
|
+
processors: list[structlog.types.Processor] = [
|
|
366
|
+
structlog.stdlib.add_log_level,
|
|
367
|
+
structlog.processors.TimeStamper(fmt="iso"),
|
|
368
|
+
structlog.processors.StackInfoRenderer(),
|
|
369
|
+
structlog.processors.UnicodeDecoder(),
|
|
370
|
+
]
|
|
371
|
+
|
|
372
|
+
if self._output_format == "json":
|
|
373
|
+
processors.append(structlog.processors.JSONRenderer())
|
|
374
|
+
else:
|
|
375
|
+
processors.append(structlog.dev.ConsoleRenderer(colors=True))
|
|
376
|
+
|
|
377
|
+
# Use wrap_logger() to create an instance-specific logger without
|
|
378
|
+
# modifying global state. This prevents conflicts when multiple
|
|
379
|
+
# instances are created with different output formats.
|
|
380
|
+
# The PrintLogger writes to stdout by default.
|
|
381
|
+
logger: structlog.BoundLogger = structlog.wrap_logger(
|
|
382
|
+
structlog.PrintLogger(),
|
|
383
|
+
processors=processors,
|
|
384
|
+
wrapper_class=structlog.BoundLogger,
|
|
385
|
+
context_class=dict,
|
|
386
|
+
)
|
|
387
|
+
return logger
|
|
388
|
+
|
|
389
|
+
def _track_instance_creation(self) -> None:
|
|
390
|
+
"""Track instance creation and warn about potential global state conflicts.
|
|
391
|
+
|
|
392
|
+
This method increments the class-level instance counter and emits a
|
|
393
|
+
warning when multiple instances are detected. While this sink uses
|
|
394
|
+
structlog.wrap_logger() to avoid global state modification, the warning
|
|
395
|
+
helps users understand that:
|
|
396
|
+
|
|
397
|
+
1. Multiple instances with different output formats can coexist safely
|
|
398
|
+
2. If other code calls structlog.configure(), it may affect all instances
|
|
399
|
+
3. Base logger configuration (PrintLogger) is shared
|
|
400
|
+
|
|
401
|
+
The warning is emitted once per process to avoid log spam.
|
|
402
|
+
|
|
403
|
+
Note:
|
|
404
|
+
This is a best-effort detection mechanism. In multi-threaded code,
|
|
405
|
+
the instance count may not be perfectly accurate, but this is
|
|
406
|
+
acceptable since the warning is informational only.
|
|
407
|
+
"""
|
|
408
|
+
SinkLoggingStructured._instance_count += 1
|
|
409
|
+
|
|
410
|
+
if (
|
|
411
|
+
SinkLoggingStructured._instance_count > 1
|
|
412
|
+
and not SinkLoggingStructured._warned_multiple_instances
|
|
413
|
+
):
|
|
414
|
+
SinkLoggingStructured._warned_multiple_instances = True
|
|
415
|
+
warnings.warn(
|
|
416
|
+
f"Multiple SinkLoggingStructured instances detected "
|
|
417
|
+
f"(count: {SinkLoggingStructured._instance_count}). "
|
|
418
|
+
f"While each instance has isolated processor chains via wrap_logger(), "
|
|
419
|
+
f"be aware that: (1) structlog.configure() called elsewhere may affect "
|
|
420
|
+
f"all instances, (2) all instances share the same base PrintLogger. "
|
|
421
|
+
f"This is typically fine but may cause unexpected behavior if you "
|
|
422
|
+
f"rely on global structlog configuration.",
|
|
423
|
+
stacklevel=3, # Points to user code that called SinkLoggingStructured()
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
@property
|
|
427
|
+
def max_buffer_size(self) -> int:
|
|
428
|
+
"""Maximum number of entries the buffer can hold."""
|
|
429
|
+
return self._max_buffer_size
|
|
430
|
+
|
|
431
|
+
@property
|
|
432
|
+
def output_format(self) -> str:
|
|
433
|
+
"""Current output format ('json' or 'console')."""
|
|
434
|
+
return self._output_format
|
|
435
|
+
|
|
436
|
+
@property
|
|
437
|
+
def drop_policy(self) -> Literal["drop_oldest"]:
|
|
438
|
+
"""Current drop policy for buffer overflow handling."""
|
|
439
|
+
return self._drop_policy
|
|
440
|
+
|
|
441
|
+
@property
|
|
442
|
+
def drop_count(self) -> int:
|
|
443
|
+
"""Number of entries dropped due to buffer overflow.
|
|
444
|
+
|
|
445
|
+
This counter is incremented each time an entry is dropped
|
|
446
|
+
because the buffer is full. It can be used to monitor
|
|
447
|
+
if the buffer size is adequate for the workload.
|
|
448
|
+
|
|
449
|
+
Guarantees:
|
|
450
|
+
- Always non-negative (initialized to 0, only incremented)
|
|
451
|
+
- Thread-safe (protected by lock)
|
|
452
|
+
|
|
453
|
+
Returns:
|
|
454
|
+
Non-negative integer count of dropped entries.
|
|
455
|
+
"""
|
|
456
|
+
with self._lock:
|
|
457
|
+
return self._drop_count
|
|
458
|
+
|
|
459
|
+
@property
|
|
460
|
+
def buffer_size(self) -> int:
|
|
461
|
+
"""Current number of entries in the buffer.
|
|
462
|
+
|
|
463
|
+
Guarantees:
|
|
464
|
+
- Always non-negative (0 <= buffer_size <= max_buffer_size)
|
|
465
|
+
- Thread-safe (protected by lock)
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
Non-negative integer count of buffered entries.
|
|
469
|
+
"""
|
|
470
|
+
with self._lock:
|
|
471
|
+
return len(self._buffer)
|
|
472
|
+
|
|
473
|
+
def emit(
|
|
474
|
+
self,
|
|
475
|
+
level: EnumLogLevel,
|
|
476
|
+
message: str,
|
|
477
|
+
context: dict[str, JsonType],
|
|
478
|
+
) -> None:
|
|
479
|
+
"""Buffer a log entry for later emission.
|
|
480
|
+
|
|
481
|
+
Synchronously buffers a log entry without performing any I/O.
|
|
482
|
+
This method MUST NOT block, perform network calls, or write to disk.
|
|
483
|
+
All I/O is deferred until flush() is called.
|
|
484
|
+
|
|
485
|
+
If the buffer is full, the oldest entry is dropped to make room
|
|
486
|
+
for the new entry (drop_oldest policy). The drop_count property
|
|
487
|
+
tracks how many entries have been dropped.
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
level: Log level from EnumLogLevel (TRACE, DEBUG, INFO, WARNING,
|
|
491
|
+
ERROR, CRITICAL, FATAL, SUCCESS, UNKNOWN).
|
|
492
|
+
message: Log message content. Should be a complete, self-contained
|
|
493
|
+
message suitable for structured logging.
|
|
494
|
+
context: Structured context data for the log entry. Values may be
|
|
495
|
+
any JSON-compatible type (str, int, float, bool, None,
|
|
496
|
+
list, dict). This enables richer context than string-only:
|
|
497
|
+
|
|
498
|
+
```python
|
|
499
|
+
context = {
|
|
500
|
+
"correlation_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
501
|
+
"retry_count": 3, # int is valid
|
|
502
|
+
"duration_ms": 42.5, # float is valid
|
|
503
|
+
"is_retry": True, # bool is valid
|
|
504
|
+
"tags": ["hot-path", "db"], # list is valid
|
|
505
|
+
"metadata": {"version": 1}, # dict is valid
|
|
506
|
+
}
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
Automatically Added Keys:
|
|
510
|
+
The sink automatically adds these keys (callers should NOT include them):
|
|
511
|
+
- ``original_timestamp``: ISO-8601 timestamp captured at emit() time
|
|
512
|
+
- ``level``: Log level string (added by structlog processor)
|
|
513
|
+
- ``timestamp``: ISO-8601 timestamp at flush() time (added by structlog)
|
|
514
|
+
|
|
515
|
+
Recommended Context Keys:
|
|
516
|
+
For effective observability, callers SHOULD include:
|
|
517
|
+
- ``correlation_id``: UUID for distributed tracing across services
|
|
518
|
+
- ``node_id``: ONEX node identifier (e.g., "node_registration_orchestrator")
|
|
519
|
+
- ``operation``: Current operation name (e.g., "validate_contract")
|
|
520
|
+
|
|
521
|
+
Example with recommended keys:
|
|
522
|
+
```python
|
|
523
|
+
sink.emit(
|
|
524
|
+
level=EnumLogLevel.INFO,
|
|
525
|
+
message="Contract validation completed",
|
|
526
|
+
context={
|
|
527
|
+
"correlation_id": str(correlation_id),
|
|
528
|
+
"node_id": "node_contract_validator",
|
|
529
|
+
"operation": "validate_contract",
|
|
530
|
+
"contract_path": "/path/to/contract.yaml",
|
|
531
|
+
"validation_result": "passed",
|
|
532
|
+
}
|
|
533
|
+
)
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
Note:
|
|
537
|
+
This method is synchronous (def, not async def) by design.
|
|
538
|
+
It MUST complete without blocking to maintain hot-path performance.
|
|
539
|
+
|
|
540
|
+
Example:
|
|
541
|
+
```python
|
|
542
|
+
sink.emit(
|
|
543
|
+
level=EnumLogLevel.INFO,
|
|
544
|
+
message="Cache hit for user lookup",
|
|
545
|
+
context={
|
|
546
|
+
"user_id": "u_123",
|
|
547
|
+
"cache_key": "user:u_123",
|
|
548
|
+
"correlation_id": str(correlation_id),
|
|
549
|
+
}
|
|
550
|
+
)
|
|
551
|
+
```
|
|
552
|
+
"""
|
|
553
|
+
# Create immutable Pydantic model for thread-safe buffering
|
|
554
|
+
entry = ModelBufferedLogEntry(
|
|
555
|
+
level=level,
|
|
556
|
+
message=message,
|
|
557
|
+
context=dict(context), # Defensive copy to prevent mutation
|
|
558
|
+
timestamp=datetime.now(UTC),
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
with self._lock:
|
|
562
|
+
# deque with maxlen automatically drops oldest when full
|
|
563
|
+
if len(self._buffer) >= self._max_buffer_size:
|
|
564
|
+
self._drop_count += 1
|
|
565
|
+
self._buffer.append(entry)
|
|
566
|
+
|
|
567
|
+
def flush(self) -> None:
|
|
568
|
+
"""Flush all buffered log entries to structlog.
|
|
569
|
+
|
|
570
|
+
This is the ONLY method in this protocol that may perform I/O.
|
|
571
|
+
All buffered log entries are written to the configured structlog
|
|
572
|
+
backend and the buffer is cleared.
|
|
573
|
+
|
|
574
|
+
The flush process:
|
|
575
|
+
1. Acquire lock and copy all entries from buffer
|
|
576
|
+
2. Clear the buffer
|
|
577
|
+
3. Release the lock
|
|
578
|
+
4. Validate required context keys (warn on missing recommended keys)
|
|
579
|
+
5. Write entries to structlog (I/O happens outside the lock)
|
|
580
|
+
6. On error, fall back to stderr
|
|
581
|
+
|
|
582
|
+
Required Context Keys Validation:
|
|
583
|
+
At flush time, the sink validates that required keys are present
|
|
584
|
+
and warns about missing recommended keys. This is done at flush
|
|
585
|
+
time (not emit time) to maintain hot-path performance.
|
|
586
|
+
|
|
587
|
+
**Always present** (added by sink):
|
|
588
|
+
- original_timestamp
|
|
589
|
+
- level (via structlog)
|
|
590
|
+
- timestamp (via structlog)
|
|
591
|
+
|
|
592
|
+
**Recommended** (warning if missing):
|
|
593
|
+
- correlation_id
|
|
594
|
+
- node_id
|
|
595
|
+
- operation
|
|
596
|
+
|
|
597
|
+
Thread-Safety:
|
|
598
|
+
This method is safe to call concurrently with emit().
|
|
599
|
+
The lock is held only during the copy/clear phase, not during I/O.
|
|
600
|
+
|
|
601
|
+
Error Handling:
|
|
602
|
+
If structlog fails during emission, the sink falls back to
|
|
603
|
+
writing entries directly to stderr to prevent data loss.
|
|
604
|
+
Errors during stderr fallback are silently ignored to prevent
|
|
605
|
+
cascading failures.
|
|
606
|
+
|
|
607
|
+
Example:
|
|
608
|
+
```python
|
|
609
|
+
# Periodic flush in a long-running process
|
|
610
|
+
while processing:
|
|
611
|
+
batch = get_next_batch()
|
|
612
|
+
process_batch(batch, sink)
|
|
613
|
+
|
|
614
|
+
# Flush every N iterations
|
|
615
|
+
if iteration % 100 == 0:
|
|
616
|
+
sink.flush()
|
|
617
|
+
|
|
618
|
+
# Final flush on shutdown
|
|
619
|
+
sink.flush()
|
|
620
|
+
```
|
|
621
|
+
"""
|
|
622
|
+
# Copy entries under lock, then release lock before I/O
|
|
623
|
+
with self._lock:
|
|
624
|
+
entries = list(self._buffer)
|
|
625
|
+
self._buffer.clear()
|
|
626
|
+
|
|
627
|
+
# Process entries outside the lock to minimize contention
|
|
628
|
+
for entry in entries:
|
|
629
|
+
self._validate_context_keys(entry)
|
|
630
|
+
self._emit_entry(entry)
|
|
631
|
+
|
|
632
|
+
def _validate_context_keys(self, entry: ModelBufferedLogEntry) -> None:
|
|
633
|
+
"""Validate that required/recommended context keys are present.
|
|
634
|
+
|
|
635
|
+
This method checks for recommended context keys and emits warnings
|
|
636
|
+
(once per key per session) when they are missing. Validation is
|
|
637
|
+
performed at flush time to avoid impacting hot-path performance.
|
|
638
|
+
|
|
639
|
+
Args:
|
|
640
|
+
entry: The buffered log entry to validate.
|
|
641
|
+
|
|
642
|
+
Note:
|
|
643
|
+
The warning is only emitted once per missing key per session
|
|
644
|
+
to avoid log spam. Missing keys are tracked in class-level
|
|
645
|
+
_warned_missing_keys set.
|
|
646
|
+
"""
|
|
647
|
+
if not self._warn_on_missing_keys:
|
|
648
|
+
return
|
|
649
|
+
|
|
650
|
+
recommended = EnumRequiredLogContextKey.recommended_keys()
|
|
651
|
+
present_keys = set(entry.context.keys())
|
|
652
|
+
missing = recommended - present_keys
|
|
653
|
+
|
|
654
|
+
# Warn once per missing key to avoid spam
|
|
655
|
+
for key in missing:
|
|
656
|
+
if key not in SinkLoggingStructured._warned_missing_keys:
|
|
657
|
+
SinkLoggingStructured._warned_missing_keys.add(key)
|
|
658
|
+
warnings.warn(
|
|
659
|
+
f"Recommended context key '{key}' missing from log entry. "
|
|
660
|
+
f"Including {', '.join(sorted(recommended))} improves observability.",
|
|
661
|
+
stacklevel=3, # Points to user code that called flush()
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
def _emit_entry(self, entry: ModelBufferedLogEntry) -> None:
|
|
665
|
+
"""Emit a single log entry to structlog.
|
|
666
|
+
|
|
667
|
+
This method maps the EnumLogLevel to the appropriate structlog method
|
|
668
|
+
and constructs the final context dict with required keys.
|
|
669
|
+
|
|
670
|
+
Args:
|
|
671
|
+
entry: The buffered log entry to emit.
|
|
672
|
+
|
|
673
|
+
Required Context Keys (always present in output):
|
|
674
|
+
The following keys are GUARANTEED to be present in every log entry.
|
|
675
|
+
If not provided by the caller, defaults are applied:
|
|
676
|
+
|
|
677
|
+
- ``original_timestamp``: ISO-8601 timestamp from emit() time
|
|
678
|
+
- ``correlation_id``: Default "00000000-0000-0000-0000-000000000000" if missing
|
|
679
|
+
- ``node_id``: Default "unknown" if missing
|
|
680
|
+
- ``operation``: Default "unknown" if missing
|
|
681
|
+
|
|
682
|
+
The structlog processor chain adds additional keys:
|
|
683
|
+
- ``level``: Log level string (via add_log_level processor)
|
|
684
|
+
- ``timestamp``: ISO-8601 timestamp at flush time (via TimeStamper)
|
|
685
|
+
|
|
686
|
+
JSON Output Guarantee:
|
|
687
|
+
When output_format="json", this method ensures valid JSON output:
|
|
688
|
+
- All context values are JSON-serializable (enforced by JsonType)
|
|
689
|
+
- Special characters are properly escaped
|
|
690
|
+
- Output is single-line (no embedded newlines)
|
|
691
|
+
- All required keys are present with valid values
|
|
692
|
+
"""
|
|
693
|
+
# Map the log level to structlog method name
|
|
694
|
+
level_str = str(entry.level.value).lower()
|
|
695
|
+
structlog_level = _STRUCTLOG_LEVEL_MAP.get(level_str, "info")
|
|
696
|
+
|
|
697
|
+
# Build context dict with REQUIRED keys guaranteed present
|
|
698
|
+
# Apply defaults for recommended keys if not provided by caller
|
|
699
|
+
# All values are JsonType (JSON-compatible) for serialization safety
|
|
700
|
+
log_context: dict[str, JsonType] = {
|
|
701
|
+
# Always-present auto-added key
|
|
702
|
+
EnumRequiredLogContextKey.ORIGINAL_TIMESTAMP: entry.timestamp.isoformat(),
|
|
703
|
+
# Required keys with defaults (applied first, then overwritten by entry.context)
|
|
704
|
+
EnumRequiredLogContextKey.CORRELATION_ID: _DEFAULT_CORRELATION_ID,
|
|
705
|
+
EnumRequiredLogContextKey.NODE_ID: _DEFAULT_NODE_ID,
|
|
706
|
+
EnumRequiredLogContextKey.OPERATION: _DEFAULT_OPERATION,
|
|
707
|
+
}
|
|
708
|
+
# Caller-provided context overwrites defaults
|
|
709
|
+
log_context.update(entry.context)
|
|
710
|
+
|
|
711
|
+
try:
|
|
712
|
+
# Get the appropriate structlog method and call it
|
|
713
|
+
log_method = getattr(self._logger, structlog_level, self._logger.info)
|
|
714
|
+
log_method(entry.message, **log_context)
|
|
715
|
+
except (ValueError, TypeError, AttributeError, OSError):
|
|
716
|
+
# Fall back to stderr if structlog fails due to:
|
|
717
|
+
# - ValueError: invalid arguments to log methods
|
|
718
|
+
# - TypeError: type mismatches in context values
|
|
719
|
+
# - AttributeError: missing log method on logger
|
|
720
|
+
# - OSError: I/O errors when writing to stdout
|
|
721
|
+
self._emit_to_stderr(entry, structlog_level)
|
|
722
|
+
|
|
723
|
+
def _emit_to_stderr(self, entry: ModelBufferedLogEntry, level: str) -> None:
|
|
724
|
+
"""Fall back to stderr when structlog fails.
|
|
725
|
+
|
|
726
|
+
This is the last-resort fallback to ensure log entries are not
|
|
727
|
+
silently lost when structlog encounters errors. Output is always
|
|
728
|
+
JSON format to maintain consistency with the primary output.
|
|
729
|
+
|
|
730
|
+
This fallback also ensures all required context keys are present
|
|
731
|
+
with defaults, maintaining the same guarantees as the primary path.
|
|
732
|
+
|
|
733
|
+
Args:
|
|
734
|
+
entry: The log entry to emit.
|
|
735
|
+
level: The log level string.
|
|
736
|
+
"""
|
|
737
|
+
try:
|
|
738
|
+
# Always emit JSON for fallback to ensure consistent format
|
|
739
|
+
# Include all required context keys with defaults (same as primary path)
|
|
740
|
+
fallback_entry: dict[str, JsonType] = {
|
|
741
|
+
EnumRequiredLogContextKey.TIMESTAMP: entry.timestamp.isoformat(),
|
|
742
|
+
EnumRequiredLogContextKey.LEVEL: level.upper(),
|
|
743
|
+
EnumRequiredLogContextKey.ORIGINAL_TIMESTAMP: entry.timestamp.isoformat(),
|
|
744
|
+
# Required keys with defaults
|
|
745
|
+
EnumRequiredLogContextKey.CORRELATION_ID: _DEFAULT_CORRELATION_ID,
|
|
746
|
+
EnumRequiredLogContextKey.NODE_ID: _DEFAULT_NODE_ID,
|
|
747
|
+
EnumRequiredLogContextKey.OPERATION: _DEFAULT_OPERATION,
|
|
748
|
+
"message": entry.message,
|
|
749
|
+
}
|
|
750
|
+
# Caller-provided context overwrites defaults
|
|
751
|
+
fallback_entry.update(entry.context)
|
|
752
|
+
# Use json.dumps for guaranteed valid JSON output
|
|
753
|
+
print(json.dumps(fallback_entry, default=str), file=sys.stderr)
|
|
754
|
+
except (ValueError, TypeError, OSError):
|
|
755
|
+
# Silently ignore errors in the fallback path to prevent cascading
|
|
756
|
+
# failures. Common errors: ValueError (string formatting),
|
|
757
|
+
# TypeError (type issues), OSError (stream write failures)
|
|
758
|
+
pass
|
|
759
|
+
|
|
760
|
+
def reset_drop_count(self) -> int:
|
|
761
|
+
"""Reset the drop counter and return the previous value.
|
|
762
|
+
|
|
763
|
+
This is useful for monitoring and alerting on buffer overflow
|
|
764
|
+
conditions in long-running processes.
|
|
765
|
+
|
|
766
|
+
Returns:
|
|
767
|
+
The number of entries that were dropped before the reset.
|
|
768
|
+
"""
|
|
769
|
+
with self._lock:
|
|
770
|
+
previous_count = self._drop_count
|
|
771
|
+
self._drop_count = 0
|
|
772
|
+
return previous_count
|
|
773
|
+
|
|
774
|
+
@classmethod
|
|
775
|
+
def reset_warning_state(cls) -> None:
|
|
776
|
+
"""Reset the class-level warning state.
|
|
777
|
+
|
|
778
|
+
This method clears the set of keys that have already triggered
|
|
779
|
+
warnings, allowing warnings to be emitted again. Useful for testing.
|
|
780
|
+
"""
|
|
781
|
+
cls._warned_missing_keys.clear()
|
|
782
|
+
|
|
783
|
+
@classmethod
|
|
784
|
+
def reset_instance_tracking(cls) -> int:
|
|
785
|
+
"""Reset the class-level instance tracking state.
|
|
786
|
+
|
|
787
|
+
This method resets the instance counter and warning flag.
|
|
788
|
+
Returns the previous instance count. Useful for testing.
|
|
789
|
+
|
|
790
|
+
Returns:
|
|
791
|
+
The number of instances that were tracked before the reset.
|
|
792
|
+
"""
|
|
793
|
+
previous_count = cls._instance_count
|
|
794
|
+
cls._instance_count = 0
|
|
795
|
+
cls._warned_multiple_instances = False
|
|
796
|
+
return previous_count
|
|
797
|
+
|
|
798
|
+
@classmethod
|
|
799
|
+
def get_instance_count(cls) -> int:
|
|
800
|
+
"""Get the current number of tracked instances.
|
|
801
|
+
|
|
802
|
+
Returns:
|
|
803
|
+
The number of SinkLoggingStructured instances created since
|
|
804
|
+
the last reset or process start.
|
|
805
|
+
"""
|
|
806
|
+
return cls._instance_count
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
__all__ = ["SinkLoggingStructured"]
|