Skip to content

Commit

Permalink
A better subclassing attempt of logging.Logger ( to add the bcdebug, …
Browse files Browse the repository at this point in the history
…verbose, and success methods directly to the logger instance)
  • Loading branch information
marcelzwiers committed Oct 25, 2024
1 parent 46b652c commit d42111f
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 35 deletions.
38 changes: 35 additions & 3 deletions bidscoin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from pathlib import Path
from importlib import metadata
from typing import Tuple, Union, List
from logging import getLogger
import logging
from .due import due, Doi
try:
import tomllib
Expand All @@ -42,8 +42,6 @@
with open(Path(__file__).parents[1]/'pyproject.toml', 'rb') as fid:
__version__ = tomllib.load(fid)['project']['version']

LOGGER = getLogger(__name__)

# Add license metadata
__license__ = 'GNU General Public License v3.0 or later (GPLv3+)'
__copyright__ = f"2018-{datetime.date.today().year}, Marcel Zwiers"
Expand Down Expand Up @@ -101,6 +99,40 @@
path='bidscoin', version=__version__, cite_module=True, tags=['reference-implementation'])


class CustomLogger(logging.Logger):
"""Extend the Logger class to add custom methods for the new levels"""

# Define custom logging levels
BCDEBUG, BCDEBUG_LEVEL = 'BCDEBUG', 11 # NB: using the standard debug mode will generate may debug messages from imports
VERBOSE, VERBOSE_LEVEL = 'VERBOSE', 15
SUCCESS, SUCCESS_LEVEL = 'SUCCESS', 25

# Add custom log levels to logging
logging.addLevelName(BCDEBUG_LEVEL, BCDEBUG)
logging.addLevelName(VERBOSE_LEVEL, VERBOSE)
logging.addLevelName(SUCCESS_LEVEL, SUCCESS)

def bcdebug(self, message, *args, **kwargs):
"""Custom BIDSCOIN DEBUG messages"""
if self.isEnabledFor(self.BCDEBUG_LEVEL):
self._log(self.BCDEBUG_LEVEL, message, args, **kwargs)

def verbose(self, message, *args, **kwargs):
"""Custom BIDSCOIN VERBOSE messages"""
if self.isEnabledFor(self.VERBOSE_LEVEL):
self._log(self.VERBOSE_LEVEL, message, args, **kwargs)

def success(self, message, *args, **kwargs):
"""Custom BIDSCOIN SUCCESS messages"""
if self.isEnabledFor(self.SUCCESS_LEVEL):
self._log(self.SUCCESS_LEVEL, message, args, **kwargs)


# Get a logger from the custom logger class
logging.setLoggerClass(CustomLogger)
LOGGER = logging.getLogger(__name__)


def check_version() -> Tuple[str, Union[bool, None], str]:
"""
Compares the BIDSCOIN version from the local metadata to the remote pypi repository
Expand Down
39 changes: 7 additions & 32 deletions bidscoin/bcoin.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,12 @@ def synchronize(pbatch, jobids: list, wait: int=15):
def setup_logging(logfile: Path=Path()):
"""
Set up the logging framework:
1) Add a 'bcdebug', 'verbose' and a 'success' logging level
2) Add a console streamhandler
3) If logfile then add a normal log and a warning/error filehandler
1) Add custom logging levels: 'bcdebug', 'verbose', and 'success'.
2) Add a console stream handler for generating terminal output.
3) Optionally add file handlers for normal log and warning/error log if logfile is provided.
:param logfile: Name of the logfile
:return:
"""
:param logfile: Path to the logfile. If none, logging is console-only
"""

# Set the default formats
if DEBUG:
Expand All @@ -130,31 +129,7 @@ def setup_logging(logfile: Path=Path()):
cfmt = '%(levelname)s | %(message)s'
datefmt = '%Y-%m-%d %H:%M:%S'

# Add a BIDScoin debug logging level = 11 (NB: using the standard debug mode will generate may debug messages from imports)
logging.BCDEBUG = 11
logging.addLevelName(logging.BCDEBUG, 'BCDEBUG')
logging.__all__ += ['BCDEBUG'] if 'BCDEBUG' not in logging.__all__ else []
def bcdebug(self, message, *args, **kws):
if self.isEnabledFor(logging.BCDEBUG): self._log(logging.BCDEBUG, message, args, **kws)
logging.Logger.bcdebug = bcdebug

# Add a verbose logging level = 15
logging.VERBOSE = 15
logging.addLevelName(logging.VERBOSE, 'VERBOSE')
logging.__all__ += ['VERBOSE'] if 'VERBOSE' not in logging.__all__ else []
def verbose(self, message, *args, **kws):
if self.isEnabledFor(logging.VERBOSE): self._log(logging.VERBOSE, message, args, **kws)
logging.Logger.verbose = verbose

# Add a success logging level = 25
logging.SUCCESS = 25
logging.addLevelName(logging.SUCCESS, 'SUCCESS')
logging.__all__ += ['SUCCESS'] if 'SUCCESS' not in logging.__all__ else []
def success(self, message, *args, **kws):
if self.isEnabledFor(logging.SUCCESS): self._log(logging.SUCCESS, message, args, **kws)
logging.Logger.success = success

# Set the root logging level
# Get the root logger and set the appropriate level
logger = logging.getLogger()
logger.setLevel('BCDEBUG' if DEBUG else 'VERBOSE')

Expand Down Expand Up @@ -194,7 +169,7 @@ def reporterrors() -> str:

# Find the filehandlers and report the errors and warnings
errors = ''
for handler in logging.getLogger().handlers:
for handler in LOGGER.handlers:
if handler.name == 'errorhandler':

errorfile = Path(handler.baseFilename)
Expand Down

0 comments on commit d42111f

Please sign in to comment.