Skip to content

Commit

Permalink
fix: only generate metadata
Browse files Browse the repository at this point in the history
fix: assert for subset ignoring runtime generated only metadata

chore: quality fixes

chore: improve docstring

fix: convert timestamp str to datetime object

test: add test for str datetime

fix: rename tracking log event emitted

fix: rename tracking log event emitted config

fix: rename tracking event

chore: handle comments
  • Loading branch information
Ian2012 committed Nov 30, 2023
1 parent 9e21f24 commit 12f0c81
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 52 deletions.
40 changes: 17 additions & 23 deletions eventtracking/backends/event_bus.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,53 @@
"""Event tracker backend that emits events to the event-bus."""
import json
import logging
from datetime import datetime

from openedx_events.analytics.data import TrackingLogData
from openedx_events.analytics.signals import TRACKING_EVENT_EMITTED
from openedx_events.event_bus import get_producer

from eventtracking.backends.routing import RoutingBackend
from eventtracking.config import SEND_TRACKING_EVENT_EMITTED_SIGNAL
from openedx_events.data import EventsMetadata
from openedx_events.event_bus import get_producer
from attrs import asdict
import logging

logger = logging.getLogger(__name__)

EVENT_BUS_SOURCE = "openedx/eventtracking"

class EventBusRoutingBackend(RoutingBackend):
"""
Event tracker backend that emits an Open edX public signal.
Event tracker backend for the event bus.
"""

def send(self, event):
"""
Emit the TRACKING_EVENT_EMITTED Open edX public signal to allow
other apps to listen for tracking events.
Send the tracking log event to the event bus by emitting the
TRACKING_EVENT_EMITTED signal using custom metadata.
"""
if not SEND_TRACKING_EVENT_EMITTED_SIGNAL.is_enabled():
return

data = json.dumps(event.get("data"))
context = json.dumps(event.get("context"))

