springbootAI 1.8.5__tar.gz → 1.8.7__tar.gz
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.
- {springbootai-1.8.5/springbootAI.egg-info → springbootai-1.8.7}/PKG-INFO +1 -1
- {springbootai-1.8.5 → springbootai-1.8.7}/pyproject.toml +1 -1
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/__init__.py +1 -1
- springbootai-1.8.7/spring/logging/loguru_logger.py +437 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/main.py +145 -69
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/utils/banner.py +1 -1
- {springbootai-1.8.5 → springbootai-1.8.7/springbootAI.egg-info}/PKG-INFO +1 -1
- {springbootai-1.8.5 → springbootai-1.8.7}/springbootAI.egg-info/SOURCES.txt +1 -0
- springbootai-1.8.7/tests/test_component_init_error.py +171 -0
- springbootai-1.8.7/tests/test_logging_config.py +186 -0
- springbootai-1.8.5/spring/logging/loguru_logger.py +0 -272
- springbootai-1.8.5/tests/test_logging_config.py +0 -65
- {springbootai-1.8.5 → springbootai-1.8.7}/LICENSE +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/MANIFEST.in +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/README.md +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/requirements.txt +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/setup.cfg +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/setup.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/advisors.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/annotations.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/autoconfig.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/core.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/etl.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/memory.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/observability.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/providers.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/resilience.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/tools.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/ai/vectorstore.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/annotations/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/annotations/cache.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/annotations/cloud.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/annotations/conditional.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/annotations/core.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/annotations/messaging.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/aop/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/aop/cloud_aop.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/aop/comprehensive_aop.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/aop/method_interceptor.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/aop/proxy_factory.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/cloud/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/cloud/discovery.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/cloud/feign.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/cloud/gateway.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/cloud/load_balancer.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/cloud/seata.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/cloud/sentinel.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/cloud/tracer.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/cloud/transaction_store.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/config/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/config/binding.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/config/config_loader.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/context/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/context/application_context.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/context/bean_definition.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/context/bean_factory.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/context/registry.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/context/scanner.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/core/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/core/graceful_shutdown.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/core/typing_utils.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/csv/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/csv/annotations.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/csv/converters.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/csv/easy_csv.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/csv/exceptions.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/csv/reader.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/csv/writer.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/data/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/data/page.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/data/repository.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/data/specification.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/datasource/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/datasource/annotations.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/datasource/context.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/datasource/dynamic.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/event/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/event/publisher.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/excel/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/excel/annotations.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/excel/converters.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/excel/easy_excel.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/excel/exceptions.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/excel/reader.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/excel/style.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/excel/writer.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/i18n/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/i18n/accessor.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/i18n/auto_config.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/i18n/holder.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/i18n/locale.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/i18n/locale_resolver.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/i18n/message_source.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/i18n/middleware.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/i18n/properties.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/i18n/sources.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/logging/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/messaging/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/messaging/rabbitmq.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/monitoring/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/monitoring/prometheus.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/database.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/ddl_auto.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/migration.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/mybatis_integration.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/annotations/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/annotations/annotations.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/cache/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/cache/cache.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/cache/redis_cache.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/circuit_breaker/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/circuit_breaker/circuit_breaker.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/configuration.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/core/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/core/sql_session.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/core/sql_session_factory.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/dialect/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/dialect/dialect.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/dynamic_sql/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/dynamic_sql/dynamic_sql.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/interceptor/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/interceptor/interceptor.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/mapper/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/mapper/mapper.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/metrics/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/metrics/metrics.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/pool/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/pool/connection_pool.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/security/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/security/access_control.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/security/password_encoder.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/security/sensitive_data_masker.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/security/sql_injection_detector.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/transaction/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/transaction/transaction.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/type_handler/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/type_handler/type_handler.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/version.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/xml_parser/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/orm/pymybatis/xml_parser/xml_parser.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/retry/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/retry/retry_annotations.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/retry/retry_decorator.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/scheduling/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/scheduling/scheduler.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/security/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/security/jwt_utils.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/security/replay_protection.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/security/secret_manager.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/security/security_aop.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/security/security_context.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/test/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/test/slicing.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/tracing/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/tracing/skywalking.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/tx/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/tx/events.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/tx/synchronization.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/utils/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/utils/bean_utils.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/utils/logger.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/utils/redis_client.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/validation/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/validation/aop.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/validation/constraints.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/validation/exceptions.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/validation/validator.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/web/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/web/actuator.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/web/exception_handler.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/web/health.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/web/interceptor.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/web/result.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/web/swagger.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/web/web_context.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/websocket/__init__.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/websocket/annotations.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/websocket/broker.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/websocket/exceptions.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/websocket/handler.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/websocket/router.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/spring/websocket/session.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/springbootAI.egg-info/dependency_links.txt +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/springbootAI.egg-info/entry_points.txt +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/springbootAI.egg-info/requires.txt +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/springbootAI.egg-info/top_level.txt +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/sql/seata_undo_log.sql +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_actuator.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_ai_module.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_annotation_combinations.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_annotations_contract.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_aop_annotations_full.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_bean_utils.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_cache_annotations.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_cloud_embedded_full.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_conditional_annotations.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_config_binding.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_config_fixes_185.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_connection_resilience.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_core_annotations_full.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_csv_module.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_data_repository.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_datasource_routing.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_ddl_auto.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_di_config_event_full.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_excel_module.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_i18n_module.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_jpa_version_transient.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_new_features.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_orm_pymybatis_full.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_production_readiness.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_pymybatis_contract.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_seata_durable_store.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_security.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_security_full.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_swagger_module.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_test_slicing.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_transactional_events.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_validation_module.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_web_annotations_full.py +0 -0
- {springbootai-1.8.5 → springbootai-1.8.7}/tests/test_websocket_module.py +0 -0
|
@@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"
|
|
|
12
12
|
[project]
|
|
13
13
|
# 发行名 springbootAI(PyPI 包名,pip install springbootAI);导入包名仍为 spring
|
|
14
14
|
name = "springbootAI"
|
|
15
|
-
version = "1.8.
|
|
15
|
+
version = "1.8.7"
|
|
16
16
|
description = "Python版Spring Boot框架,集成PyMyBatis ORM"
|
|
17
17
|
readme = "README.md"
|
|
18
18
|
license = "MIT"
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Loguru结构化日志模块
|
|
3
|
+
提供企业级日志功能
|
|
4
|
+
"""
|
|
5
|
+
import logging
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
import tempfile
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
# 尝试导入loguru,失败则使用标准logging
|
|
13
|
+
try:
|
|
14
|
+
from loguru import logger as loguru_logger
|
|
15
|
+
_loguru_available = True
|
|
16
|
+
except ImportError:
|
|
17
|
+
_loguru_available = False
|
|
18
|
+
loguru_logger = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _format_config_error(config_key: str, config_value, reason: str,
|
|
22
|
+
suggestions: list = None) -> str:
|
|
23
|
+
"""格式化配置错误信息为清晰可读的多行文本。
|
|
24
|
+
|
|
25
|
+
统一所有配置校验失败的输出格式,让用户一眼定位是哪个配置项、什么值、
|
|
26
|
+
为什么错、怎么修,而不是看到框架内部 traceback 不知道哪里出问题。
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
config_key: 配置项名(如 ``logging.log_dir``)
|
|
30
|
+
config_value: 用户配置的值
|
|
31
|
+
reason: 错误原因
|
|
32
|
+
suggestions: 修复建议列表
|
|
33
|
+
"""
|
|
34
|
+
lines = [
|
|
35
|
+
"=" * 64,
|
|
36
|
+
f"[配置错误] {config_key} 配置无效",
|
|
37
|
+
"-" * 64,
|
|
38
|
+
f" 配置项: {config_key}",
|
|
39
|
+
f" 配置值: {config_value!r}",
|
|
40
|
+
f" 错误原因: {reason}",
|
|
41
|
+
]
|
|
42
|
+
if suggestions:
|
|
43
|
+
lines.append(" 修复建议:")
|
|
44
|
+
for i, s in enumerate(suggestions, 1):
|
|
45
|
+
lines.append(f" {i}. {s}")
|
|
46
|
+
lines.append("=" * 64)
|
|
47
|
+
return "\n".join(lines)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class LoggingConfigError(RuntimeError):
|
|
51
|
+
"""日志配置校验失败(路径不可创建/不可写入等)。
|
|
52
|
+
|
|
53
|
+
继承 RuntimeError 而非直接用 ConfigurationError,避免与 config_loader 的
|
|
54
|
+
循环导入;信息格式由 ``_format_config_error`` 统一。
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class SpringLogger:
|
|
59
|
+
"""Spring日志管理器"""
|
|
60
|
+
|
|
61
|
+
_instance = None
|
|
62
|
+
_lock = __import__('threading').Lock()
|
|
63
|
+
|
|
64
|
+
def __new__(cls, *args, **kwargs):
|
|
65
|
+
if cls._instance is None:
|
|
66
|
+
with cls._lock:
|
|
67
|
+
if cls._instance is None:
|
|
68
|
+
cls._instance = super().__new__(cls)
|
|
69
|
+
return cls._instance
|
|
70
|
+
|
|
71
|
+
def __init__(self, level: str = "INFO", log_format: str = None,
|
|
72
|
+
log_dir: str = "logs", retention: str = "30 days",
|
|
73
|
+
rotation: str = "100 MB"):
|
|
74
|
+
if hasattr(self, '_initialized'):
|
|
75
|
+
return
|
|
76
|
+
self.level = level.upper()
|
|
77
|
+
self.log_dir = log_dir
|
|
78
|
+
self.retention = retention
|
|
79
|
+
self.rotation = rotation
|
|
80
|
+
self._initialized = True
|
|
81
|
+
self._use_loguru = _loguru_available
|
|
82
|
+
self.log_format = log_format or self._default_format()
|
|
83
|
+
|
|
84
|
+
# import 时只设置控制台输出,不创建文件 handler(不创建 logs/ 目录)。
|
|
85
|
+
# 文件 handler 在 init_logging → reconfigure 读取用户配置后创建,
|
|
86
|
+
# 避免在 CWD 下提前生成 logs/ 目录与用户配置的 log_dir 产生双份日志。
|
|
87
|
+
if self._use_loguru:
|
|
88
|
+
loguru_logger.remove()
|
|
89
|
+
loguru_logger.add(
|
|
90
|
+
sys.stdout, format=self.log_format, level=self.level, colorize=True)
|
|
91
|
+
else:
|
|
92
|
+
self._setup_std_logging(strict=False, enable_file=False)
|
|
93
|
+
|
|
94
|
+
def reconfigure(self, level: Optional[str] = None, log_format: Optional[str] = None,
|
|
95
|
+
log_dir: Optional[str] = None, retention: Optional[str] = None,
|
|
96
|
+
rotation: Optional[str] = None) -> None:
|
|
97
|
+
"""重新配置日志参数并重建处理器(读取配置后调用)。
|
|
98
|
+
|
|
99
|
+
SpringLogger 为单例,``__init__`` 的 ``_initialized`` 守卫会阻止后续 ``__init__``
|
|
100
|
+
更新参数。``init_logging`` 读取 ``application.yml`` 的 ``logging.log_dir`` 后,
|
|
101
|
+
必须通过本方法重新配置,否则日志目录永远停留在默认 ``'logs'``(相对当前工作目录,
|
|
102
|
+
即 Application.py 所在目录/logs)。
|
|
103
|
+
|
|
104
|
+
本方法以 **strict 模式** 校验日志目录:用户显式配置的 ``log_dir`` 如果路径
|
|
105
|
+
不合法/不可创建/不可写入,将抛出 ``LoggingConfigError``(含明确错误信息),
|
|
106
|
+
而不是静默降级到默认目录——配置写错必须让用户知道。
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
level: 日志级别(如 INFO/DEBUG),None 表示保留原值
|
|
110
|
+
log_format: 日志格式,None 表示保留原值
|
|
111
|
+
log_dir: 日志目录,None 表示保留原值
|
|
112
|
+
retention: 日志保留期,None 表示保留原值
|
|
113
|
+
rotation: 日志轮转大小,None 表示保留原值
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
LoggingConfigError: 日志目录不可创建或不可写入(strict 模式)
|
|
117
|
+
"""
|
|
118
|
+
if level is not None:
|
|
119
|
+
self.level = level.upper()
|
|
120
|
+
if log_format is not None:
|
|
121
|
+
self.log_format = log_format
|
|
122
|
+
# 记录是否是用户显式配置了 log_dir:只有显式配置才 strict 校验,
|
|
123
|
+
# 保留旧值(log_dir=None)时用非严格模式,避免默认 'logs' 在只读 CWD 报错
|
|
124
|
+
log_dir_explicitly_set = log_dir is not None
|
|
125
|
+
if log_dir_explicitly_set:
|
|
126
|
+
self.log_dir = log_dir
|
|
127
|
+
if retention is not None:
|
|
128
|
+
self.retention = retention
|
|
129
|
+
if rotation is not None:
|
|
130
|
+
self.rotation = rotation
|
|
131
|
+
# 重建日志处理器:用户显式配置 log_dir 时 strict=True(路径错必须报错),
|
|
132
|
+
# 否则 strict=False(保留旧值/默认值时允许降级)。
|
|
133
|
+
# reconfigure 始终启用文件 handler(enable_file=True),
|
|
134
|
+
# 因为此时用户配置已读取,应该创建日志文件。
|
|
135
|
+
strict_mode = log_dir_explicitly_set
|
|
136
|
+
if self._use_loguru:
|
|
137
|
+
self._setup_loguru(strict=strict_mode, enable_file=True)
|
|
138
|
+
else:
|
|
139
|
+
self._setup_std_logging(strict=strict_mode, enable_file=True)
|
|
140
|
+
|
|
141
|
+
def _validate_log_dir(self, strict: bool) -> bool:
|
|
142
|
+
"""校验日志目录可创建且可写入。
|
|
143
|
+
|
|
144
|
+
``strict=True``(用户配置生效路径):校验失败抛 ``LoggingConfigError``,
|
|
145
|
+
错误信息含配置项名、配置值、具体 errno 原因、修复建议。
|
|
146
|
+
``strict=False``(import 时默认配置):校验失败仅 warning 并返回 False,
|
|
147
|
+
保证 import 不崩溃。
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
strict: 是否严格模式(True=报错,False=降级)
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
True 表示目录可用,False 表示不可用(仅 strict=False 时返回)
|
|
154
|
+
|
|
155
|
+
Raises:
|
|
156
|
+
LoggingConfigError: strict=True 且目录不可用时
|
|
157
|
+
"""
|
|
158
|
+
suggestions = [
|
|
159
|
+
"检查路径拼写是否正确",
|
|
160
|
+
"确认父目录存在且有写权限",
|
|
161
|
+
"使用绝对路径避免工作目录歧义",
|
|
162
|
+
"Windows 路径用双反斜杠或正斜杠: \"C:/Users/xxx/logs\"",
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
# 1. 空值校验
|
|
166
|
+
if not self.log_dir or not str(self.log_dir).strip():
|
|
167
|
+
msg = _format_config_error(
|
|
168
|
+
'logging.log_dir', self.log_dir,
|
|
169
|
+
'日志目录为空字符串,无法创建', suggestions)
|
|
170
|
+
if strict:
|
|
171
|
+
raise LoggingConfigError(msg)
|
|
172
|
+
print(f"[WARNING] {msg}", file=sys.stderr)
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
log_dir = str(self.log_dir).strip()
|
|
176
|
+
|
|
177
|
+
# 2. 尝试创建目录(捕获所有 OSError 子类:PermissionError/FileNotFoundError 等)
|
|
178
|
+
try:
|
|
179
|
+
os.makedirs(log_dir, exist_ok=True)
|
|
180
|
+
except OSError as exc:
|
|
181
|
+
# 根据 errno 给出具体原因
|
|
182
|
+
import errno
|
|
183
|
+
if exc.errno == errno.EACCES:
|
|
184
|
+
reason = f"无写权限(Permission denied): {exc}"
|
|
185
|
+
elif exc.errno == errno.ENOENT:
|
|
186
|
+
reason = f"父目录不存在且无法创建: {exc}"
|
|
187
|
+
elif exc.errno == errno.ENOTDIR:
|
|
188
|
+
reason = f"路径中某一段不是目录(可能是文件): {exc}"
|
|
189
|
+
elif exc.errno == errno.EROFS:
|
|
190
|
+
reason = f"只读文件系统: {exc}"
|
|
191
|
+
else:
|
|
192
|
+
reason = f"{type(exc).__name__} (errno={exc.errno}): {exc}"
|
|
193
|
+
msg = _format_config_error(
|
|
194
|
+
'logging.log_dir', self.log_dir, reason, suggestions)
|
|
195
|
+
if strict:
|
|
196
|
+
raise LoggingConfigError(msg) from exc
|
|
197
|
+
print(f"[WARNING] {msg}", file=sys.stderr)
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
# 3. 测试可写入(创建临时文件后删除)
|
|
201
|
+
test_file = os.path.join(log_dir, f".spring_write_test_{os.getpid()}")
|
|
202
|
+
try:
|
|
203
|
+
with open(test_file, 'w', encoding='utf-8') as f:
|
|
204
|
+
f.write("write permission test")
|
|
205
|
+
os.remove(test_file)
|
|
206
|
+
except OSError as exc:
|
|
207
|
+
import errno
|
|
208
|
+
if exc.errno == errno.EACCES:
|
|
209
|
+
reason = f"目录已创建但无写权限: {exc}"
|
|
210
|
+
else:
|
|
211
|
+
reason = f"目录已创建但无法写入文件: {type(exc).__name__}: {exc}"
|
|
212
|
+
msg = _format_config_error(
|
|
213
|
+
'logging.log_dir', self.log_dir, reason, suggestions)
|
|
214
|
+
if strict:
|
|
215
|
+
raise LoggingConfigError(msg) from exc
|
|
216
|
+
print(f"[WARNING] {msg}", file=sys.stderr)
|
|
217
|
+
return False
|
|
218
|
+
|
|
219
|
+
return True
|
|
220
|
+
|
|
221
|
+
def _default_format(self) -> str:
|
|
222
|
+
"""默认日志格式"""
|
|
223
|
+
if self._use_loguru:
|
|
224
|
+
return (
|
|
225
|
+
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
|
|
226
|
+
"<level>{level: <8}</level> | "
|
|
227
|
+
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
|
|
228
|
+
"<level>{message}</level>"
|
|
229
|
+
)
|
|
230
|
+
return "%(asctime)s | %(levelname)-8s | %(name)s:%(funcName)s:%(lineno)d | %(message)s"
|
|
231
|
+
|
|
232
|
+
def _setup_loguru(self, strict: bool = False, enable_file: bool = True):
|
|
233
|
+
"""配置Loguru。
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
strict: True 时日志目录校验失败抛 ``LoggingConfigError``(用户配置路径);
|
|
237
|
+
False 时降级为仅控制台日志(import 时默认配置,保证不崩溃)
|
|
238
|
+
enable_file: True 时添加文件 handler(创建日志目录+文件);
|
|
239
|
+
False 时仅控制台输出(import 时避免提前创建 logs/ 目录)
|
|
240
|
+
"""
|
|
241
|
+
# 清除默认处理器
|
|
242
|
+
loguru_logger.remove()
|
|
243
|
+
|
|
244
|
+
# 添加控制台输出(始终启用,确保错误信息至少能打印到控制台)
|
|
245
|
+
loguru_logger.add(
|
|
246
|
+
sys.stdout,
|
|
247
|
+
format=self.log_format,
|
|
248
|
+
level=self.level,
|
|
249
|
+
colorize=True,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# enable_file=False 时只输出到控制台(import 时使用,不创建 logs/ 目录)
|
|
253
|
+
if not enable_file:
|
|
254
|
+
return
|
|
255
|
+
|
|
256
|
+
# 校验日志目录:strict 模式下失败会抛异常(由 reconfigure 捕获并输出),
|
|
257
|
+
# 非 strict 模式下返回 False 则仅使用控制台日志
|
|
258
|
+
if not self._validate_log_dir(strict=strict):
|
|
259
|
+
return
|
|
260
|
+
|
|
261
|
+
# 添加文件输出(按日期轮转)
|
|
262
|
+
loguru_logger.add(
|
|
263
|
+
os.path.join(self.log_dir, "application_{time:YYYY-MM-DD}.log"),
|
|
264
|
+
format=self.log_format,
|
|
265
|
+
level=self.level,
|
|
266
|
+
rotation=self.rotation,
|
|
267
|
+
retention=self.retention,
|
|
268
|
+
compression="zip",
|
|
269
|
+
encoding="utf-8",
|
|
270
|
+
)
|
|
271
|
+
# 添加错误日志单独输出
|
|
272
|
+
loguru_logger.add(
|
|
273
|
+
os.path.join(self.log_dir, "error_{time:YYYY-MM-DD}.log"),
|
|
274
|
+
format=self.log_format,
|
|
275
|
+
level="ERROR",
|
|
276
|
+
rotation=self.rotation,
|
|
277
|
+
retention=self.retention,
|
|
278
|
+
compression="zip",
|
|
279
|
+
encoding="utf-8",
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
def _setup_std_logging(self, strict: bool = False, enable_file: bool = True):
|
|
283
|
+
"""配置标准logging(fallback)。
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
strict: True 时日志目录校验失败抛 ``LoggingConfigError``;
|
|
287
|
+
False 时降级为仅控制台日志(import 时保证不崩溃)
|
|
288
|
+
enable_file: True 时添加文件 handler;False 时仅控制台输出
|
|
289
|
+
(import 时避免提前创建 logs/ 目录)
|
|
290
|
+
"""
|
|
291
|
+
self._logger = logging.getLogger("Spring")
|
|
292
|
+
self._logger.setLevel(getattr(logging, self.level))
|
|
293
|
+
# 清除旧 handler(reconfigure 重建时避免重复 add 导致日志重复输出)
|
|
294
|
+
for handler in list(self._logger.handlers):
|
|
295
|
+
self._logger.removeHandler(handler)
|
|
296
|
+
|
|
297
|
+
# 添加控制台输出(始终启用)
|
|
298
|
+
console_handler = logging.StreamHandler(sys.stdout)
|
|
299
|
+
console_handler.setFormatter(logging.Formatter(self.log_format))
|
|
300
|
+
self._logger.addHandler(console_handler)
|
|
301
|
+
|
|
302
|
+
# enable_file=False 时只输出到控制台
|
|
303
|
+
if not enable_file:
|
|
304
|
+
return
|
|
305
|
+
|
|
306
|
+
# 校验日志目录
|
|
307
|
+
if not self._validate_log_dir(strict=strict):
|
|
308
|
+
return
|
|
309
|
+
|
|
310
|
+
# 添加文件输出
|
|
311
|
+
file_handler = logging.FileHandler(
|
|
312
|
+
os.path.join(self.log_dir, "application.log"),
|
|
313
|
+
encoding="utf-8"
|
|
314
|
+
)
|
|
315
|
+
file_handler.setFormatter(logging.Formatter(self.log_format))
|
|
316
|
+
self._logger.addHandler(file_handler)
|
|
317
|
+
|
|
318
|
+
def get_logger(self):
|
|
319
|
+
"""获取日志实例"""
|
|
320
|
+
if self._use_loguru:
|
|
321
|
+
return loguru_logger
|
|
322
|
+
return self._logger
|
|
323
|
+
|
|
324
|
+
def info(self, message: str, **kwargs):
|
|
325
|
+
"""记录INFO级别日志"""
|
|
326
|
+
if self._use_loguru:
|
|
327
|
+
loguru_logger.info(message, **kwargs)
|
|
328
|
+
else:
|
|
329
|
+
self._logger.info(message)
|
|
330
|
+
|
|
331
|
+
def debug(self, message: str, **kwargs):
|
|
332
|
+
"""记录DEBUG级别日志"""
|
|
333
|
+
if self._use_loguru:
|
|
334
|
+
loguru_logger.debug(message, **kwargs)
|
|
335
|
+
else:
|
|
336
|
+
self._logger.debug(message)
|
|
337
|
+
|
|
338
|
+
def warning(self, message: str, **kwargs):
|
|
339
|
+
"""记录WARNING级别日志"""
|
|
340
|
+
if self._use_loguru:
|
|
341
|
+
loguru_logger.warning(message, **kwargs)
|
|
342
|
+
else:
|
|
343
|
+
self._logger.warning(message)
|
|
344
|
+
|
|
345
|
+
def error(self, message: str, **kwargs):
|
|
346
|
+
"""记录ERROR级别日志"""
|
|
347
|
+
if self._use_loguru:
|
|
348
|
+
loguru_logger.error(message, **kwargs)
|
|
349
|
+
else:
|
|
350
|
+
self._logger.error(message)
|
|
351
|
+
|
|
352
|
+
def critical(self, message: str, **kwargs):
|
|
353
|
+
"""记录CRITICAL级别日志"""
|
|
354
|
+
if self._use_loguru:
|
|
355
|
+
loguru_logger.critical(message, **kwargs)
|
|
356
|
+
else:
|
|
357
|
+
self._logger.critical(message)
|
|
358
|
+
|
|
359
|
+
def exception(self, message: str, **kwargs):
|
|
360
|
+
"""记录异常日志"""
|
|
361
|
+
if self._use_loguru:
|
|
362
|
+
loguru_logger.exception(message, **kwargs)
|
|
363
|
+
else:
|
|
364
|
+
self._logger.exception(message)
|
|
365
|
+
|
|
366
|
+
def log(self, level: str, message: str, **kwargs):
|
|
367
|
+
"""记录指定级别日志"""
|
|
368
|
+
if self._use_loguru:
|
|
369
|
+
loguru_logger.log(level.upper(), message, **kwargs)
|
|
370
|
+
else:
|
|
371
|
+
self._logger.log(getattr(logging, level.upper()), message)
|
|
372
|
+
|
|
373
|
+
def bind(self, **extra):
|
|
374
|
+
"""绑定额外字段到日志上下文"""
|
|
375
|
+
if self._use_loguru:
|
|
376
|
+
return loguru_logger.bind(**extra)
|
|
377
|
+
return self._logger
|
|
378
|
+
|
|
379
|
+
def patch(self, function):
|
|
380
|
+
"""添加额外字段到日志消息"""
|
|
381
|
+
if self._use_loguru:
|
|
382
|
+
return loguru_logger.patch(function)
|
|
383
|
+
return self._logger
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
# 创建全局日志管理器实例
|
|
387
|
+
spring_logger = SpringLogger()
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def init_logging(config: dict) -> None:
|
|
391
|
+
"""初始化日志配置(读取 application.yml 的 logging 段后调用)。
|
|
392
|
+
|
|
393
|
+
通过 ``reconfigure`` 重新配置单例 SpringLogger,使 ``logging.log_dir`` / ``level``
|
|
394
|
+
等配置生效。直接 ``SpringLogger(log_dir=...)`` 因单例 ``_initialized`` 守卫不会更新参数。
|
|
395
|
+
|
|
396
|
+
如果用户配置的 ``log_dir`` 路径不合法/不可创建/不可写入,``reconfigure`` 会抛出
|
|
397
|
+
``LoggingConfigError``。本函数捕获后打印明确错误横幅到 stderr(确保用户看到),
|
|
398
|
+
然后重新抛出,让上层 fail-fast 终止启动——配置写错必须让用户知道,而不是静默
|
|
399
|
+
降级到默认目录。
|
|
400
|
+
|
|
401
|
+
Args:
|
|
402
|
+
config: 配置字典(logging 子字典),包含 level/log_dir/retention/rotation 等
|
|
403
|
+
|
|
404
|
+
Raises:
|
|
405
|
+
LoggingConfigError: 日志目录配置无效(路径不合法/不可创建/不可写入)
|
|
406
|
+
"""
|
|
407
|
+
global spring_logger
|
|
408
|
+
try:
|
|
409
|
+
spring_logger.reconfigure(
|
|
410
|
+
level=config.get('level'),
|
|
411
|
+
log_format=config.get('log_format'),
|
|
412
|
+
log_dir=config.get('log_dir'),
|
|
413
|
+
retention=config.get('retention'),
|
|
414
|
+
rotation=config.get('rotation'),
|
|
415
|
+
)
|
|
416
|
+
except LoggingConfigError as e:
|
|
417
|
+
# 只打印格式化的错误信息(含配置项/值/原因/建议),不输出框架 traceback
|
|
418
|
+
print(f"\n{e}\n", file=sys.stderr)
|
|
419
|
+
raise
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
# 兼容标准logging模块
|
|
423
|
+
if _loguru_available:
|
|
424
|
+
class LoguruHandler(logging.Handler):
|
|
425
|
+
"""Loguru处理器,用于将标准logging日志转发到Loguru"""
|
|
426
|
+
|
|
427
|
+
def emit(self, record: logging.LogRecord):
|
|
428
|
+
"""处理日志记录"""
|
|
429
|
+
try:
|
|
430
|
+
level = loguru_logger.level(record.levelname).name
|
|
431
|
+
message = self.format(record)
|
|
432
|
+
loguru_logger.log(level, message)
|
|
433
|
+
except Exception:
|
|
434
|
+
self.handleError(record)
|
|
435
|
+
|
|
436
|
+
# 将标准logging日志转发到Loguru
|
|
437
|
+
logging.basicConfig(handlers=[LoguruHandler()], level=logging.INFO)
|