[Django]-Python django logging: One single logger with more than one logging level

2👍

Best solution I found was to create multiple handlers for one single logger:

LOGGING = {
    'version': 1,
    'disable_existing_loggers' : False,
    'loggers': {
        'general': {
            'handlers': ['error', 'info', 'debug'],
            'level': 1
        }
    },
    'handlers': {
        'std_err': {
            'class': 'logging.StreamHandler'
        },
        'info': {
            'class': 'logging.FileHandler',
            'filename': 'info.log',
            'level': 'INFO',
            'formatter': 'default',
        },
        'error': {
            'class': 'logging.FileHandler',
            'filename': 'error.log',
            'level': 'ERROR',
            'formatter': 'error',
        },
        'debug': {
            'class': 'logging.FileHandler',
            'filename': 'debug.log',
            'level': 'DEBUG',
            'formatter': 'default',
        },
    },
    'formatters': {
        'default': {
            'format': '%(asctime)s [%(module)s | %(levelname)s] %(message)s',
        },
        'error': {
            'format': '%(asctime)s [%(module)s | %(levelname)s] %(message)s @ %(pathname)s : %(lineno)d : %(funcName)s',
        },
    },
}

Which allows the following:

logger = logging.getLogger('general')
logger.error("Some error message...")
logger.debug("Debug message...")
logger.info("Some info message..")

it even allows:

logger.exception("Exception message", fmt=std.FAIL)

2👍

I think one way to use one log file for different purposes is to change your log level in your logger configs because based on this document you can not log debug level in to info level. For example look at the following configs which I usually use as my best practice:

LOG_DIR = BASE_DIR / 'logs'
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'simple': {
            'format': '[%(asctime)s] %(levelname)s %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        },
        'verbose': {
            'format': '[%(asctime)s] %(levelname)s [%(filename)s.%(funcName)s:%(lineno)d] %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        },
    },
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler',
            'formatter': 'verbose'
        },
        'file': {
            'level': 'DEBUG' if DEBUG else 'INFO',
            'class': 'logging.FileHandler',
            'filename': LOG_DIR / 'django.log',
            'formatter': 'verbose' if DEBUG else 'simple',
        },
        'db_queries': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.FileHandler',
            'filename': LOG_DIR / 'db_queries.log',
        },
        'null': {
            'level': 'DEBUG',
            'class': 'logging.NullHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'level': 'DEBUG',
            'handlers': ['db_queries'],
            'propagate': False,
        },
        'accounts': {
            'handlers': ['file', 'console'],
            'level': 'DEBUG',
        },
    },
}

And for logging just use following lines:

logger = logging.getLogger('accounts')

logger.info("some info logs")
logger.debug("some debug logs")
👤Roham

0👍

One solution might be this.

import logging

class MultiLogger(logging.Logger):
    def __init__(self, name, level=logging.INFO, formatter=None):
        self.name = name
        self.level = level
        self.formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
        logger = logging.getLogger(self.name)
        logger.setLevel(self.level)
        self.logger = logger
        super().__init__(name=name, level=level)

    def debug(self, msg, log_file="debug.log", *args, **kwargs):
        handler = logging.FileHandler(log_file)
        handler.setFormatter(self.formatter)

        for h in self.handlers:
            self.removeHandler(h)

        self.addHandler(handler)
        self.level = 10
        return super().debug(msg, *args, **kwargs)
    
    def error(self, msg, log_file="error.log", *args, **kwargs):
        handler = logging.FileHandler(log_file)
        handler.setFormatter(self.formatter)
        for h in self.handlers:
            self.removeHandler(h)
        self.addHandler(handler)
        self.level = 40
        return super().error(msg, *args, **kwargs)
    
    def warning(self, msg, log_file="warning.log", *args, **kwargs):
        handler = logging.FileHandler(log_file)
        handler.setFormatter(self.formatter)
        for h in self.handlers:
            self.removeHandler(h)
        self.addHandler(handler)
        self.level = 30
        return super().warning(msg, *args, **kwargs)
    
    def info(self, msg, log_file="info.log", *args, **kwargs):
        handler = logging.FileHandler(log_file)
        handler.setFormatter(self.formatter)
        for h in self.handlers:
            self.removeHandler(h)
        self.addHandler(handler)
        self.level = 20
        return super().info(msg, *args, **kwargs)
    
    

logger = MultiLogger(name="info_logger", level=40)
logger.debug("This is debug message", log_file="debug.log")
logger.error("This is error message", log_file="error.log")
logger.info("This is info message", log_file="info.log")
logger.warning("This is warning message", log_file="warn.log")

Leave a comment