Skip to content

Commit

Permalink
Add Django support.
Browse files Browse the repository at this point in the history
* Move from django-kaneda project.
* Add integration tests.
* Improve Django documentation
  • Loading branch information
marctc committed May 3, 2016
1 parent b4fe950 commit 9b73598
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 87 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ Changelog

0.3 (2016-03-28)
~~~~~~~~~~~~~~~~
* Add LoggerBackend. Useful for debugging
* Add LoggerBackend.
* Add exeception treatment on backend report methods.
* Add connection timeout for storage backends.
* Storage backends now support passing client or connection url as parameters instead all parameters.
* Add support to use django-kaneda on debug mode.

0.2 (2016-02-17)
~~~~~~~~~~~~~~~~
Expand Down
40 changes: 40 additions & 0 deletions django_kaneda/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import logging

from django.utils.functional import LazyObject


class LazyMetrics(LazyObject):

def _setup(self):
from kaneda import Metrics
from kaneda.utils import import_class, get_object_from_settings
from kaneda.exceptions import UnexistingKanedaClass, SettingsError
from . import settings

if settings.DEBUG:
backend_class = import_class('kaneda.backends.LoggerBackend')
if settings.LOGGER:
backend = backend_class(logger=logging.getLogger(settings.LOGGER))
elif settings.LOGGER_FILENAME:
backend = backend_class(filename=settings.LOGGER_FILENAME)
else:
backend = backend_class()
_metrics = Metrics(backend=backend)
else:
if not settings.BACKEND and not settings.QUEUE:
raise SettingsError('You need to set KANEDA_BACKEND or KANEDA_QUEUE on settings.py to django_kaneda')
if settings.BACKEND:
try:
backend = get_object_from_settings(settings.BACKEND, settings)
_metrics = Metrics(backend=backend)
except UnexistingKanedaClass:
raise UnexistingKanedaClass('The selected KANEDA_BACKEND class does not exists.')
if settings.QUEUE:
try:
queue = get_object_from_settings(settings.QUEUE, settings)
_metrics = Metrics(queue=queue)
except UnexistingKanedaClass:
raise UnexistingKanedaClass('The selected KANEDA_QUEUE class does not exists.')
self._wrapped = _metrics

metrics = LazyMetrics()
35 changes: 35 additions & 0 deletions django_kaneda/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from django.conf import settings

BACKEND = getattr(settings, 'KANEDA_BACKEND', None)
QUEUE = getattr(settings, 'KANEDA_QUEUE', None)

# Elasticsearch backend settings
ELASTIC_INDEX_NAME = getattr(settings, 'KANEDA_ELASTIC_INDEX_NAME', 'kaneda')
ELASTIC_APP_NAME = getattr(settings, 'KANEDA_ELASTIC_APP_NAME', 'default')
ELASTIC_CONNECTION_URL = getattr(settings, 'KANEDA_ELASTIC_CONNECTION_URL', None)
ELASTIC_HOST = getattr(settings, 'KANEDA_ELASTIC_HOST', None)
ELASTIC_PORT = getattr(settings, 'KANEDA_ELASTIC_PORT', None)
ELASTIC_USER = getattr(settings, 'KANEDA_ELASTIC_USER', None)
ELASTIC_PASSWORD = getattr(settings, 'KANEDA_ELASTIC_PASSWORD', None)
ELASTIC_TIMEOUT = getattr(settings, 'KANEDA_ELASTIC_TIMEOUT', 0.3)

# MongoDB backend settings
MONGO_DB_NAME = getattr(settings, 'KANEDA_MONGO_DB_NAME', 'kaneda')
MONGO_COLLECTION_NAME = getattr(settings, 'KANEDA_MONGO_COLLECTION_NAME', 'default')
MONGO_CONNECTION_URL = getattr(settings, 'KANEDA_MONGO_CONNECTION_URL', None)
MONGO_HOST = getattr(settings, 'KANEDA_MONGO_HOST', None)
MONGO_PORT = getattr(settings, 'KANEDA_MONGO_PORT', None)
MONGO_TIMEOUT = getattr(settings, 'KANEDA_MONGO_TIMEOUT', 300)

# Debug backend mode settings
DEBUG = getattr(settings, 'KANEDA_DEBUG', False)
LOGGER = getattr(settings, 'KANEDA_LOGGER', None)
LOGGER_FILENAME = getattr(settings, 'KANEDA_LOGGER_FILENAME', None)

# Celery queue settings
CELERY_BROKER = getattr(settings, 'KANEDA_CELERY_BROKER', '')
CELERY_QUEUE_NAME = getattr(settings, 'KANEDA_CELERY_QUEUE_NAME', '')