tracking_log=TrackingLogData(
timestamp = event.get("timestamp")

if isinstance(timestamp, str):
timestamp = datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%f%z")

tracking_log = TrackingLogData(
name=event.get("name"),
timestamp=event.get("timestamp"),
timestamp=timestamp,
data=data,
context=context,
)

logger.info(f"Sending tracking event emitted signal for event for {tracking_log.name}")
metadata = TRACKING_EVENT_EMITTED.generate_signal_metadata()

logger.info(f"Emitting tracking log {tracking_log.name} to the event bus.")
get_producer().send(
signal=TRACKING_EVENT_EMITTED,
topic="analytics",
event_key_field="tracking_log.name",
event_data={"tracking_log": tracking_log},
event_metadata=generate_signal_metadata()
event_metadata=metadata,
)


def generate_signal_metadata():
"""
Generate the metadata for the signal with a custom source.
"""
metadata = TRACKING_EVENT_EMITTED.generate_signal_metadata()
medata_dict = asdict(metadata)
medata_dict["source"] = EVENT_BUS_SOURCE
metadata = EventsMetadata(**medata_dict)
return metadata
4 changes: 2 additions & 2 deletions eventtracking/backends/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def process_event(self, event):
processed_event = modified_event
except EventEmissionExit:
raise
except Exception: # pylint: disable=broad-except
except Exception:
LOG.exception(
'Failed to execute processor: %s', str(processor)
)
Expand All @@ -142,7 +142,7 @@ def send_to_backends(self, event):
LOG.info('[send_to_backends] Failed to send edx event "%s" to "%s" backend. "%s" backend has'
' not been enabled, [%s]', event["name"], name, name, repr(exc)
)
except Exception: # pylint: disable=broad-except
except Exception:
LOG.exception(
'Unable to send edx event "%s" to backend: %s', event["name"], name
)
65 changes: 41 additions & 24 deletions eventtracking/backends/tests/test_event_bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@
Test the async routing backend.
"""
import json

from datetime import datetime
from unittest import TestCase
from unittest.mock import sentinel, patch, Mock
from eventtracking.backends.event_bus import EventBusRoutingBackend
from unittest.mock import Mock, patch, sentinel

from django.test import override_settings
from openedx_events.analytics.data import TrackingLogData
from openedx_events.analytics.signals import TRACKING_EVENT_EMITTED

from eventtracking.backends.event_bus import EventBusRoutingBackend


class TestAsyncRoutingBackend(TestCase):
"""
Expand All @@ -16,40 +21,52 @@ class TestAsyncRoutingBackend(TestCase):
def setUp(self):
super().setUp()
self.sample_event = {
'name': str(sentinel.name),
'data': {'foo': 'bar'},
'timestamp': '2020-01-01T12:12:12.000000+00:00',
'context': {'baz': 'qux'},
"name": str(sentinel.name),
"data": {"foo": "bar"},
"timestamp": "2020-01-01T12:12:12.000000+00:00",
"context": {"baz": "qux"},
}

@patch('eventtracking.backends.event_bus.EventBusRoutingBackend.send')
@patch("eventtracking.backends.event_bus.EventBusRoutingBackend.send")
def test_successful_send(self, mocked_send_event):
backend = EventBusRoutingBackend()
backend.send(self.sample_event)
mocked_send_event.assert_called_once_with(self.sample_event)

@patch('eventtracking.backends.event_bus.get_producer')
@override_settings(SEND_TRACKING_EVENT_EMITTED_SIGNAL=True)
@patch("eventtracking.backends.event_bus.get_producer")
def test_successful_send_event(self, mock_get_producer):
backend = EventBusRoutingBackend()
backend.send(self.sample_event)
mock_send = Mock()

mock_get_producer.return_value = Mock(send=mock_send)

mock_get_producer.assert_called()
backend = EventBusRoutingBackend()
backend.send(self.sample_event)

mock_get_producer.assert_called()
mock_send.assert_called()
mock_send.assert_called_once_with(
tracking_log=TrackingLogData(
name=self.sample_event['name'],
timestamp=self.sample_event['timestamp'],
data=json.dumps(self.sample_event['data']),
context=json.dumps(self.sample_event['context']),
)


@patch('eventtracking.backends.event_bus.SEND_TRACKING_EVENT_EMITTED_SIGNAL.is_enabled')
@patch('eventtracking.backends.event_bus.get_producer')
self.assertDictContainsSubset(
{
"signal": TRACKING_EVENT_EMITTED,
"topic": "analytics",
"event_key_field": "tracking_log.name",
"event_data": {
"tracking_log": TrackingLogData(
name=self.sample_event["name"],
timestamp=datetime.strptime(
self.sample_event["timestamp"], "%Y-%m-%dT%H:%M:%S.%f%z"
),
data=json.dumps(self.sample_event["data"]),
context=json.dumps(self.sample_event["context"]),
)
},
},
mock_send.call_args.kwargs,
)

@patch(
"eventtracking.backends.event_bus.SEND_TRACKING_EVENT_EMITTED_SIGNAL.is_enabled"
)
@patch("eventtracking.backends.event_bus.get_producer")
def test_event_is_disabled(self, mock_get_producer, mock_is_enabled):
mock_is_enabled.return_value = False
backend = EventBusRoutingBackend()
Expand Down
11 changes: 8 additions & 3 deletions eventtracking/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
This module contains various configuration settings via
waffle switches for the Certificates app.
waffle switches for the event-tracking app.
"""

from edx_toggles.toggles import SettingToggle
Expand All @@ -10,5 +10,10 @@
# .. toggle_default: False
# .. toggle_description: When True, the system will publish `TRACKING_EVENT_EMITTED` signals to the event bus. The
# `TRACKING_EVENT_EMITTED` signal is emit when a tracking log is emitted.
# .. toggle_use_cases: publish
SEND_TRACKING_EVENT_EMITTED_SIGNAL = SettingToggle('SEND_TRACKING_EVENT_EMITTED_SIGNAL', default=True, module_name=__name__)
# .. toggle_use_cases: circuit_breaker
# .. toggle_creation_date: 2023-10-26
SEND_TRACKING_EVENT_EMITTED_SIGNAL = SettingToggle(
'SEND_TRACKING_EVENT_EMITTED_SIGNAL',
default=False,
module_name=__name__
)

0 comments on commit 12f0c81

Please sign in to comment.