Commit dba12c09 by David Ormsbee

Merge pull request #11088 from edx/ormsbee/seq_new_relic_tagging

Add New Relic instrumentation to SequenceModule.
parents 4f185abc 02190715
...@@ -3,7 +3,7 @@ xModule implementation of a learning sequence ...@@ -3,7 +3,7 @@ xModule implementation of a learning sequence
""" """
# pylint: disable=abstract-method # pylint: disable=abstract-method
import collections
import json import json
import logging import logging
from pkg_resources import resource_string from pkg_resources import resource_string
...@@ -13,6 +13,7 @@ from lxml import etree ...@@ -13,6 +13,7 @@ from lxml import etree
from xblock.core import XBlock from xblock.core import XBlock
from xblock.fields import Integer, Scope, Boolean, String from xblock.fields import Integer, Scope, Boolean, String
from xblock.fragment import Fragment from xblock.fragment import Fragment
import newrelic.agent
from .exceptions import NotFoundError from .exceptions import NotFoundError
from .fields import Date from .fields import Date
...@@ -191,6 +192,11 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): ...@@ -191,6 +192,11 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
context["username"] = self.runtime.service(self, "user").get_current_user().opt_attrs['edx-platform.username'] context["username"] = self.runtime.service(self, "user").get_current_user().opt_attrs['edx-platform.username']
display_names = [self.get_parent().display_name or '', self.display_name or ''] display_names = [self.get_parent().display_name or '', self.display_name or '']
# We do this up here because proctored exam functionality could bypass
# rendering after this section.
self._capture_basic_metrics()
# Is this sequential part of a timed or proctored exam? # Is this sequential part of a timed or proctored exam?
if self.is_time_limited: if self.is_time_limited:
view_html = self._time_limited_student_view(context) view_html = self._time_limited_student_view(context)
...@@ -201,7 +207,8 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): ...@@ -201,7 +207,8 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
fragment.add_content(view_html) fragment.add_content(view_html)
return fragment return fragment
for child in self.get_display_items(): display_items = self.get_display_items()
for child in display_items:
is_bookmarked = bookmarks_service.is_bookmarked(usage_key=child.scope_ids.usage_id) is_bookmarked = bookmarks_service.is_bookmarked(usage_key=child.scope_ids.usage_id)
context["bookmarked"] = is_bookmarked context["bookmarked"] = is_bookmarked
...@@ -238,8 +245,78 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): ...@@ -238,8 +245,78 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
fragment.add_content(self.system.render_template("seq_module.html", params)) fragment.add_content(self.system.render_template("seq_module.html", params))
self._capture_full_seq_item_metrics(display_items)
self._capture_current_unit_metrics(display_items)
# Get all descendant XBlock types and counts
return fragment return fragment
def _locations_in_subtree(self, node):
"""
The usage keys for all descendants of an XBlock/XModule as a flat list.
Includes the location of the node passed in.
"""
stack = [node]
locations = []
while stack:
curr = stack.pop()
locations.append(curr.location)
if curr.has_children:
stack.extend(curr.get_children())
return locations
def _capture_basic_metrics(self):
"""
Capture basic information about this sequence in New Relic.
"""
newrelic.agent.add_custom_parameter('seq.block_id', unicode(self.location))
newrelic.agent.add_custom_parameter('seq.display_name', self.display_name or '')
newrelic.agent.add_custom_parameter('seq.position', self.position)
newrelic.agent.add_custom_parameter('seq.is_time_limited', self.is_time_limited)
def _capture_full_seq_item_metrics(self, display_items):
"""
Capture information about the number and types of XBlock content in
the sequence as a whole. We send this information to New Relic so that
we can do better performance analysis of courseware.
"""
# Basic count of the number of Units (a.k.a. VerticalBlocks) we have in
# this learning sequence
newrelic.agent.add_custom_parameter('seq.num_units', len(display_items))
# Count of all modules (leaf nodes) in this sequence (e.g. videos,
# problems, etc.) The units (verticals) themselves are not counted.
all_item_keys = self._locations_in_subtree(self)
newrelic.agent.add_custom_parameter('seq.num_items', len(all_item_keys))
# Count of all modules by block_type (e.g. "video": 2, "discussion": 4)
block_counts = collections.Counter(usage_key.block_type for usage_key in all_item_keys)
for block_type, count in block_counts.items():
newrelic.agent.add_custom_parameter('seq.block_counts.{}'.format(block_type), count)
def _capture_current_unit_metrics(self, display_items):
"""
Capture information about the current selected Unit within the Sequence.
"""
# Positions are stored with indexing starting at 1. If we get into a
# weird state where the saved position is out of bounds (e.g. the
# content was changed), avoid going into any details about this unit.
if 1 <= self.position <= len(display_items):
# Basic info about the Unit...
current = display_items[self.position - 1]
newrelic.agent.add_custom_parameter('seq.current.block_id', unicode(current.location))
newrelic.agent.add_custom_parameter('seq.current.display_name', current.display_name or '')
# Examining all items inside the Unit (or split_test, conditional, etc.)
child_locs = self._locations_in_subtree(current)
newrelic.agent.add_custom_parameter('seq.current.num_items', len(child_locs))
curr_block_counts = collections.Counter(usage_key.block_type for usage_key in child_locs)
for block_type, count in curr_block_counts.items():
newrelic.agent.add_custom_parameter('seq.current.block_counts.{}'.format(block_type), count)
def _time_limited_student_view(self, context): def _time_limited_student_view(self, context):
""" """
Delegated rendering of a student view when in a time Delegated rendering of a student view when in a time
......
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