Merge pull request #9875 from edx/bderusha/segment-cleanup
Segment Clean Up
This commit is contained in:
@@ -1052,7 +1052,7 @@ class CourseEnrollment(models.Model):
|
||||
with tracker.get_tracker().context(event_name, context):
|
||||
tracker.emit(event_name, data)
|
||||
|
||||
if settings.FEATURES.get('SEGMENT_IO_LMS') and settings.SEGMENT_IO_LMS_KEY:
|
||||
if settings.SEGMENT_KEY:
|
||||
tracking_context = tracker.get_tracker().resolve_context()
|
||||
analytics.track(self.user_id, event_name, {
|
||||
'category': 'conversion',
|
||||
|
||||
@@ -1163,11 +1163,11 @@ def login_user(request, error=""): # pylint: disable=too-many-statements,unused
|
||||
LoginFailures.clear_lockout_counter(user)
|
||||
|
||||
# Track the user's sign in
|
||||
if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'):
|
||||
if settings.SEGMENT_KEY:
|
||||
tracking_context = tracker.get_tracker().resolve_context()
|
||||
analytics.identify(user.id, {
|
||||
'email': email,
|
||||
'username': username,
|
||||
'username': username
|
||||
})
|
||||
|
||||
analytics.track(
|
||||
@@ -1601,7 +1601,7 @@ def create_account_with_params(request, params):
|
||||
third_party_provider = provider.Registry.get_from_pipeline(running_pipeline)
|
||||
|
||||
# Track the user's registration
|
||||
if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'):
|
||||
if settings.SEGMENT_KEY:
|
||||
tracking_context = tracker.get_tracker().resolve_context()
|
||||
identity_args = [
|
||||
user.id, # pylint: disable=no-member
|
||||
|
||||
@@ -585,7 +585,7 @@ def set_logged_in_cookies(backend=None, user=None, strategy=None, auth_entry=Non
|
||||
|
||||
@partial.partial
|
||||
def login_analytics(strategy, auth_entry, *args, **kwargs):
|
||||
""" Sends login info to Segment.io """
|
||||
""" Sends login info to Segment """
|
||||
|
||||
event_name = None
|
||||
if auth_entry == AUTH_ENTRY_LOGIN:
|
||||
@@ -593,7 +593,7 @@ def login_analytics(strategy, auth_entry, *args, **kwargs):
|
||||
elif auth_entry in [AUTH_ENTRY_ACCOUNT_SETTINGS]:
|
||||
event_name = 'edx.bi.user.account.linked'
|
||||
|
||||
if event_name is not None and hasattr(settings, 'SEGMENT_IO_LMS_KEY') and settings.SEGMENT_IO_LMS_KEY:
|
||||
if event_name is not None and settings.SEGMENT_KEY:
|
||||
tracking_context = tracker.get_tracker().resolve_context()
|
||||
analytics.track(
|
||||
kwargs['user'].id,
|
||||
|
||||
@@ -67,7 +67,7 @@ def remove_shim_context(event):
|
||||
context = event['context']
|
||||
# These fields are present elsewhere in the event at this point
|
||||
context_fields_to_remove = set(CONTEXT_FIELDS_TO_INCLUDE)
|
||||
# This field is only used for Segment.io web analytics and does not concern researchers
|
||||
# This field is only used for Segment web analytics and does not concern researchers
|
||||
context_fields_to_remove.add('client_id')
|
||||
for field in context_fields_to_remove:
|
||||
if field in context:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Handle events that were forwarded from the segment.io webhook integration"""
|
||||
"""Handle events that were forwarded from the Segment webhook integration"""
|
||||
|
||||
import datetime
|
||||
import json
|
||||
@@ -35,28 +35,28 @@ ERROR_MISSING_RECEIVED_AT = 'Required receivedAt field not found'
|
||||
@csrf_exempt
|
||||
def segmentio_event(request):
|
||||
"""
|
||||
An endpoint for logging events using segment.io's webhook integration.
|
||||
An endpoint for logging events using Segment's webhook integration.
|
||||
|
||||
segment.io provides a custom integration mechanism that initiates a request to a configurable URL every time an
|
||||
Segment provides a custom integration mechanism that initiates a request to a configurable URL every time an
|
||||
event is received by their system. This endpoint is designed to receive those requests and convert the events into
|
||||
standard tracking log entries.
|
||||
|
||||
For now we limit the scope of handled events to track and screen events from mobile devices. In the future we could
|
||||
enable logging of other types of events, however, there is significant overlap with our non-segment.io based event
|
||||
tracking. Given that segment.io is closed third party solution we are limiting its required usage to just
|
||||
enable logging of other types of events, however, there is significant overlap with our non-Segment based event
|
||||
tracking. Given that Segment is closed third party solution we are limiting its required usage to just
|
||||
collecting events from mobile devices for the time being.
|
||||
|
||||
Many of the root fields of a standard edX tracking event are read out of the "properties" dictionary provided by the
|
||||
segment.io event, which is, in turn, provided by the client that emitted the event.
|
||||
Segment event, which is, in turn, provided by the client that emitted the event.
|
||||
|
||||
In order for an event to be accepted and logged the "key" query string parameter must exactly match the django
|
||||
setting TRACKING_SEGMENTIO_WEBHOOK_SECRET. While the endpoint is public, we want to limit access to it to the
|
||||
segment.io servers only.
|
||||
Segment servers only.
|
||||
|
||||
"""
|
||||
|
||||
# Validate the security token. We must use a query string parameter for this since we cannot customize the POST body
|
||||
# in the segment.io webhook configuration, we can only change the URL that they call, so we force this token to be
|
||||
# in the Segment webhook configuration, we can only change the URL that they call, so we force this token to be
|
||||
# included in the URL and reject any requests that do not include it. This also assumes HTTPS is used to make the
|
||||
# connection between their server and ours.
|
||||
expected_secret = getattr(settings, 'TRACKING_SEGMENTIO_WEBHOOK_SECRET', None)
|
||||
@@ -68,7 +68,7 @@ def segmentio_event(request):
|
||||
track_segmentio_event(request)
|
||||
except EventValidationError as err:
|
||||
log.warning(
|
||||
'Unable to process event received from segment.io: message="%s" event="%s"',
|
||||
'Unable to process event received from Segment: message="%s" event="%s"',
|
||||
str(err),
|
||||
request.body
|
||||
)
|
||||
@@ -85,24 +85,24 @@ class EventValidationError(Exception):
|
||||
|
||||
def track_segmentio_event(request): # pylint: disable=too-many-statements
|
||||
"""
|
||||
Record an event received from segment.io to the tracking logs.
|
||||
Record an event received from Segment to the tracking logs.
|
||||
|
||||
This method assumes that the event has come from a trusted source.
|
||||
|
||||
The received event must meet the following conditions in order to be logged:
|
||||
|
||||
* The value of the "type" field of the event must be included in the list specified by the django setting
|
||||
TRACKING_SEGMENTIO_ALLOWED_TYPES. In order to make use of *all* of the features segment.io offers we would have
|
||||
TRACKING_SEGMENTIO_ALLOWED_TYPES. In order to make use of *all* of the features Segment offers we would have
|
||||
to implement some sort of persistent storage of information contained in some actions (like identify). For now,
|
||||
we defer support of those actions and just support a limited set that can be handled without storing information
|
||||
in external state.
|
||||
* The value of the standard "userId" field of the event must be an integer that can be used to look up the user
|
||||
using the primary key of the User model.
|
||||
* Include a "name" field in the properties dictionary that indicates the edX event name. Note this can differ
|
||||
from the "event" field found in the root of a segment.io event. The "event" field at the root of the structure is
|
||||
from the "event" field found in the root of a Segment event. The "event" field at the root of the structure is
|
||||
intended to be human readable, the "name" field is expected to conform to the standard for naming events
|
||||
found in the edX data documentation.
|
||||
* Have originated from a known and trusted segment.io client library. The django setting
|
||||
* Have originated from a known and trusted Segment client library. The django setting
|
||||
TRACKING_SEGMENTIO_SOURCE_MAP maps the known library names to internal "event_source" strings. In order to be
|
||||
logged the event must have a library name that is a valid key in that map.
|
||||
|
||||
@@ -122,11 +122,11 @@ def track_segmentio_event(request): # pylint: disable=too-many-statements
|
||||
# We mostly care about the properties
|
||||
segment_properties = full_segment_event.get('properties', {})
|
||||
|
||||
# Start with the context provided by segment.io in the "client" field if it exists
|
||||
# Start with the context provided by Segment in the "client" field if it exists
|
||||
# We should tightly control which fields actually get included in the event emitted.
|
||||
segment_context = full_segment_event.get('context')
|
||||
|
||||
# Build up the event context by parsing fields out of the event received from segment.io
|
||||
# Build up the event context by parsing fields out of the event received from Segment
|
||||
context = {}
|
||||
|
||||
library_name = segment_context.get('library', {}).get('name')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Ensure we can parse events sent to us from the segment.io webhook integration"""
|
||||
"""Ensure we can parse events sent to us from the Segment webhook integration"""
|
||||
|
||||
from datetime import datetime
|
||||
import json
|
||||
@@ -50,7 +50,7 @@ def expect_failure_with_message(message):
|
||||
EVENT_TRACKING_PROCESSORS=MOBILE_SHIM_PROCESSOR,
|
||||
)
|
||||
class SegmentIOTrackingTestCase(EventTrackingTestCase):
|
||||
"""Test processing of segment.io events"""
|
||||
"""Test processing of Segment events"""
|
||||
|
||||
def setUp(self):
|
||||
super(SegmentIOTrackingTestCase, self).setUp()
|
||||
@@ -85,7 +85,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
|
||||
self.assert_no_events_emitted()
|
||||
|
||||
def create_request(self, key=None, **kwargs):
|
||||
"""Create a fake request that emulates a request from the segment.io servers to ours"""
|
||||
"""Create a fake request that emulates a request from the Segment servers to ours"""
|
||||
if key is None:
|
||||
key = SECRET
|
||||
|
||||
@@ -106,7 +106,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
|
||||
self.post_segmentio_event(name=name)
|
||||
|
||||
def post_segmentio_event(self, **kwargs):
|
||||
"""Post a fake segment.io event to the view that processes it"""
|
||||
"""Post a fake Segment event to the view that processes it"""
|
||||
request = self.create_request(
|
||||
data=self.create_segmentio_event_json(**kwargs),
|
||||
content_type='application/json'
|
||||
@@ -114,7 +114,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
|
||||
segmentio.track_segmentio_event(request)
|
||||
|
||||
def create_segmentio_event(self, **kwargs):
|
||||
"""Populate a fake segment.io event with data of interest"""
|
||||
"""Populate a fake Segment event with data of interest"""
|
||||
action = kwargs.get('action', 'Track')
|
||||
sample_event = {
|
||||
"userId": kwargs.get('user_id', USER_ID),
|
||||
@@ -158,7 +158,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
|
||||
return sample_event
|
||||
|
||||
def create_segmentio_event_json(self, **kwargs):
|
||||
"""Return a json string containing a fake segment.io event"""
|
||||
"""Return a json string containing a fake Segment event"""
|
||||
return json.dumps(self.create_segmentio_event(**kwargs))
|
||||
|
||||
@expect_failure_with_message(segmentio.WARNING_IGNORED_SOURCE)
|
||||
|
||||
Reference in New Issue
Block a user