import logging from .handler import NOTICE, EMERGENCY, ALERT from logging import CRITICAL, ERROR, WARNING, INFO, DEBUG class Rfc5424SysLogAdapter(logging.LoggerAdapter): _extra_levels_enabled = False def __init__(self, logger, extra=None, enable_extra_levels=False): """ Initialize the adapter with a logger and a dict-like object which provides contextual information. This constructor signature allows easy stacking of LoggerAdapters, if so desired. The dictionary passed as the ``extra`` argument will be included in every message sent via the adapter. Example: You can effectively pass keyword arguments as shown in the following example:: >>> adapter = Rfc5424SysLogAdapter(someLogger, dict(p1=v1, p2="v2")) Args: logger (logging.Logger): A Logger class instance extra (dict): A Dictionary with extra contextual information, sent with every message. enable_extra_levels (bool): Add custom log levels to the logging framework. Use with caution because it can conflict with other packages defining custom levels. """ if enable_extra_levels and not Rfc5424SysLogAdapter._extra_levels_enabled: logging.addLevelName(EMERGENCY, 'EMERG') logging.addLevelName(EMERGENCY, 'EMERGENCY') logging.addLevelName(ALERT, 'ALERT') logging.addLevelName(NOTICE, 'NOTICE') Rfc5424SysLogAdapter._extra_levels_enabled = True if extra is not None and not isinstance(extra, dict): raise TypeError("Parameter extra must be a dictionary") super(Rfc5424SysLogAdapter, self).__init__(logger, extra or {}) def process(self, msg=None, kwargs=None): """ Process the logging message and keyword arguments passed in to a logging call to insert contextual information. Searches for ``msgid`` and ``sd`` or ``structured_data`` in the keyword arguments and puts them in the ``extra`` keyword argument We don't touch other keyword arguments so we don't interfere with possible other logger adapters """ hostname = kwargs.pop('hostname', None) appname = kwargs.pop('appname', None) procid = kwargs.pop('procid', None) msgid = kwargs.pop('msgid', None) structured_data = kwargs.pop('sd', None) if structured_data is None: structured_data = kwargs.pop('structured_data', None) extra = self.extra.copy() extra.update(kwargs.get('extra', {})) kwargs['extra'] = extra if hostname: kwargs['extra']['hostname'] = hostname if appname: kwargs['extra']['appname'] = appname if procid: kwargs['extra']['procid'] = procid if msgid: kwargs['extra']['msgid'] = msgid if structured_data: kwargs['extra']['structured_data'] = structured_data return msg, kwargs def log(self, level, msg=None, *args, **kwargs): # If custom levels are not enabled, we convert # the level to a standard one if not Rfc5424SysLogAdapter._extra_levels_enabled: if level == EMERGENCY or level == ALERT: level = logging.CRITICAL elif level == NOTICE: level = logging.WARNING super(Rfc5424SysLogAdapter, self).log(level, msg, *args, **kwargs) def emergency(self, msg=None, *args, **kwargs): self.log(EMERGENCY, msg, *args, **kwargs) emerg = emergency def alert(self, msg=None, *args, **kwargs): self.log(ALERT, msg, *args, **kwargs) def critical(self, msg=None, *args, **kwargs): self.log(CRITICAL, msg, *args, **kwargs) def error(self, msg=None, *args, **kwargs): self.log(ERROR, msg, *args, **kwargs) def warning(self, msg=None, *args, **kwargs): self.log(WARNING, msg, *args, **kwargs) warn = warning def notice(self, msg=None, *args, **kwargs): self.log(NOTICE, msg, *args, **kwargs) def info(self, msg=None, *args, **kwargs): self.log(INFO, msg, *args, **kwargs) def debug(self, msg=None, *args, **kwargs): self.log(DEBUG, msg, *args, **kwargs)