Fixed #21714 -- Moved logging configuration to global setup()

Thanks Aymeric Augustin for the report and the review.
This commit is contained in:
Claude Paroz 2013-12-31 12:28:01 +01:00
parent 1d23d766ab
commit b8e3373f45
5 changed files with 36 additions and 41 deletions

View File

@ -9,8 +9,13 @@ def get_version(*args, **kwargs):
def setup(): def setup():
# Configure the settings (this happens as a side effect of accessing """
# INSTALLED_APPS or any other setting) and populate the app registry. Configure the settings (this happens as a side effect of accessing the
first setting), configure logging and populate the app registry.
"""
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.utils.log import configure_logging
configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
apps.populate(settings.INSTALLED_APPS) apps.populate(settings.INSTALLED_APPS)

View File

@ -7,16 +7,12 @@ a list of all possible variables.
""" """
import importlib import importlib
import logging
import os import os
import sys
import time # Needed for Windows import time # Needed for Windows
import warnings
from django.conf import global_settings from django.conf import global_settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import LazyObject, empty from django.utils.functional import LazyObject, empty
from django.utils.module_loading import import_by_path
from django.utils import six from django.utils import six
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
@ -44,34 +40,12 @@ class LazySettings(LazyObject):
% (desc, ENVIRONMENT_VARIABLE)) % (desc, ENVIRONMENT_VARIABLE))
self._wrapped = Settings(settings_module) self._wrapped = Settings(settings_module)
self._configure_logging()
def __getattr__(self, name): def __getattr__(self, name):
if self._wrapped is empty: if self._wrapped is empty:
self._setup(name) self._setup(name)
return getattr(self._wrapped, name) return getattr(self._wrapped, name)
def _configure_logging(self):
"""
Setup logging from LOGGING_CONFIG and LOGGING settings.
"""
if not sys.warnoptions:
# Route warnings through python logging
logging.captureWarnings(True)
# Allow DeprecationWarnings through the warnings filters
warnings.simplefilter("default", DeprecationWarning)
if self.LOGGING_CONFIG:
from django.utils.log import DEFAULT_LOGGING
# First find the logging configuration function ...
logging_config_func = import_by_path(self.LOGGING_CONFIG)
logging_config_func(DEFAULT_LOGGING)
# ... then invoke it with the logging settings
if self.LOGGING:
logging_config_func(self.LOGGING)
def configure(self, default_settings=global_settings, **options): def configure(self, default_settings=global_settings, **options):
""" """
Called to manually configure the settings. The 'default_settings' Called to manually configure the settings. The 'default_settings'
@ -84,7 +58,6 @@ class LazySettings(LazyObject):
for name, value in options.items(): for name, value in options.items():
setattr(holder, name, value) setattr(holder, name, value)
self._wrapped = holder self._wrapped = holder
self._configure_logging()
@property @property
def configured(self): def configured(self):

View File

@ -1,8 +1,11 @@
import logging import logging
import sys
import warnings
from django.conf import settings from django.conf import settings
from django.core import mail from django.core import mail
from django.core.mail import get_connection from django.core.mail import get_connection
from django.utils.module_loading import import_by_path
from django.views.debug import ExceptionReporter, get_exception_reporter_filter from django.views.debug import ExceptionReporter, get_exception_reporter_filter
# Imports kept for backwards-compatibility in Django 1.7. # Imports kept for backwards-compatibility in Django 1.7.
@ -61,6 +64,24 @@ DEFAULT_LOGGING = {
} }
def configure_logging(logging_config, logging_settings):
if not sys.warnoptions:
# Route warnings through python logging
logging.captureWarnings(True)
# Allow DeprecationWarnings through the warnings filters
warnings.simplefilter("default", DeprecationWarning)
if logging_config:
# First find the logging configuration function ...
logging_config_func = import_by_path(logging_config)
logging_config_func(DEFAULT_LOGGING)
# ... then invoke it with the logging settings
if logging_settings:
logging_config_func(logging_settings)
class AdminEmailHandler(logging.Handler): class AdminEmailHandler(logging.Handler):
"""An exception log handler that emails log entries to site admins. """An exception log handler that emails log entries to site admins.

View File

@ -222,11 +222,9 @@ set to ``True`` (which is the default) the default configuration is completely
overridden. Alternatively you can redefine some or all of the loggers by overridden. Alternatively you can redefine some or all of the loggers by
setting ``disable_existing_loggers`` to ``False``. setting ``disable_existing_loggers`` to ``False``.
Logging is configured as soon as settings have been loaded Logging is configured as part of the general Django ``setup()`` function.
(either manually using :func:`~django.conf.settings.configure` or when at least Therefore, you can be certain that loggers are always ready for use in your
one setting is accessed). Since the loading of settings is one of the first project code.
things that Django does, you can be certain that loggers are always ready for
use in your project code.
.. _dictConfig format: http://docs.python.org/library/logging.config.html#configuration-dictionary-schema .. _dictConfig format: http://docs.python.org/library/logging.config.html#configuration-dictionary-schema

View File

@ -3,7 +3,6 @@ from __future__ import unicode_literals
import logging import logging
import warnings import warnings
from django.conf import LazySettings
from django.core import mail from django.core import mail
from django.test import TestCase, RequestFactory, override_settings from django.test import TestCase, RequestFactory, override_settings
from django.test.utils import patch_logger from django.test.utils import patch_logger
@ -342,15 +341,14 @@ def dictConfig(config):
dictConfig.called = False dictConfig.called = False
class SettingsConfigureLogging(TestCase): class SetupConfigureLogging(TestCase):
""" """
Test that calling settings.configure() initializes the logging Test that calling django.setup() initializes the logging configuration.
configuration.
""" """
@override_settings(LOGGING_CONFIG='logging_tests.tests.dictConfig')
def test_configure_initializes_logging(self): def test_configure_initializes_logging(self):
settings = LazySettings() from django import setup
settings.configure( setup()
LOGGING_CONFIG='logging_tests.tests.dictConfig')
self.assertTrue(dictConfig.called) self.assertTrue(dictConfig.called)