# RQ queue settings
RQ_REDIS_URL = getattr(settings, 'KANEDA_RQ_REDIS_URL', 'kaneda')
RQ_QUEUE_NAME = getattr(settings, 'KANEDA_RQ_QUEUE_NAME', None)
44 changes: 33 additions & 11 deletions docs/django.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@ Django Setup

Kaneda can be use with Django as a mechanism to reporting metrics and events.

1. Install `kaneda` and `django-kaneda` packages::
1. Add :code:`django_kaneda` to :code:`INSTALLED_APPS` in :file:`settings.py`.

pip install git+https://gitlab.apsl.net/apsl/kaneda.git
pip install git+https://gitlab.apsl.net/apsl/django-kaneda.git

2. Add :code:`django_kaneda` to :code:`INSTALLED_APPS` in :file:`settings.py`.

3. Set :code:`KANEDA_BACKEND` and the properly configuration of your selected backend in :file:`settings.py`. If you want to use Elasticsearch our configuration will be something like this::
2. Set :code:`KANEDA_BACKEND` and the properly configuration of your selected backend in :file:`settings.py`. If you want to use Elasticsearch our configuration will be something like this::

KANEDA_BACKEND = 'kaneda.backends.ElasticsearchBackend'
KANEDA_ELASTIC_INDEX_NAME = 'kaneda'
Expand All @@ -22,6 +17,11 @@ Kaneda can be use with Django as a mechanism to reporting metrics and events.
KANEDA_ELASTIC_USER = 'user'
KANEDA_ELASTIC_PASSWORD = 'pass'

Alternatively you can set :code:`KANEDA_QUEUE` to specify a :ref:`queue <queues>` configuration to use Kaneda in :ref:`async mode <async>`::

KANEDA_BACKEND = 'kaneda.queues.CeleryQueue'
KANEDA_CELERY_BROKER = 'redis://localhost:6379/0'

With this, you can use Kaneda in everyplace of your Django project::

from django_kaneda import metrics
Expand Down Expand Up @@ -82,10 +82,13 @@ KANEDA_ELASTIC_INDEX_NAME (='kaneda')
KANEDA_ELASTIC_APP_NAME (='default')
Name of the app/project where metrics are used.

