Skip to content

Commit d42111f

Browse files
committed
A better subclassing attempt of logging.Logger ( to add the bcdebug, verbose, and success methods directly to the logger instance)
1 parent 46b652c commit d42111f

File tree

2 files changed

+42
-35
lines changed

2 files changed

+42
-35
lines changed

bidscoin/__init__.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from pathlib import Path
2929
from importlib import metadata
3030
from typing import Tuple, Union, List
31-
from logging import getLogger
31+
import logging
3232
from .due import due, Doi
3333
try:
3434
import tomllib
@@ -42,8 +42,6 @@
4242
with open(Path(__file__).parents[1]/'pyproject.toml', 'rb') as fid:
4343
__version__ = tomllib.load(fid)['project']['version']
4444

45-
LOGGER = getLogger(__name__)
46-
4745
# Add license metadata
4846
__license__ = 'GNU General Public License v3.0 or later (GPLv3+)'
4947
__copyright__ = f"2018-{datetime.date.today().year}, Marcel Zwiers"
@@ -101,6 +99,40 @@
10199
path='bidscoin', version=__version__, cite_module=True, tags=['reference-implementation'])
102100

103101

102+
class CustomLogger(logging.Logger):
103+
"""Extend the Logger class to add custom methods for the new levels"""
104+
105+
# Define custom logging levels
106+
BCDEBUG, BCDEBUG_LEVEL = 'BCDEBUG', 11 # NB: using the standard debug mode will generate may debug messages from imports
107+
VERBOSE, VERBOSE_LEVEL = 'VERBOSE', 15
108+
SUCCESS, SUCCESS_LEVEL = 'SUCCESS', 25
109+
110+
# Add custom log levels to logging
111+
logging.addLevelName(BCDEBUG_LEVEL, BCDEBUG)
112+
logging.addLevelName(VERBOSE_LEVEL, VERBOSE)
113+
logging.addLevelName(SUCCESS_LEVEL, SUCCESS)
114+
115+
def bcdebug(self, message, *args, **kwargs):
116+
"""Custom BIDSCOIN DEBUG messages"""
117+
if self.isEnabledFor(self.BCDEBUG_LEVEL):
118+
self._log(self.BCDEBUG_LEVEL, message, args, **kwargs)
119+
120+
def verbose(self, message, *args, **kwargs):
121+
"""Custom BIDSCOIN VERBOSE messages"""
122+
if self.isEnabledFor(self.VERBOSE_LEVEL):
123+
self._log(self.VERBOSE_LEVEL, message, args, **kwargs)
124+
125+
def success(self, message, *args, **kwargs):
126+
"""Custom BIDSCOIN SUCCESS messages"""
127+
if self.isEnabledFor(self.SUCCESS_LEVEL):
128+
self._log(self.SUCCESS_LEVEL, message, args, **kwargs)
129+
130+
131+
# Get a logger from the custom logger class
132+
logging.setLoggerClass(CustomLogger)
133+
LOGGER = logging.getLogger(__name__)
134+
135+
104136
def check_version() -> Tuple[str, Union[bool, None], str]:
105137
"""
106138
Compares the BIDSCOIN version from the local metadata to the remote pypi repository

bidscoin/bcoin.py

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,12 @@ def synchronize(pbatch, jobids: list, wait: int=15):
113113
def setup_logging(logfile: Path=Path()):
114114
"""
115115
Set up the logging framework:
116-
1) Add a 'bcdebug', 'verbose' and a 'success' logging level
117-
2) Add a console streamhandler
118-
3) If logfile then add a normal log and a warning/error filehandler
116+
1) Add custom logging levels: 'bcdebug', 'verbose', and 'success'.
117+
2) Add a console stream handler for generating terminal output.
118+
3) Optionally add file handlers for normal log and warning/error log if logfile is provided.
119119
120-
:param logfile: Name of the logfile
121-
:return:
122-
"""
120+
:param logfile: Path to the logfile. If none, logging is console-only
121+
"""
123122

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

133-
# Add a BIDScoin debug logging level = 11 (NB: using the standard debug mode will generate may debug messages from imports)
134-
logging.BCDEBUG = 11
135-
logging.addLevelName(logging.BCDEBUG, 'BCDEBUG')
136-
logging.__all__ += ['BCDEBUG'] if 'BCDEBUG' not in logging.__all__ else []
137-
def bcdebug(self, message, *args, **kws):
138-
if self.isEnabledFor(logging.BCDEBUG): self._log(logging.BCDEBUG, message, args, **kws)
139-
logging.Logger.bcdebug = bcdebug
140-
141-
# Add a verbose logging level = 15
142-
logging.VERBOSE = 15
143-
logging.addLevelName(logging.VERBOSE, 'VERBOSE')
144-
logging.__all__ += ['VERBOSE'] if 'VERBOSE' not in logging.__all__ else []
145-
def verbose(self, message, *args, **kws):
146-
if self.isEnabledFor(logging.VERBOSE): self._log(logging.VERBOSE, message, args, **kws)
147-
logging.Logger.verbose = verbose
148-
149-
# Add a success logging level = 25
150-
logging.SUCCESS = 25
151-
logging.addLevelName(logging.SUCCESS, 'SUCCESS')
152-
logging.__all__ += ['SUCCESS'] if 'SUCCESS' not in logging.__all__ else []
153-
def success(self, message, *args, **kws):
154-
if self.isEnabledFor(logging.SUCCESS): self._log(logging.SUCCESS, message, args, **kws)
155-
logging.Logger.success = success
156-
157-
# Set the root logging level
132+
# Get the root logger and set the appropriate level
158133
logger = logging.getLogger()
159134
logger.setLevel('BCDEBUG' if DEBUG else 'VERBOSE')
160135

@@ -194,7 +169,7 @@ def reporterrors() -> str:
194169

195170
# Find the filehandlers and report the errors and warnings
196171
errors = ''
197-
for handler in logging.getLogger().handlers:
172+
for handler in LOGGER.handlers:
198173
if handler.name == 'errorhandler':
199174

200175
errorfile = Path(handler.baseFilename)

0 commit comments

Comments
 (0)