Source code for ska_sdp_piper.piper.utils.log_util

import logging
from copy import deepcopy

import dask
from distributed import WorkerPlugin
from ska_ser_logging import configure_logging

from ska_sdp_piper.piper.utils.log_config import LOGGING_CONFIG


[docs] class LogUtil: """ A class to setup logging configuration in the context of piper based pipelines. This also stores some global settings related to the logging, which might be useful for the pipelines or runners. """ level: int = logging.INFO "Stores the logging level to be used globally" verbose: bool = False "Stores whether user enabled verbose logs via the CLI options" log_file: str | None = None """ Stores the file path to which the logs will be written. Piper will set this up on behalf of the user. """
[docs] @classmethod def configure( cls, log_file: str | None = None, verbose: bool = False, disable_console: bool = False, ): """ Setup logging config as per the SKA Logging Format. Additionally, this can setup logging to a file, and can disable logging to stdout. Every call to this function will override the existing global logging config. Ideally in the appplication's lifecycle, this function should be called once, as early as possible. Parameters ---------- log_file Path to log file. If None or if value is "falsy", logs are not written to a file. verbose If True, set the log level to DEBUG, else set to INFO. disable_console By default, the ska_ser_logging logger logs to the sys.stdout stream. This can be disabled by setting disable_console value to True. """ cls.verbose = verbose cls.log_file = log_file if cls.verbose: cls.level = logging.DEBUG overrides_config = deepcopy(LOGGING_CONFIG) if cls.log_file: overrides_config["handlers"]["file"] = { "()": logging.FileHandler, "formatter": "default", "filename": cls.log_file, "filters": deepcopy( overrides_config["handlers"]["console"]["filters"] ), } overrides_config["root"]["handlers"].append("file") if disable_console: # Set console handler to None, so that # configure_logging will delete it when merging with # SKA standard config dictionary overrides_config["handlers"]["console"] = None overrides_config["root"]["handlers"].remove("console") configure_logging( level=cls.level, overrides=overrides_config, )
[docs] class LogPlugin(WorkerPlugin): """ Dask worker plugin that configures logging on worker startup. """ idempotent = True def __init__( self, log_file: str | None = None, verbose: bool = False, disable_console: bool = False, ): """ This accepts same parameters as the :py:func:`LogUtil.configure()` function. Refer to that function for details. Example ------- >>> plugin = LogPlugin(verbose=LogUtil.verbose) >>> client.register_worker_plugin(plugin) """ self.log_file = log_file self.verbose = verbose self.disable_console = disable_console
[docs] def setup(self, worker): LogUtil.configure( log_file=self.log_file, verbose=self.verbose, disable_console=self.disable_console, )
@dask.delayed def delayed_log(logger: logging.Logger, formated_log_msg: str, **kwargs): """ Log a formatted message in a Dask-delayed task. This ensures that dask delayed objects inside kwargs dictionary, whose results are needed for logging a message, are not computed eagerly. Parameters ---------- logger Logging callable that accepts a single formatted message. formated_log_msg Format string used to build the log message. **kwargs Keyword arguments used to format ``formated_log_msg``. Example ------- >>> # Assuming root logger can stream to stdout >>> logger = logging.getLogger() >>> task = delayed_log( ... logger.info, ... "{var_1} and {var_2}", ... var_1=10, ... var_2=dask.delayed(list)([1, 2, 3]) ... ) >>> task.compute() "10 and [1, 2, 3]" """ logger(formated_log_msg.format(**kwargs))