Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fixed #21714 -- Moved logging configuration to global setup()
Thanks Aymeric Augustin for the report and the review.
  • Loading branch information
claudep committed Dec 31, 2013
1 parent 1d23d76 commit b8e3373
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 41 deletions.
9 changes: 7 additions & 2 deletions django/__init__.py
Expand Up @@ -9,8 +9,13 @@ def get_version(*args, **kwargs):


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.conf import settings
from django.utils.log import configure_logging

configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
apps.populate(settings.INSTALLED_APPS)
27 changes: 0 additions & 27 deletions django/conf/__init__.py
Expand Up @@ -7,16 +7,12 @@
"""

import importlib
import logging
import os
import sys
import time # Needed for Windows
import warnings

from django.conf import global_settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import LazyObject, empty
from django.utils.module_loading import import_by_path
from django.utils import six

ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
Expand Down Expand Up @@ -44,34 +40,12 @@ def _setup(self, name=None):
% (desc, ENVIRONMENT_VARIABLE))

self._wrapped = Settings(settings_module)
self._configure_logging()

def __getattr__(self, name):
if self._wrapped is empty:
self._setup(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):
"""
Called to manually configure the settings. The 'default_settings'
Expand All @@ -84,7 +58,6 @@ def configure(self, default_settings=global_settings, **options):
for name, value in options.items():
setattr(holder, name, value)
self._wrapped = holder
self._configure_logging()

@property
def configured(self):
Expand Down
21 changes: 21 additions & 0 deletions django/utils/log.py
@@ -1,8 +1,11 @@
import logging
import sys
import warnings

from django.conf import settings
from django.core import mail
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

# Imports kept for backwards-compatibility in Django 1.7.
Expand Down Expand Up @@ -61,6 +64,24 @@
}


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):
"""An exception log handler that emails log entries to site admins.
Expand Down
8 changes: 3 additions & 5 deletions docs/topics/logging.txt
Expand Up @@ -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
setting ``disable_existing_loggers`` to ``False``.

Logging is configured as soon as settings have been loaded
(either manually using :func:`~django.conf.settings.configure` or when at least
one setting is accessed). Since the loading of settings is one of the first
things that Django does, you can be certain that loggers are always ready for
use in your project code.
Logging is configured as part of the general Django ``setup()`` function.
Therefore, 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

Expand Down
12 changes: 5 additions & 7 deletions tests/logging_tests/tests.py
Expand Up @@ -3,7 +3,6 @@
import logging
import warnings

from django.conf import LazySettings
from django.core import mail
from django.test import TestCase, RequestFactory, override_settings
from django.test.utils import patch_logger
Expand Down Expand Up @@ -342,15 +341,14 @@ def dictConfig(config):
dictConfig.called = False


class SettingsConfigureLogging(TestCase):
class SetupConfigureLogging(TestCase):
"""
Test that calling settings.configure() initializes the logging
configuration.
Test that calling django.setup() initializes the logging configuration.
"""
@override_settings(LOGGING_CONFIG='logging_tests.tests.dictConfig')
def test_configure_initializes_logging(self):
settings = LazySettings()
settings.configure(
LOGGING_CONFIG='logging_tests.tests.dictConfig')
from django import setup
setup()
self.assertTrue(dictConfig.called)


Expand Down

1 comment on commit b8e3373

@jezdez
Copy link
Contributor

@jezdez jezdez commented on b8e3373 Jan 1, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙇

Please sign in to comment.