{"id":8653,"library":"snakemake-interface-logger-plugins","title":"Snakemake Logger Plugin Interface","description":"The `snakemake-interface-logger-plugins` library provides the abstract base classes and registry for implementing custom logger plugins for Snakemake. It defines the interface for `LoggerPlugin` and `LoggerWrapper` classes, allowing users to extend Snakemake's logging capabilities. The current version is 2.0.1 and it follows the Snakemake plugin API's release cadence, typically tied to major Snakemake versions.","status":"active","version":"2.0.1","language":"en","source_language":"en","source_url":"https://github.com/snakemake/snakemake-interface-logger-plugins","tags":["snakemake","plugin","logging","interface","workflow_management"],"install":[{"cmd":"pip install snakemake-interface-logger-plugins","lang":"bash","label":"Install core interface"},{"cmd":"pip install snakemake","lang":"bash","label":"Install Snakemake (required for use)"}],"dependencies":[{"reason":"Used internally for the plugin system.","package":"pluggy","optional":false},{"reason":"This library provides an interface for Snakemake; it cannot be used standalone.","package":"snakemake","optional":false}],"imports":[{"symbol":"LoggerPlugin","correct":"from snakemake_interface_logger_plugins.plugin import LoggerPlugin"},{"symbol":"LoggerWrapper","correct":"from snakemake_interface_logger_plugins.wrapper import LoggerWrapper"},{"symbol":"CommonLoggerSettings","correct":"from snakemake_interface_logger_plugins.settings import CommonLoggerSettings"}],"quickstart":{"code":"import os\nfrom argparse import ArgumentParser\nfrom snakemake_interface_logger_plugins.plugin import LoggerPlugin\nfrom snakemake_interface_logger_plugins.wrapper import LoggerWrapper\nfrom snakemake_interface_logger_plugins.settings import CommonLoggerSettings\n\n# Save this as my_custom_logger.py\n\nclass MyLoggerPlugin(LoggerPlugin):\n    \"\"\"A simple custom logger plugin for Snakemake.\"\"\"\n    def __init__(self, settings: CommonLoggerSettings | None = None):\n        self.settings = settings\n\n    def register_args(self, argparser: ArgumentParser):\n        \"\"\"Register command line arguments for this plugin.\"\"\"\n        argparser.add_argument(\n            \"--my-logger-prefix\",\n            default=\"[CUSTOM LOG]\",\n            help=\"Prefix for custom logger messages.\"\n        )\n\n    def setup(self):\n        \"\"\"Perform setup actions before any logging occurs.\"\"\"\n        # Access custom args via self.settings if defined\n        # print(f\"{self.settings.my_logger_prefix} Initializing MyLoggerPlugin...\")\n        pass # For this minimal example, we don't need complex setup\n\n    def get_wrapper(self) -> LoggerWrapper:\n        \"\"\"Return an instance of the logger wrapper.\"\"\"\n        return MyLoggerWrapper(self.settings)\n\nclass MyLoggerWrapper(LoggerWrapper):\n    \"\"\"Handles actual logging events.\"\"\"\n    def __init__(self, settings: CommonLoggerSettings | None = None):\n        self.settings = settings\n\n    def handle_info(self, msg: str):\n        prefix = getattr(self.settings, 'my_logger_prefix', '[MYLOGGER]')\n        print(f\"{prefix} INFO: {msg}\")\n\n    def handle_error(self, msg: str):\n        prefix = getattr(self.settings, 'my_logger_prefix', '[MYLOGGER]')\n        print(f\"{prefix} ERROR: {msg}\")\n\n    # Implement other handle_* methods as needed for full functionality\n    # e.g., handle_log, handle_job_info, handle_job_error, handle_start, handle_finish, etc.\n    # For this example, we only show info and error.\n    # All abstract methods must be implemented, even if with a 'pass'\n    def handle_log(self, msg: str):\n        prefix = getattr(self.settings, 'my_logger_prefix', '[MYLOGGER]')\n        print(f\"{prefix} LOG: {msg}\")\n\n    def handle_start(self):\n        prefix = getattr(self.settings, 'my_logger_prefix', '[MYLOGGER]')\n        print(f\"{prefix} Workflow started.\")\n\n    def handle_finish(self):\n        prefix = getattr(self.settings, 'my_logger_prefix', '[MYLOGGER]')\n        print(f\"{prefix} Workflow finished.\")\n\n    def handle_job_info(self, job_info: dict):\n        prefix = getattr(self.settings, 'my_logger_prefix', '[MYLOGGER]')\n        print(f\"{prefix} Job info: {job_info.get('jobid')} - {job_info.get('output')}\")\n\n    def handle_job_error(self, job_info: dict):\n        prefix = getattr(self.settings, 'my_logger_prefix', '[MYLOGGER]')\n        print(f\"{prefix} Job error: {job_info.get('jobid')} - {job_info.get('output')}\")\n\n# To run this with Snakemake, save it as `my_custom_logger.py` and then run:\n# snakemake --snakefile Snakefile --logger-plugin my_custom_logger.py --my-logger-prefix \"[SNAKEMAKE-CUSTOM]\" -c1\n# (Requires a simple Snakefile, e.g., 'rule all: run: print(\"Hello from Snakemake\")')\n","lang":"python","description":"This quickstart demonstrates how to create a basic Snakemake logger plugin. It defines `MyLoggerPlugin` (the entry point for Snakemake) and `MyLoggerWrapper` (which handles the actual logging messages). It also shows how to register custom command-line arguments and access them via settings. To use, save the code as `my_custom_logger.py` and run Snakemake with `--logger-plugin my_custom_logger.py`."},"warnings":[{"fix":"Upgrade `snakemake-interface-logger-plugins` to version 2.0.0 or higher to match Snakemake 8.0+ requirements. If targeting older Snakemake versions, pin `snakemake-interface-logger-plugins` to a compatible 1.x version.","message":"The logger plugin API underwent a significant redesign with Snakemake 8.0. Versions of `snakemake-interface-logger-plugins` prior to 2.0.0 (e.g., 1.x) are not compatible with Snakemake 8.0+.","severity":"breaking","affected_versions":"<2.0.0"},{"fix":"Ensure the path provided to `--logger-plugin` is correct and the Python file/module is accessible from where Snakemake is run. For packages, ensure the plugin module is importable and that it contains a class named `LoggerPlugin`.","message":"Snakemake's plugin discovery requires the `--logger-plugin` argument to point to a valid Python file (e.g., `my_plugin.py`) or a discoverable Python module (e.g., `my_package.my_module`). Incorrect paths or non-discoverable modules will prevent the plugin from loading.","severity":"gotcha","affected_versions":"All"},{"fix":"Refer to the `LoggerPlugin` and `LoggerWrapper` base classes for the full list of abstract methods (e.g., `handle_info`, `handle_error`, `handle_job_info`, `setup`, `register_args`, `get_wrapper`). Implement all of them, even if with a `pass` statement, if no specific action is needed.","message":"When implementing `LoggerPlugin` or `LoggerWrapper`, you must implement all abstract methods defined in the interface. Failing to do so will result in `TypeError` when attempting to instantiate your plugin.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Implement all abstract methods defined in `snakemake_interface_logger_plugins.plugin.LoggerPlugin` and `snakemake_interface_logger_plugins.wrapper.LoggerWrapper` in your custom classes.","cause":"Your custom logger plugin class `MyLoggerPlugin` (or `MyLoggerWrapper`) is missing implementations for one or more abstract methods inherited from `LoggerPlugin` or `LoggerWrapper`.","error":"TypeError: Can't instantiate abstract class MyLoggerPlugin with abstract methods get_wrapper, register_args, setup"},{"fix":"Verify the `--logger-plugin` argument points to the correct file path or an importable Python module. Ensure the file exists and is accessible, or that the module is correctly installed and discoverable in the Python environment. Also, ensure your plugin class is named `LoggerPlugin` in the specified file/module.","cause":"The Python file or module specified with `--logger-plugin` could not be found or imported by Snakemake, or it does not contain a class named `LoggerPlugin`.","error":"snakemake.exceptions.PluginError: Could not find logger plugin 'my_non_existent_plugin.py'"}]}