Source code for oci_policy_analysis.presentation.qt.logger_catalog

"""Discover application logger declarations without importing optional interfaces."""

import ast
import logging
from functools import lru_cache
from pathlib import Path

from oci_policy_analysis.application.services.logging_service import CANONICAL_COMPONENT_ALIASES


[docs] @lru_cache(maxsize=1) def declared_components() -> frozenset[str]: """Find literal get_logger declarations in installed Python package sources. Returns: frozenset[str]: Application components, including unloaded Tk/web/MCP modules. Reading source avoids importing their optional dependencies. """ components = {alias for aliases in CANONICAL_COMPONENT_ALIASES.values() for alias in aliases} root = Path(__file__).parents[2] for path in root.rglob('*.py'): if {'generated', 'condition_parser', 'policy_parser'} & set(path.parts): continue try: tree = ast.parse(path.read_text(encoding='utf-8')) except (OSError, SyntaxError): continue for node in ast.walk(tree): if not isinstance(node, ast.Call) or not isinstance(node.func, ast.Name) or node.func.id != 'get_logger': continue argument = next( (kw.value for kw in node.keywords if kw.arg == 'component'), node.args[0] if node.args else None ) if isinstance(argument, ast.Constant) and isinstance(argument.value, str): components.add(argument.value) return frozenset(components)
[docs] def available_components(settings: dict) -> list[str]: """Merge declared, persisted, and currently registered component names. Args: settings: Effective logging configuration with canonical component keys. Returns: list[str]: Sorted logger names; application names omit the common prefix. """ prefix = 'oci-policy-analysis.' components = set(declared_components()) | set(settings.get('log_levels') or {}) for name, logger in list(logging.root.manager.loggerDict.items()): if isinstance(logger, logging.Logger): components.add(name.removeprefix(prefix) if name.startswith(prefix) else name) return sorted(components)