From 73f0b62c3a3580cc63ca6937621125e93842b556 Mon Sep 17 00:00:00 2001 From: aidankhogg Date: Mon, 29 Jun 2026 23:09:40 +0100 Subject: [PATCH] Fix logs package refactor imports --- README.md | 2 +- netengine/api/app.py | 2 +- netengine/api/auth.py | 2 +- netengine/api/routes.py | 2 +- netengine/cli/main.py | 2 +- netengine/core/consumer_supervisor.py | 2 +- netengine/core/docker_factory.py | 2 +- netengine/core/drift_controller.py | 2 +- netengine/core/orchestrator.py | 2 +- netengine/core/reload.py | 2 +- netengine/core/self_healing.py | 2 +- netengine/core/state.py | 2 +- netengine/handlers/and_handler.py | 2 +- netengine/handlers/app_handler.py | 2 +- netengine/handlers/gateway_portal_handler.py | 2 +- netengine/handlers/phase_pki.py | 2 +- netengine/handlers/pki_handler.py | 2 +- netengine/logs/__init__.py | 18 +++++++++++++++ netengine/logs/core.py | 22 +++++++++++++++++++ netengine/monitoring/service.py | 2 +- netengine/phases/phase_inworld_identity.py | 2 +- netengine/phases/phase_platform_identity.py | 2 +- netengine/spec/loader.py | 2 +- netengine/utils/migrations.py | 2 +- netengine/workers/pki_cert_rotation_worker.py | 2 +- pyproject.toml | 4 ++-- tests/conftest.py | 4 ++-- tests/integration/test_e2e_federation.py | 2 +- tests/integration/test_e2e_fullstack.py | 2 +- tests/integration/test_m1_m2_bootstrap.py | 2 +- tests/integration/test_m6_inworld_identity.py | 2 +- tests/integration/test_m7_ands.py | 2 +- tests/integration/test_m8_mail.py | 2 +- tests/test_pgmq_emitters.py | 2 +- tests/test_spec_parsing.py | 10 ++++----- 35 files changed, 79 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index d702701..f0ad93e 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,7 @@ netengine/ spec/ Pydantic v2 models + YAML loader with cross-field validation events/ EventEnvelope schema (locked) api/ FastAPI operator API - logging/ Structured logging (loguru) + logs/ Structured logging (loguru) errors.py Error hierarchy (SubstrateError, DNSError, PKIError, …) migrations/ SQL schema + pgmq queue setup examples/ Reference YAML specs diff --git a/netengine/api/app.py b/netengine/api/app.py index ee7ef57..adc4935 100644 --- a/netengine/api/app.py +++ b/netengine/api/app.py @@ -3,7 +3,7 @@ from fastapi import FastAPI from netengine.api.routes import router -from logs.middleware import StructuredLoggingMiddleware +from netengine.logs.middleware import StructuredLoggingMiddleware app = FastAPI( title="NetEngine Operator API", diff --git a/netengine/api/auth.py b/netengine/api/auth.py index 3c12a44..b29aaa2 100644 --- a/netengine/api/auth.py +++ b/netengine/api/auth.py @@ -18,7 +18,7 @@ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from netengine.core.state import RuntimeState -from logs import get_logger +from netengine.logs import get_logger logger = get_logger(__name__) diff --git a/netengine/api/routes.py b/netengine/api/routes.py index 3102afe..4b832d3 100644 --- a/netengine/api/routes.py +++ b/netengine/api/routes.py @@ -20,7 +20,7 @@ from netengine.core.reload import ReloadResult, apply_reload from netengine.core.state import RUNTIME_STATE_SCHEMA_VERSION, RuntimeState from netengine.events.queues import PRIMARY_QUEUES, Queue, dlq_for -from logs import get_logger +from netengine.logs import get_logger from netengine.phase_labels import PHASE_LABELS from netengine.security.redaction import ( _contains_private_pem, diff --git a/netengine/cli/main.py b/netengine/cli/main.py index 4811700..fafcb1a 100644 --- a/netengine/cli/main.py +++ b/netengine/cli/main.py @@ -28,7 +28,7 @@ run_migrations, ) from netengine.events.queues import PRIMARY_QUEUES, Queue, dlq_for -from logs import get_logger +from netengine.logs import get_logger from netengine.phase_labels import PHASE_LABELS from netengine.spec.loader import ( SpecLoadError, diff --git a/netengine/core/consumer_supervisor.py b/netengine/core/consumer_supervisor.py index a932411..f873896 100644 --- a/netengine/core/consumer_supervisor.py +++ b/netengine/core/consumer_supervisor.py @@ -1,7 +1,7 @@ import asyncio from typing import Any, Callable, Coroutine, Dict -from logs import get_logger +from netengine.logs import get_logger logger = get_logger(__name__) diff --git a/netengine/core/docker_factory.py b/netengine/core/docker_factory.py index 0194917..4795dd7 100644 --- a/netengine/core/docker_factory.py +++ b/netengine/core/docker_factory.py @@ -7,7 +7,7 @@ import os from typing import Any, Optional -from logs import get_logger +from netengine.logs import get_logger logger = get_logger(__name__) diff --git a/netengine/core/drift_controller.py b/netengine/core/drift_controller.py index 9bf5dec..8101f19 100644 --- a/netengine/core/drift_controller.py +++ b/netengine/core/drift_controller.py @@ -6,7 +6,7 @@ """ import asyncio -import logs +import netengine.logs as logs from dataclasses import dataclass from datetime import UTC, datetime from typing import Any, Optional diff --git a/netengine/core/orchestrator.py b/netengine/core/orchestrator.py index cdbfbf1..96e7d61 100644 --- a/netengine/core/orchestrator.py +++ b/netengine/core/orchestrator.py @@ -14,7 +14,7 @@ from netengine.handlers.dns import DNSHandler from netengine.handlers.phase_pki import PKIPhaseHandler from netengine.handlers.substrate import SubstrateHandler -from logs import get_logger +from netengine.logs import get_logger from netengine.monitoring.metrics import record_healthcheck_failure, record_phase from netengine.phases.phase_ands import ANDsPhaseHandler from netengine.phases.phase_inworld_identity import InWorldIdentityPhaseHandler diff --git a/netengine/core/reload.py b/netengine/core/reload.py index 83359cc..3b79685 100644 --- a/netengine/core/reload.py +++ b/netengine/core/reload.py @@ -13,7 +13,7 @@ from pydantic import BaseModel from netengine.core.state import RuntimeState -from logs import get_logger +from netengine.logs import get_logger from netengine.spec.models import NetEngineSpec logger = get_logger(__name__) diff --git a/netengine/core/self_healing.py b/netengine/core/self_healing.py index 510f1ff..0f53595 100644 --- a/netengine/core/self_healing.py +++ b/netengine/core/self_healing.py @@ -3,7 +3,7 @@ Implements the logic for re-applying drifted phases and their dependencies. """ -import logs +import netengine.logs as logs from dataclasses import dataclass from typing import Optional diff --git a/netengine/core/state.py b/netengine/core/state.py index 21e1abb..e062a90 100644 --- a/netengine/core/state.py +++ b/netengine/core/state.py @@ -6,7 +6,7 @@ from pathlib import Path from typing import TYPE_CHECKING, Any, Dict, Optional, TypedDict, cast -from logs import get_logger +from netengine.logs import get_logger if TYPE_CHECKING: import asyncio diff --git a/netengine/handlers/and_handler.py b/netengine/handlers/and_handler.py index 65e582e..913f6f1 100644 --- a/netengine/handlers/and_handler.py +++ b/netengine/handlers/and_handler.py @@ -10,7 +10,7 @@ from netengine.handlers.domain_registry_handler import DomainRegistryHandler from netengine.handlers.gateway_handler import GatewayHandler from netengine.handlers.protocols import DockerAdapterProtocol, PGMQAdapterProtocol -from logs import get_logger +from netengine.logs import get_logger from netengine.spec.models import NetEngineSpec diff --git a/netengine/handlers/app_handler.py b/netengine/handlers/app_handler.py index 74a18d2..1285a51 100644 --- a/netengine/handlers/app_handler.py +++ b/netengine/handlers/app_handler.py @@ -9,7 +9,7 @@ from netengine.handlers.oidc_handler import OIDCHandler from netengine.handlers.pki_handler import PKIHandler from netengine.handlers.protocols import DockerAdapterProtocol, PGMQAdapterProtocol -from logs import get_logger +from netengine.logs import get_logger from netengine.spec.models import NetEngineSpec diff --git a/netengine/handlers/gateway_portal_handler.py b/netengine/handlers/gateway_portal_handler.py index 749e963..50c8e72 100644 --- a/netengine/handlers/gateway_portal_handler.py +++ b/netengine/handlers/gateway_portal_handler.py @@ -21,7 +21,7 @@ from netengine.handlers.context import PhaseContext from netengine.handlers.gateway_handler import GatewayHandler from netengine.handlers.protocols import DockerAdapterProtocol -from logs import get_logger +from netengine.logs import get_logger from netengine.spec.models import CrossWorldPeer, GatewayPortal from netengine.spec.types import GatewayCrossWorldMode, GatewayRealInternetMode diff --git a/netengine/handlers/phase_pki.py b/netengine/handlers/phase_pki.py index beba642..59b235e 100644 --- a/netengine/handlers/phase_pki.py +++ b/netengine/handlers/phase_pki.py @@ -6,7 +6,7 @@ from netengine.handlers._base import BasePhaseHandler from netengine.handlers.context import PhaseContext from netengine.handlers.pki_handler import PKIHandler -from logs import get_logger +from netengine.logs import get_logger from netengine.workers.pki_cert_rotation_worker import CertTypeRotationConfig, PKICertRotationWorker logger = get_logger(__name__) diff --git a/netengine/handlers/pki_handler.py b/netengine/handlers/pki_handler.py index 3751876..98b94d5 100644 --- a/netengine/handlers/pki_handler.py +++ b/netengine/handlers/pki_handler.py @@ -12,7 +12,7 @@ from netengine.core.state import RuntimeState from netengine.errors import PKIError from netengine.handlers.protocols import DockerAdapterProtocol -from logs import get_logger +from netengine.logs import get_logger logger = get_logger(__name__) diff --git a/netengine/logs/__init__.py b/netengine/logs/__init__.py index c05ed98..ea71590 100644 --- a/netengine/logs/__init__.py +++ b/netengine/logs/__init__.py @@ -17,6 +17,13 @@ "LoggerFactory", "LogConfig", "get_logger", + "getLogger", + "Logger", + "DEBUG", + "INFO", + "WARNING", + "ERROR", + "CRITICAL", "log_context", "timed_operation", # Tracing @@ -39,6 +46,9 @@ "PerformanceMetricsSink", ] +import logging as _stdlib_logging +from loguru._logger import Logger + from .core import LogConfig, LoggerFactory, get_logger, log_context, timed_operation from .middleware import LoggingMiddleware, StructuredLoggingMiddleware from .sinks import ( @@ -59,5 +69,13 @@ with_trace_context, ) +# Compatibility aliases for code/tests that previously used a logging-like module. +getLogger = get_logger +DEBUG = _stdlib_logging.DEBUG +INFO = _stdlib_logging.INFO +WARNING = _stdlib_logging.WARNING +ERROR = _stdlib_logging.ERROR +CRITICAL = _stdlib_logging.CRITICAL + # Initialize logger on import logger = LoggerFactory.get_logger(__name__) diff --git a/netengine/logs/core.py b/netengine/logs/core.py index c686686..9fb1893 100644 --- a/netengine/logs/core.py +++ b/netengine/logs/core.py @@ -10,6 +10,7 @@ """ import json +import logging import os import sys import threading @@ -134,6 +135,15 @@ def format_record_json(record: "Record") -> str: return json.dumps(log_entry).replace("{", "{{").replace("}", "}}") + "\n" +def forward_to_stdlib_logging(message: Any) -> None: + """Forward Loguru records to Python logging for pytest caplog and integrations.""" + record = message.record + logging.getLogger(record["extra"].get("logger_name") or record["name"]).log( + record["level"].no, + record["message"], + ) + + # ============================================================================ # Filters # ============================================================================ @@ -269,6 +279,7 @@ def initialize( if add_default_sinks: cls.add_stdout_sink(config) cls.add_file_sink(config) + cls.add_stdlib_sink(config) cls._initialized = True @@ -289,6 +300,17 @@ def add_stdout_sink(cls, config: type[LogConfig] = LogConfig) -> None: ) cls._sinks.append("stdout") + @classmethod + def add_stdlib_sink(cls, config: type[LogConfig] = LogConfig) -> None: + """Forward log records to Python's logging module for integrations like pytest caplog.""" + _logger.add( + forward_to_stdlib_logging, + level=config.LOG_LEVEL, + format="{message}", + filter=NoiseFilter(), + ) + cls._sinks.append("stdlib") + @classmethod def add_file_sink( cls, diff --git a/netengine/monitoring/service.py b/netengine/monitoring/service.py index cc499f3..3fd0213 100644 --- a/netengine/monitoring/service.py +++ b/netengine/monitoring/service.py @@ -1,7 +1,7 @@ """Monitoring service — runs all probes on schedule and publishes world_health events to pgmq.""" import asyncio -import logs +import netengine.logs as logs from typing import Any from netengine.core.pgmq_client import PGMQClient diff --git a/netengine/phases/phase_inworld_identity.py b/netengine/phases/phase_inworld_identity.py index 5cf5709..c754024 100644 --- a/netengine/phases/phase_inworld_identity.py +++ b/netengine/phases/phase_inworld_identity.py @@ -25,7 +25,7 @@ from netengine.handlers.docker_handler import DockerHandler from netengine.handlers.oidc_handler import OIDCHandler from netengine.handlers.pki_handler import PKIHandler -from logs import get_logger +from netengine.logs import get_logger logger = get_logger(__name__) diff --git a/netengine/phases/phase_platform_identity.py b/netengine/phases/phase_platform_identity.py index 486b85e..ae9d540 100644 --- a/netengine/phases/phase_platform_identity.py +++ b/netengine/phases/phase_platform_identity.py @@ -9,7 +9,7 @@ from netengine.handlers.docker_handler import DockerHandler from netengine.handlers.oidc_handler import OIDCHandler from netengine.handlers.pki_handler import PKIHandler -from logs import get_logger +from netengine.logs import get_logger logger = get_logger(__name__) diff --git a/netengine/spec/loader.py b/netengine/spec/loader.py index 79832e5..970dcae 100644 --- a/netengine/spec/loader.py +++ b/netengine/spec/loader.py @@ -1,7 +1,7 @@ """YAML spec loading and validation with OmegaConf composition support.""" import ipaddress -import logs +import netengine.logs as logs from collections.abc import Iterator from pathlib import Path from typing import Any, Optional diff --git a/netengine/utils/migrations.py b/netengine/utils/migrations.py index 1797e52..c9cca36 100644 --- a/netengine/utils/migrations.py +++ b/netengine/utils/migrations.py @@ -8,7 +8,7 @@ from types import TracebackType from typing import Protocol -from logs import get_logger +from netengine.logs import get_logger logger = get_logger(__name__) diff --git a/netengine/workers/pki_cert_rotation_worker.py b/netengine/workers/pki_cert_rotation_worker.py index 5840bd7..34fb325 100644 --- a/netengine/workers/pki_cert_rotation_worker.py +++ b/netengine/workers/pki_cert_rotation_worker.py @@ -1,6 +1,6 @@ # netengine/workers/pki_cert_rotation_worker.py import asyncio -import logs +import netengine.logs as logs from dataclasses import dataclass from datetime import UTC, datetime, timedelta from typing import Any, Awaitable, Callable, Dict, List, Optional, cast diff --git a/pyproject.toml b/pyproject.toml index 49e4e53..fd08387 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,8 +53,8 @@ exclude = [ "netengine/handlers/mail_handler\\.py", "netengine/handlers/minio_handler\\.py", "netengine/handlers/whois_server\\.py", - "netengine/logging/middleware\\.py", - "netengine/logging/sinks\\.py", + "netengine/logs/middleware\\.py", + "netengine/logs/sinks\\.py", ] [[tool.mypy.overrides]] diff --git a/tests/conftest.py b/tests/conftest.py index dd8bed4..fdc23b2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,13 +1,13 @@ """Pytest configuration and shared fixtures.""" -import logs +import netengine.logs as logs from pathlib import Path from unittest.mock import AsyncMock, MagicMock import pytest from netengine.handlers.context import PhaseContext, RuntimeState -from logs import get_logger +from netengine.logs import get_logger from netengine.spec.loader import load_spec from netengine.spec.models import NetEngineSpec diff --git a/tests/integration/test_e2e_federation.py b/tests/integration/test_e2e_federation.py index 4768728..13931b4 100644 --- a/tests/integration/test_e2e_federation.py +++ b/tests/integration/test_e2e_federation.py @@ -34,7 +34,7 @@ from netengine.handlers.docker_handler import DockerHandler from netengine.handlers.gateway_portal_handler import GatewayPortalHandler from netengine.handlers.substrate import SubstrateHandler -from logs import get_logger +from netengine.logs import get_logger from netengine.spec.loader import load_spec from netengine.spec.models import ( CrossWorldConfig, diff --git a/tests/integration/test_e2e_fullstack.py b/tests/integration/test_e2e_fullstack.py index 8cb05e3..fa98732 100644 --- a/tests/integration/test_e2e_fullstack.py +++ b/tests/integration/test_e2e_fullstack.py @@ -36,7 +36,7 @@ from netengine.handlers.docker_handler import DockerHandler from netengine.handlers.phase_pki import PKIPhaseHandler from netengine.handlers.substrate import SubstrateHandler -from logs import get_logger +from netengine.logs import get_logger from netengine.spec.loader import load_spec FIXTURES_DIR = Path(__file__).parent.parent / "fixtures" diff --git a/tests/integration/test_m1_m2_bootstrap.py b/tests/integration/test_m1_m2_bootstrap.py index 45b6c6a..041ce7e 100644 --- a/tests/integration/test_m1_m2_bootstrap.py +++ b/tests/integration/test_m1_m2_bootstrap.py @@ -13,7 +13,7 @@ from netengine.handlers.context import PhaseContext, RuntimeState from netengine.handlers.dns import DNSHandler from netengine.handlers.substrate import SubstrateHandler -from logs import get_logger +from netengine.logs import get_logger from netengine.spec.models import NetEngineSpec diff --git a/tests/integration/test_m6_inworld_identity.py b/tests/integration/test_m6_inworld_identity.py index 512e9a5..eff15ea 100644 --- a/tests/integration/test_m6_inworld_identity.py +++ b/tests/integration/test_m6_inworld_identity.py @@ -16,7 +16,7 @@ from netengine.core.state import RuntimeState from netengine.handlers._base import BasePhaseHandler from netengine.handlers.context import PhaseContext -from logs import get_logger +from netengine.logs import get_logger from netengine.phases.phase_inworld_identity import InWorldIdentityPhaseHandler from netengine.spec.models import IdentityInWorldPhase, InWorldUser, OrgUsers diff --git a/tests/integration/test_m7_ands.py b/tests/integration/test_m7_ands.py index 2e5ceb9..fab58c2 100644 --- a/tests/integration/test_m7_ands.py +++ b/tests/integration/test_m7_ands.py @@ -17,7 +17,7 @@ from netengine.core.state import RuntimeState from netengine.handlers._base import BasePhaseHandler from netengine.handlers.context import PhaseContext -from logs import get_logger +from netengine.logs import get_logger from netengine.phases.phase_ands import ANDsPhaseHandler diff --git a/tests/integration/test_m8_mail.py b/tests/integration/test_m8_mail.py index 0e488a9..3913a31 100644 --- a/tests/integration/test_m8_mail.py +++ b/tests/integration/test_m8_mail.py @@ -15,7 +15,7 @@ from netengine.core.state import RuntimeState from netengine.handlers._base import BasePhaseHandler from netengine.handlers.context import PhaseContext -from logs import get_logger +from netengine.logs import get_logger from netengine.phases.phase_services import ServicesPhaseHandler from netengine.spec.models import ( DKIMConfig, diff --git a/tests/test_pgmq_emitters.py b/tests/test_pgmq_emitters.py index d69e697..884f3fa 100644 --- a/tests/test_pgmq_emitters.py +++ b/tests/test_pgmq_emitters.py @@ -8,7 +8,7 @@ from netengine.handlers.dns import DNSHandler from netengine.handlers.phase_pki import PKIPhaseHandler from netengine.handlers.substrate import SubstrateHandler -from logs import get_logger +from netengine.logs import get_logger from netengine.phases.phase_inworld_identity import InWorldIdentityPhaseHandler diff --git a/tests/test_spec_parsing.py b/tests/test_spec_parsing.py index 1374283..7c08b89 100644 --- a/tests/test_spec_parsing.py +++ b/tests/test_spec_parsing.py @@ -165,7 +165,7 @@ def _merge(a, b): return spec_file def test_experimental_pki_field_logs_warning_not_error(self, tmp_path, caplog) -> None: - import logs + import netengine.logs as logs # DNSSEC/CRL/OCSP were promoted from unsupported to experimental once the # CoreDNS online-signing + step-ca config paths were wired (WS-A). They @@ -181,7 +181,7 @@ def test_experimental_pki_field_logs_warning_not_error(self, tmp_path, caplog) - ) def test_experimental_gateway_mode_logs_warning_not_raises(self, tmp_path, caplog) -> None: - import logs + import netengine.logs as logs spec_file = self._write_spec( tmp_path, @@ -255,7 +255,7 @@ def test_service_mirror_targets_must_be_ipv4_for_alpha_nftables(self, tmp_path) def test_experimental_profile_field_logs_warning_not_raises(self, tmp_path, caplog) -> None: - import logs + import netengine.logs as logs spec_file = self._write_spec( tmp_path, @@ -284,7 +284,7 @@ def test_experimental_profile_field_logs_warning_not_raises(self, tmp_path, capl ) def test_experimental_enabled_field_logs_warning(self, tmp_path, caplog) -> None: - import logs + import netengine.logs as logs spec_file = self._write_spec(tmp_path, {"pki": {"intermediate_ca_enabled": True}}) @@ -298,7 +298,7 @@ def test_experimental_enabled_field_logs_warning(self, tmp_path, caplog) -> None ) def test_no_warnings_for_default_spec(self, caplog, minimal_spec) -> None: - import logs + import netengine.logs as logs with caplog.at_level(logs.WARNING, logger="netengine.spec.loader"): from netengine.spec.loader import _validate_feature_states