Transport-for-the-North / caf.toolkit

Toolkit of transport planning and appraisal functionalities.
https://caftoolkit.readthedocs.io/en/stable/
Other
0 stars 2 forks source link

Logging Package Filter #123

Open MattBuckley-TfN opened 6 months ago

MattBuckley-TfN commented 6 months ago

Add functionality to allow for custom package filtering for logging messages i.e. allowing for log messages from all caf packages to be kept but ignoring any from other third-party packages. An example implementation for the filter class is given below, which allows for multiple package names to be provide and provides the filter method for ignoring log records from other packages.

class PackageFilter(logging.Filter):
    """Logging filter which only allows given packages (and sub-packages)."""

    def __init__(self, allowed_pkgs: Sequence[str]) -> None:
        super().__init__()

        pkgs = set(str(i).lower().strip() for i in allowed_pkgs)

        # Build package match pattern
        pkg_str = "|".join(re.escape(i) for i in pkgs)
        self._pattern = re.compile(rf"^({pkg_str})(\..*)*$", re.I)

        LOG.debug("Setup logging package filter with regex: %r", self._pattern.pattern)

    def filter(self, record: logging.LogRecord) -> bool:
        matched = self._pattern.match(record.name.strip())
        if matched is None:
            return False

        return True

This class should be added to log_helpers and then integrated into the LogHelper class so that it's easy to use, something like the following might work:

class LogHelper:
    ...

   def __init__(
        self,
        root_logger: str,
        tool_details: ToolDetails,
        console: bool = True,
        log_file: os.PathLike | None = None,
        warning_capture: bool = True,
        allowed_packages: Optional[Sequence[str]] = None
    ):
        ...

        if allowed_packages is None:
            self.package_filter = None
        else:
            self.package_filter = PackageFilter(allowed_packages)

        ...

def add_handler(self, handler: logging.Handler) -> None:
        """..."""
        if self.package_filter is not None:
            handler.addFilter(self.package_filter)

        ...