View file File name : mixins.py Content :""" salt._logging.mixins ~~~~~~~~~~~~~~~~~~~~ Logging related mix-ins """ import logging import sys class NewStyleClassMixin: """ Simple new style class to make pylint shut up! This is required because SaltLoggingClass can't subclass object directly: 'Cannot create a consistent method resolution order (MRO) for bases' """ class LoggingProfileMixin: """ Simple mix-in class to add a trace method to python's logging. """ def profile(self, msg, *args, **kwargs): self.log(getattr(logging, "PROFILE", 15), msg, *args, **kwargs) class LoggingTraceMixin: """ Simple mix-in class to add a trace method to python's logging. """ def trace(self, msg, *args, **kwargs): self.log(getattr(logging, "TRACE", 5), msg, *args, **kwargs) class LoggingGarbageMixin: """ Simple mix-in class to add a garbage method to python's logging. """ def garbage(self, msg, *args, **kwargs): self.log(getattr(logging, "GARBAGE", 5), msg, *args, **kwargs) class LoggingMixinMeta(type): """ This class is called whenever a new instance of ``SaltLoggingClass`` is created. What this class does is check if any of the bases have a `trace()` or a `garbage()` method defined, if they don't we add the respective mix-ins to the bases. """ def __new__(mcs, name, bases, attrs): include_profile = include_trace = include_garbage = True bases = list(bases) if name == "SaltLoggingClass": for base in bases: if hasattr(base, "trace"): include_trace = False if hasattr(base, "garbage"): include_garbage = False if include_profile: bases.append(LoggingProfileMixin) if include_trace: bases.append(LoggingTraceMixin) if include_garbage: bases.append(LoggingGarbageMixin) return super().__new__(mcs, name, tuple(bases), attrs) class ExcInfoOnLogLevelFormatMixin: """ Logging handler class mixin to properly handle including exc_info on a per logging handler basis """ def format(self, record): """ Format the log record to include exc_info if the handler is enabled for a specific log level """ formatted_record = super().format(record) exc_info_on_loglevel = getattr(record, "exc_info_on_loglevel", None) exc_info_on_loglevel_formatted = getattr( record, "exc_info_on_loglevel_formatted", None ) if exc_info_on_loglevel is None and exc_info_on_loglevel_formatted is None: return formatted_record # If we reached this far it means the log record was created with exc_info_on_loglevel # If this specific handler is enabled for that record, then we should format it to # include the exc_info details if self.level > exc_info_on_loglevel: # This handler is not enabled for the desired exc_info_on_loglevel, don't include exc_info return formatted_record # If we reached this far it means we should include exc_info if ( not record.exc_info_on_loglevel_instance and not exc_info_on_loglevel_formatted ): # This should actually never occur return formatted_record if record.exc_info_on_loglevel_formatted is None: # Let's cache the formatted exception to avoid recurring conversions and formatting calls if ( self.formatter is None ): # pylint: disable=access-member-before-definition self.formatter = logging._defaultFormatter record.exc_info_on_loglevel_formatted = self.formatter.formatException( record.exc_info_on_loglevel_instance ) # Let's format the record to include exc_info just like python's logging formatted does if formatted_record[-1:] != "\n": formatted_record += "\n" try: formatted_record += record.exc_info_on_loglevel_formatted except UnicodeError: # According to the standard library logging formatter comments: # # Sometimes filenames have non-ASCII chars, which can lead # to errors when s is Unicode and record.exc_text is str # See issue 8924. # We also use replace for when there are multiple # encodings, e.g. UTF-8 for the filesystem and latin-1 # for a script. See issue 13232. formatted_record += record.exc_info_on_loglevel_formatted.decode( sys.getfilesystemencoding(), "replace" ) # Reset the record.exc_info_on_loglevel_instance because it might need # to "travel" through a multiprocessing process and it might contain # data which is not pickle'able record.exc_info_on_loglevel_instance = None return formatted_record