KANEDA_ELASTIC_HOST (='localhost')
KANEDA_ELASTIC_CONNECTION_URL (=None)
Elasticsearch connection url (https://user:secret@localhost:9200).

KANEDA_ELASTIC_HOST (=None)
Server host.

KANEDA_ELASTIC_PORT (=9200)
KANEDA_ELASTIC_PORT (=None)
Server port.

KANEDA_ELASTIC_USER (=None)
Expand All @@ -105,15 +108,34 @@ KANEDA_MONGO_DB_NAME (='kaneda')
KANEDA_MONGO_COLLECTION_NAME (='default')
Name of the MongoDB collection used to store metric data.

KANEDA_MONGO_HOST (='localhost')
KANEDA_MONGO_CONNECTION_URL (=None)
Mongo connection url (mongodb://localhost:27017/).

KANEDA_MONGO_HOST (=None)
Server host.

KANEDA_MONGO_PORT (=27017)
KANEDA_MONGO_PORT (=None)
Server port.

KANEDA_MONGO_TIMEOUT (=300)
MongoDB connection timeout (milliseconds).

Celery
------
KANEDA_CELERY_BROKER (='')
Broker connection url.

KANEDA_CELERY_QUEUE_NAME (='')
Name of the Celery queue.

RQ
--
KANEDA_RQ_REDIS_URL (='')
Redis connection url.

KANEDA_RQ_QUEUE_NAME (='kaneda')
Name of the RQ queue.

Debug
-----
KANEDA_DEBUG (=True)
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ Example::
:hidden:

usage
django
metrics
backends
queues
settings
django
changelog

2 changes: 1 addition & 1 deletion docs/queues.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Queues
======

Kaneda provides builtin queues to store metrics and events to perform :ref:`async`. If you want to use your
Kaneda provides builtin queues to store metrics and events to perform :ref:`asynchronous reporting <async>`. If you want to use your
custom asynchronous queue system you need to subclass :code:`BaseQueue` and implement your custom :code:`report` method
which is the responsible to pass metrics data to a job queue.

Expand Down
2 changes: 1 addition & 1 deletion docs/settings.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Settings
========

Kaneda can be used with a settings file as a similar way to use with :ref:`Django <django>`. Simply define a
Kaneda can be used with a settings file as the same way to use with :ref:`Django <django>`. Simply define a
:file:`kanedasettings.py` file with the backend or queue settings. Alternatively you can define the environment variable
`DEFAULT_SETTINGS_ENVAR` pointing to the desired settings filename.

Expand Down
4 changes: 2 additions & 2 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Asynchronous reporting
Depending the selection of the backend the process of reporting metrics could be "slow" if the response time of your
application is critical (e.g: a website). Furthermore if your application doesn't need the see the reported metrics
in real time you probably have to consider to using asynchronous reporting. With this system you are allowed to send a
metric report in background without affecting your performance.
metric report in background without adding too much overhead.

To use this system you need to install a queue system and use one of the builtin Kaneda :ref:`queues` classes.
To setup Kaneda in async mode follow these steps.
Expand Down Expand Up @@ -79,5 +79,5 @@ As in the backend example it can be used passing a queue client::
q = Queue(queue_name, connection=Redis())
queue = RQQueue(queue=q)

Notice that you are able to specify a Redis connection url (or a broker url if you use :ref:`Celery`). Notice this allows you
Also you are able to specify a Redis connection url (or a broker url if you use :ref:`Celery`). Notice this allows you
to run the worker on a different server.
1 change: 0 additions & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
# -*- coding: utf-8 -*-
Empty file.
30 changes: 30 additions & 0 deletions tests/integration/django/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import pytest


@pytest.fixture
def django_settings_backend(elastic_settings):
elastic_settings.DEBUG = False
elastic_settings.QUEUE = None
return elastic_settings


@pytest.fixture
def django_settings_debug():
class Settings:
DEBUG = True
LOGGER = None
LOGGER_FILENAME = None

return Settings


@pytest.fixture
def django_settings_queue(celery_settings):
celery_settings.DEBUG = False
celery_settings.BACKEND = None
return celery_settings


def pytest_configure():
from django.conf import settings
settings.configure()
29 changes: 29 additions & 0 deletions tests/integration/django/test_django.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from kaneda.backends import LoggerBackend, ElasticsearchBackend
from kaneda.queues import CeleryQueue
from django_kaneda import settings


class TestDjango(object):

def test_django_kaneda_with_backend(self, mocker, django_settings_backend):
mocker.patch('django_kaneda.settings', django_settings_backend)
from django_kaneda import LazyMetrics
metrics = LazyMetrics()
assert isinstance(metrics.backend, ElasticsearchBackend)
result = metrics.gauge('test_gauge', 42)
assert result

def test_django_kaneda_with_debug(self, mocker, django_settings_debug):
mocker.patch('django_kaneda.settings', django_settings_debug)
from django_kaneda import LazyMetrics
metrics = LazyMetrics()
metrics.gauge('test_gauge', 42)
assert isinstance(metrics.backend, LoggerBackend)

def test_django_kaneda_with_queue(self, mocker, django_settings_queue):
mocker.patch('django_kaneda.settings', django_settings_queue)
from django_kaneda import LazyMetrics
metrics = LazyMetrics()
assert isinstance(metrics.queue, CeleryQueue)
result = metrics.gauge('test_gauge', 42)
assert result
54 changes: 3 additions & 51 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,68 +12,20 @@ def report(self, name, metric, value, tags, id_=None):
self.reported_data[name] = payload


@pytest.fixture(scope='module')
@pytest.fixture
def dummy_backend():
return DummyBackend()


@pytest.fixture(scope='module')
def elasticsearch_backend_settings():
class Settings:
BACKEND = 'kaneda.backends.ElasticsearchBackend'
ELASTIC_INDEX_NAME = 'test'
ELASTIC_APP_NAME = 'test'
ELASTIC_HOST = 'localhost'
ELASTIC_PORT = 9200
ELASTIC_USER = 'test'
ELASTIC_PASSWORD = 'test'
ELASTIC_TIMEOUT = 0.3

return Settings


@pytest.fixture(scope='module')
def mongo_backend_settings():
class Settings:
BACKEND = 'kaneda.backends.MongoBackend'
MONGO_DB_NAME = 'test'
MONGO_COLLECTION_NAME = 'test'
MONGO_HOST = 'localhost'
MONGO_PORT = 27017
MONGO_TIMEOUT = 300

return Settings


@pytest.fixture(scope='module')
def rq_queue_settings():
class Settings:
QUEUE = 'kaneda.queues.RQQueue'
RQ_REDIS_URL = 'redis://localhost:6379/1'
RQ_QUEUE_NAME = ''

return Settings


@pytest.fixture(scope='module')
def celery_queue_settings():
class Settings:
QUEUE = 'kaneda.queues.CeleryQueue'
CELERY_BROKER = 'redis://localhost:6379/1'
CELERY_QUEUE_NAME = ''

return Settings


@pytest.fixture(scope='module')
@pytest.fixture
def empty_settings():
class Settings:
pass

return Settings


@pytest.fixture(scope='module')
@pytest.fixture
def unexisting_backend_settings():
class Settings:
BACKEND = 'kaneda.backends.UnexsitingBackend'
Expand Down
Loading

0 comments on commit 9b73598

Please sign in to comment.