Commit 1c29d33a by Gabe Mulley

port mongodb backend from edx-platform

parent caa49ced
"""
Event tracking backend module.
Contains the base class for event trackers, and implementation of some
backends.
"""
from __future__ import absolute_import
import abc
# pylint: disable=unused-argument
class BaseBackend(object):
"""
Abstract Base Class for event tracking backends.
"""
__metaclass__ = abc.ABCMeta
def __init__(self, **kwargs):
pass
@abc.abstractmethod
def send(self, event):
"""Send event to tracker."""
pass
"""MongoDB event tracker backend."""
from __future__ import absolute_import
import logging
import pymongo
from pymongo import MongoClient
from pymongo.errors import PyMongoError
from track.backends import BaseBackend
log = logging.getLogger('track.backends.mongodb')
class MongoBackend(BaseBackend):
"""Class for a MongoDB event tracker Backend"""
def __init__(self, **kwargs):
"""
Connect to a MongoDB.
:Parameters:
- `host`: hostname
- `port`: port
- `user`: collection username
- `password`: collection user password
- `database`: name of the database
- `collection`: name of the collection
- `extra`: parameters to pymongo.MongoClient not listed above
"""
super(MongoBackend, self).__init__(**kwargs)
# Extract connection parameters from kwargs
host = kwargs.get('host', 'localhost')
port = kwargs.get('port', 27017)
user = kwargs.get('user', '')
password = kwargs.get('password', '')
db_name = kwargs.get('database', 'track')
collection_name = kwargs.get('collection', 'events')
# Other mongo connection arguments
extra = kwargs.get('extra', {})
# By default disable write acknowledgments, reducing the time
# blocking during an insert
extra['w'] = extra.get('w', 0)
# Make timezone aware by default
extra['tz_aware'] = extra.get('tz_aware', True)
# Connect to database and get collection
self.connection = MongoClient(
host=host,
port=port,
**extra
)
self.collection = self.connection[db_name][collection_name]
if user or password:
self.collection.database.authenticate(user, password)
self._create_indexes()
def _create_indexes(self):
# WARNING: The collection will be locked during the index
# creation. If the collection has a large number of
# documents in it, the operation can take a long time.
# TODO: The creation of indexes can be moved to a Django
# management command or equivalent. There is also an option to
# run the indexing on the background, without locking.
self.collection.ensure_index([('time', pymongo.DESCENDING)])
self.collection.ensure_index('event_type')
def send(self, event):
try:
self.collection.insert(event, manipulate=False)
except PyMongoError:
msg = 'Error inserting to MongoDB event tracker backend'
log.exception(msg)
from __future__ import absolute_import
from uuid import uuid4
from mock import patch
from django.test import TestCase
from track.backends.mongodb import MongoBackend
class TestMongoBackend(TestCase):
def setUp(self):
self.mongo_patcher = patch('track.backends.mongodb.MongoClient')
self.addCleanup(self.mongo_patcher.stop)
self.mongo_patcher.start()
self.backend = MongoBackend()
def test_mongo_backend(self):
events = [{'test': 1}, {'test': 2}]
self.backend.send(events[0])
self.backend.send(events[1])
# Check if we inserted events into the database
calls = self.backend.collection.insert.mock_calls
self.assertEqual(len(calls), 2)
# Unpack the arguments and check if the events were used
# as the first argument to collection.insert
def first_argument(call):
_, args, _ = call
return args[0]
self.assertEqual(events[0], first_argument(calls[0]))
self.assertEqual(events[1], first_argument(calls[1]))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment