I have developed a custom logger class known as ClassNameLogger, which includes an additional parameter called 'className'. I have integrated this specialized logger class into the settings.py by utilizing the logger.setLoggerClass(ClassNameLogger) method. Consequently, when I initiate the server, it successfully commences; however, I am encountering a logging error. I am also getting the logs as expected. But I want to resolve this logging error. The error says:
--- Logging error ---
Traceback (most recent call last):
File "C:\Users\z004mtzy\AppData\Local\Programs\Python\Python310\lib\logging\__init__.py", line 440, in format
return self._format(record)
File "C:\Users\z004mtzy\AppData\Local\Programs\Python\Python310\lib\logging\__init__.py", line 458, in _format
return self._fmt.format(**values)
KeyError: 'className'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\z004mtzy\AppData\Local\Programs\Python\Python310\lib\logging\handlers.py", line 73, in emit
if self.shouldRollover(record):
File "C:\Users\z004mtzy\AppData\Local\Programs\Python\Python310\lib\logging\handlers.py", line 196, in shouldRollover
msg = "%s\n" % self.format(record)
File "C:\Users\z004mtzy\AppData\Local\Programs\Python\Python310\lib\logging\__init__.py", line 943, in format
return fmt.format(record)
File "D:\ws1\hmi.dashboard\dashboard\custom_logging.py", line 18, in format
File "C:\Users\z004mtzy\AppData\Local\Programs\Python\Python310\lib\logging\__init__.py", line 681, in format
s = self.formatMessage(record)
File "C:\Users\z004mtzy\AppData\Local\Programs\Python\Python310\lib\logging\__init__.py", line 650, in formatMessage
return self._style.format(record)
File "C:\Users\z004mtzy\AppData\Local\Programs\Python\Python310\lib\logging\__init__.py", line 442, in format
raise ValueError('Formatting field not found in record: %s' % e)
ValueError: Formatting field not found in record: 'className'
Here is my custom_logging.py:
import logging
class ClassNameLogger(logging.Logger):
def __init__(self, name):
super().__init__(name)
def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False):
if extra is None:
extra = {}
# Automatically add the class name to the extra attributes
extra['className'] = self.name
super()._log(level, msg, args, exc_info, extra, stack_info)
class CustomFormatter(logging.Formatter):
def format(self, record):
if 'className' in record.__dict__:
record.msg = f"[{record.__dict__['className']}] {record.msg}"
return super().format(record)
And my settings.py is like this
import dashboard.custom_logging
LOGS_DIR = os.path.join(Path("D:\practice"), "example")
logging.setLoggerClass(dashboard.custom_logging.ClassNameLogger)
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'dashboard': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # Use the custom handler defined in this script
#Modify this filename before starting the server, this file name used for deployement
'filename': os.path.join(LOGS_DIR, "example.log"),
'backupCount': 14, # Number of backup files to keep
'maxBytes': 52428800, #Roll over once the file size reaches 50 MB
'formatter': 'verbose',
},
},
'formatters': {
'verbose': {
'()': 'dashboard.custom_logging.CustomFormatter',
'format': '{levelname} :::: {asctime} :::: {module} :::: {className} :::: {funcName} :::: {lineno} :::: {message}',
'style': '{',
},
},
'root': {
'handlers': ['dashboard'],
'level': 'DEBUG', # Adjust the level as needed
'propagate': False, # Prevent propagation to the root logger
}
}
#Set the custom logger class and configure logging
logging.config.dictConfig(LOGGING)
Here is the example of how I used the logger:
from custom_logging import ClassNameLogger
# Create an instance of ClassNameLogger
logger = ClassNameLogger(__class__.__name__)
# Log messages using the custom logger
logger.debug('Debug message')