Skip to content

Commit

Permalink
Merge pull request #386 from goodtune/feature/logging-filter
Browse files Browse the repository at this point in the history
Add TenantContextFilter for schema/domain logging
  • Loading branch information
bernardopires committed Sep 26, 2016
2 parents eceab7a + b62cbd7 commit a57d3ef
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 7 deletions.
40 changes: 37 additions & 3 deletions docs/use.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ To run only a particular schema, there is an optional argument called ``--schema
./manage.py migrate_schemas --schema=customer1
migrate_schemas
migrate_schemas
~~~~~~~~~~~~~~~

``migrate_schemas`` is the most important command on this app. The way it works is that it calls Django's ``migrate`` in two different ways. First, it calls ``migrate`` for the ``public`` schema, only syncing the shared apps. Then it runs ``migrate`` for every tenant in the database, this time only syncing the tenant apps.
Expand Down Expand Up @@ -103,8 +103,8 @@ If you don't specify a schema, you will be prompted to enter one. Otherwise, you
.. code-block:: bash
./manage.py tenant_command loaddata --schema=customer1
createsuperuser
createsuperuser
~~~~~~~~~~~~~~~

The command ``createsuperuser`` is already automatically wrapped to have a ``schema`` flag. Create a new super user with
Expand Down Expand Up @@ -210,6 +210,40 @@ get_limit_set_calls
Returns the TENANT_LIMIT_SET_CALLS setting or the default (False). See bellow.


Logging
-------

The optional ``TenantContextFilter`` can be included in ``settings.LOGGING`` to add the current ``schema_name`` and ``domain_url`` to the logging context.

.. code-block:: python
# settings.py
LOGGING = {
'filters': {
'tenant_context': {
'()': 'tenant_schemas.log.TenantContextFilter'
},
},
'formatters': {
'tenant_context': {
'format': '[%(schema_name)s:%(domain_url)s] '
'%(levelname)-7s %(asctime)s %(message)s',
},
},
'handlers': {
'console': {
'filters': ['tenant_context'],
},
},
}
This will result in logging output that looks similar to:

.. code-block:: text
[example:example.com] DEBUG 13:29 django.db.backends: (0.001) SELECT ...
Performance Considerations
--------------------------

Expand Down
10 changes: 9 additions & 1 deletion dts_test_project/dts_test_project/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,19 +125,27 @@
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
},
'tenant_context': {
'()': 'tenant_schemas.log.TenantContextFilter'
},
},
'formatters': {
'simple': {
'format': '%(levelname)-7s %(asctime)s %(message)s',
},
'tenant_context': {
'format': '[%(schema_name)s:%(domain_url)s] '
'%(levelname)-7s %(asctime)s %(message)s',
},
},
'handlers': {
'null': {
'class': 'logging.NullHandler',
},
'console': {
'class': 'logging.StreamHandler',
'formatter': 'simple',
'filters': ['tenant_context'],
'formatter': 'tenant_context',
},
},
'loggers': {
Expand Down
15 changes: 15 additions & 0 deletions tenant_schemas/log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import logging

from django.db import connection


class TenantContextFilter(logging.Filter):
"""
Add the current ``schema_name`` and ``domain_url`` to log records.
Thanks to @regolith for the snippet on #248
"""
def filter(self, record):
record.schema_name = connection.tenant.schema_name
record.domain_url = getattr(connection.tenant, 'domain_url', '')
return True
2 changes: 2 additions & 0 deletions tenant_schemas/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from test_routes import *
from test_tenants import *
from test_cache import *
from test_log import *
from test_utils import *
16 changes: 16 additions & 0 deletions tenant_schemas/tests/test_log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import logging

from django.test import TestCase

from tenant_schemas import log


class LoggingFilterTests(TestCase):

def test_tenant_context_filter(self):
filter_ = log.TenantContextFilter()
record = logging.makeLogRecord({})
res = filter_.filter(record)
self.assertEqual(res, True)
self.assertEqual(record.schema_name, 'public')
self.assertEqual(record.domain_url, '')
2 changes: 0 additions & 2 deletions tenant_schemas/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from django.core import mail



@contextmanager
def schema_context(schema_name):
previous_tenant = connection.tenant
Expand Down Expand Up @@ -117,4 +116,3 @@ def app_labels(apps_list):
if AppConfig is None:
return [app.split('.')[-1] for app in apps_list]
return [AppConfig.create(app).label for app in apps_list]

4 changes: 3 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ basepython =
usedevelop = True

deps =
coverage
dj18: Django~=1.8.0
dj19: Django~=1.9.0
dj110: Django~=1.10.0
Expand All @@ -16,4 +17,5 @@ changedir = dts_test_project
passenv = PG_USER PG_PASSWORD

commands =
{envpython} manage.py test tenant_schemas.tests --noinput -v 2
coverage run manage.py test --noinput {posargs:tenant_schemas.tests -v 2}
coverage report -m --include=../tenant_schemas/*

0 comments on commit a57d3ef

Please sign in to comment.