def configure_twisted_logging(verbosity: int, mode: LoggingMode): """Configure Twisted's legacy logging system. We do this because it's what `twistd` uses. When we switch to `twist` we can update this. :param verbosity: See `get_logging_level`. :param mode: The mode in which to configure logging. See `LoggingMode`. """ set_twisted_verbosity(verbosity) warn_unless(hasattr(twistedLegacy, "startLoggingWithObserver"), ( "No startLoggingWithObserver function found; please investigate!")) twistedLegacy.startLoggingWithObserver = _startLoggingWithObserver # Set the legacy `logfile` namespace according to the environment in which # we guess we're running. This `logfile` is used primarily — in MAAS — by # Twisted's HTTP server machinery for combined access logging. twistedLegacy.logfile.log.namespace = _getCommandName(sys.argv) # Customise warnings behaviour. Ensure that nothing else — neither the # standard library's `logging` module nor Django — clobbers this later. warn_unless(warnings.showwarning.__module__ == warnings.__name__, ( "The warnings module has already been modified; please investigate!")) if mode == LoggingMode.TWISTD: twistedModern.globalLogBeginner.showwarning = show_warning_via_twisted twistedLegacy.theLogPublisher.showwarning = show_warning_via_twisted else: twistedModern.globalLogBeginner.showwarning = warnings.showwarning twistedLegacy.theLogPublisher.showwarning = warnings.showwarning # Prevent `crochet` from initialising Twisted's logging. warn_unless(hasattr(crochet._main, "_startLoggingWithObserver"), ( "No _startLoggingWithObserver function found; please investigate!")) crochet._main._startLoggingWithObserver = None # Turn off some inadvisable defaults in Twisted and elsewhere. from twisted.internet.protocol import AbstractDatagramProtocol, Factory warn_unless(hasattr(AbstractDatagramProtocol, "noisy"), ( "No AbstractDatagramProtocol.noisy attribute; please investigate!")) AbstractDatagramProtocol.noisy = False warn_unless(hasattr(Factory, "noisy"), ( "No Factory.noisy attribute; please investigate!")) Factory.noisy = False # Install filters for other noisy parts of Twisted itself. from twisted.internet import tcp, udp, unix LegacyLogger.install(tcp, observer=observe_twisted_internet_tcp) LegacyLogger.install(udp, observer=observe_twisted_internet_udp) LegacyLogger.install(unix, observer=observe_twisted_internet_unix) # Start Twisted logging if we're running a command. Use `sys.__stdout__`, # the original standard out stream when this process was started. This # bypasses any wrapping or redirection that may have been done elsewhere. if mode == LoggingMode.COMMAND: twistedModern.globalLogBeginner.beginLoggingTo( [EventLogger()], discardBuffer=False, redirectStandardIO=False)
def configure_django_logging(verbosity: int, mode: LoggingMode): """Do basic logging configuration for Django, if possible. Then destroy Django's ability to mess with logging configuration. We have to do this by monkey-patching because changing Django's settings at run-time is not supported. If Django is not installed this is a no-op. :param verbosity: See `get_logging_level`. :param mode: The mode in which to configure logging. See `LoggingMode`. """ try: from django.utils import log except ImportError: # Django not installed; nothing to be done. return # Django's default logging configuration is not great. For example it # wants to email request errors and security issues to the site admins, # but fails silently. Throw it all away. warn_unless( hasattr(log, "DEFAULT_LOGGING"), "No DEFAULT_LOGGING attribute found in Django; please investigate!", ) log.DEFAULT_LOGGING = {"version": 1, "disable_existing_loggers": False} # Prevent Django from meddling with `warnings`. There's no configuration # option for this so we have to get invasive. We also skip running-in # Django's default log configuration even though we threw it away already. def configure_logging(logging_config, logging_settings): """Reduced variant of Django's configure_logging.""" if logging_config is not None: logging_config_func = log.import_string(logging_config) logging_config_func(logging_settings) warn_unless( hasattr(log, "configure_logging"), "No configure_logging function found in Django; please investigate!", ) log.configure_logging = configure_logging # Outside of the development environment ensure that deprecation warnings # from Django are silenced. End users are _not_ interested in deprecation # warnings from Django. Developers are, however. if not is_dev_environment(): from django.utils.deprecation import RemovedInNextVersionWarning warnings.simplefilter("ignore", RemovedInNextVersionWarning)
def install(cls, module, attribute="log", *, source=None, observer=None): """Install a `LegacyLogger` at `module.attribute`. Warns if `module.attribute` does not exist, but carries on anyway. :param module: A module (or any other object with assignable attributes and a `__name__`). :param attribute: The name of the attribute on `module` to replace. :param source: See `Logger.__init__`. :param observer: See `Logger.__init__`. :return: The newly created `LegacyLogger`. """ replacing = getattr(module, attribute, "<not-found>") warn_unless(replacing is twistedLegacy, ( "Legacy logger being installed to replace %r but expected a " "reference to twisted.python.log module; please investigate!" % (replacing,))) logger = cls(module.__name__, source=source, observer=observer) setattr(module, attribute, logger) return logger