Support emitting analytical events from xblocks running in the LMS
XBlocks can and should use the "publish" method provided by the runtime to emit analytical events. In theory we could now start replacing calls to track_function with calls to publish, however, that migration is not handled by this change. Fixes: AN-789
This commit is contained in:
@@ -844,8 +844,8 @@ class CapaMixin(CapaFields):
|
||||
score = self.lcp.get_score()
|
||||
self.runtime.publish(
|
||||
self,
|
||||
'grade',
|
||||
{
|
||||
'event_name': 'grade',
|
||||
'value': score['score'],
|
||||
'max_value': score['total'],
|
||||
}
|
||||
|
||||
@@ -533,12 +533,12 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'}
|
||||
if action == 'replaceResultRequest':
|
||||
self.system.publish(
|
||||
self,
|
||||
'grade',
|
||||
{
|
||||
'event_name': 'grade',
|
||||
'value': score * self.max_score(),
|
||||
'max_value': self.max_score(),
|
||||
},
|
||||
custom_user=real_user
|
||||
'user_id': real_user.id,
|
||||
}
|
||||
)
|
||||
|
||||
values = {
|
||||
|
||||
@@ -1059,11 +1059,13 @@ class DescriptorSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable
|
||||
"""
|
||||
raise NotImplementedError("edX Platform doesn't currently implement XBlock resource urls")
|
||||
|
||||
def publish(self, block, event):
|
||||
def publish(self, block, event_type, event):
|
||||
"""
|
||||
See :meth:`xblock.runtime.Runtime:publish` for documentation.
|
||||
"""
|
||||
raise NotImplementedError("edX Platform doesn't currently implement XBlock publish")
|
||||
xmodule_runtime = getattr(block, 'xmodule_runtime', None)
|
||||
if xmodule_runtime is not None:
|
||||
return xmodule_runtime.publish(block, event_type, event)
|
||||
|
||||
def add_block_as_child_node(self, block, node):
|
||||
child = etree.SubElement(node, "unknown")
|
||||
@@ -1228,7 +1230,7 @@ class ModuleSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable=abs
|
||||
def resource_url(self, resource):
|
||||
raise NotImplementedError("edX Platform doesn't currently implement XBlock resource urls")
|
||||
|
||||
def publish(self, block, event):
|
||||
def publish(self, block, event_type, event):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -21,8 +21,13 @@ These are properties and methods available on ``self.runtime`` when a view or ha
|
||||
that the block is being executed in. The same student in two different courses
|
||||
will have two different ids.
|
||||
|
||||
* publish(event): Emit events to the surrounding system. Events are dictionaries with
|
||||
at least the key 'event_type', which identifies the other fields.
|
||||
* publish(event): Emit events to the surrounding system. Events are dictionaries that can contain arbitrary data.
|
||||
XBlocks can publish events by calling ``self.runtime.publish(self, event_type, event)``. The ``event_type`` parameter
|
||||
enables downstream processing of the event since it uniquely identifies the schema. This call will cause the runtime
|
||||
to save the event data in the application event stream. XBlocks should publish events whenever a significant state
|
||||
change occurs. Post-hoc analysis of the event stream can yield insight about how the XBlock is used in the context of
|
||||
the application. Ideally interesting state of the XBlock could be reconstructed at any point in history through
|
||||
careful analysis of the event stream.
|
||||
|
||||
TODO: Link to the authoritive list of event types.
|
||||
|
||||
@@ -51,12 +56,14 @@ should ``publish`` a ``grade`` event whenever the grade changes. The ``grade`` e
|
||||
dictionary of the following form::
|
||||
|
||||
{
|
||||
'event_type': 'grade',
|
||||
'value': <number>,
|
||||
'max_value': <number>,
|
||||
'user_id': <number>,
|
||||
}
|
||||
|
||||
The grade event represents a grade of ``value/max_value`` for the current user.
|
||||
The grade event represents a grade of ``value/max_value`` for the current user. The
|
||||
``user_id`` field is optional, the currently logged in user's ID will be used if it is
|
||||
omitted.
|
||||
|
||||
Restrictions
|
||||
~~~~~~~~~~~~
|
||||
|
||||
@@ -292,15 +292,8 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
position, wrap_xmodule_display, grade_bucket_type,
|
||||
static_asset_path)
|
||||
|
||||
def publish(block, event, custom_user=None):
|
||||
"""A function that allows XModules to publish events. This only supports grade changes right now."""
|
||||
if event.get('event_name') != 'grade':
|
||||
return
|
||||
|
||||
if custom_user:
|
||||
user_id = custom_user.id
|
||||
else:
|
||||
user_id = user.id
|
||||
def handle_grade_event(block, event_type, event):
|
||||
user_id = event.get('user_id', user.id)
|
||||
|
||||
# Construct the key for the module
|
||||
key = KeyValueStore.Key(
|
||||
@@ -333,6 +326,13 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
|
||||
dog_stats_api.increment("lms.courseware.question_answered", tags=tags)
|
||||
|
||||
def publish(block, event_type, event):
|
||||
"""A function that allows XModules to publish events."""
|
||||
if event_type == 'grade':
|
||||
handle_grade_event(block, event_type, event)
|
||||
else:
|
||||
track_function(event_type, event)
|
||||
|
||||
# Build a list of wrapping functions that will be applied in order
|
||||
# to the Fragment content coming out of the xblocks that are about to be rendered.
|
||||
block_wrappers = []
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
-e git+https://github.com/appliedsec/pygeoip.git@95e69341cebf5a6a9fbf7c4f5439d458898bdc3b#egg=pygeoip
|
||||
|
||||
# Our libraries:
|
||||
-e git+https://github.com/edx/XBlock.git@6ec7edd6c44c7d2f1583df077cbf3e0f621ae984#egg=XBlock
|
||||
-e git+https://github.com/edx/XBlock.git@cfe5c37f98febd9a215d23cb206a25711056a142#egg=XBlock
|
||||
-e git+https://github.com/edx/codejail.git@e3d98f9455#egg=codejail
|
||||
-e git+https://github.com/edx/diff-cover.git@v0.2.9#egg=diff_cover
|
||||
-e git+https://github.com/edx/js-test-tool.git@v0.1.5#egg=js_test_tool
|
||||
|
||||
Reference in New Issue
Block a user