https://github.com/edx/edx-platform/pull/20645 This introduces: * A new XBlock runtime that can read and write XBlocks that are persisted using Blockstore instead of Modulestore. The new runtime is currently isolated so that it can be tested without risk to the current courseware/runtime. * Content Libraries v2, which store XBlocks in Blockstore not modulestore * An API Client for Blockstore * "Learning Context" plugin API. A learning context is a more abstract concept than a course; it's a collection of XBlocks that serves some learning purpose.
86 lines
2.6 KiB
Python
86 lines
2.6 KiB
Python
"""
|
|
error_tracker: A hook for tracking errors in loading XBlocks.
|
|
|
|
Used for example to get a list of all non-fatal problems on course
|
|
load, and display them to the user.
|
|
|
|
Patterns for using the error handler:
|
|
try:
|
|
x = access_some_resource()
|
|
check_some_format(x)
|
|
except SomeProblem as err:
|
|
msg = 'Grommet {0} is broken: {1}'.format(x, str(err))
|
|
log.warning(msg) # don't rely on tracker to log
|
|
# NOTE: we generally don't want content errors logged as errors
|
|
error_tracker = self.runtime.service(self, 'error_tracker')
|
|
if error_tracker:
|
|
error_tracker(msg)
|
|
# work around
|
|
return 'Oops, couldn't load grommet'
|
|
|
|
OR, if not in an exception context:
|
|
|
|
if not check_something(thingy):
|
|
msg = "thingy {0} is broken".format(thingy)
|
|
log.critical(msg)
|
|
error_tracker = self.runtime.service(self, 'error_tracker')
|
|
if error_tracker:
|
|
error_tracker(msg)
|
|
|
|
NOTE: To avoid duplication, do not call the tracker on errors
|
|
that you're about to re-raise---let the caller track them.
|
|
"""
|
|
from __future__ import absolute_import
|
|
|
|
import logging
|
|
import sys
|
|
import traceback
|
|
from collections import namedtuple
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
ErrorLog = namedtuple('ErrorLog', 'tracker errors')
|
|
|
|
|
|
def exc_info_to_str(exc_info):
|
|
"""Given some exception info, convert it into a string using
|
|
the traceback.format_exception() function.
|
|
"""
|
|
return ''.join(traceback.format_exception(*exc_info))
|
|
|
|
|
|
def in_exception_handler():
|
|
'''Is there an active exception?'''
|
|
return sys.exc_info() != (None, None, None)
|
|
|
|
|
|
def make_error_tracker():
|
|
'''Return an ErrorLog (named tuple), with fields (tracker, errors), where
|
|
the logger appends a tuple (message, exception_str) to the errors on every
|
|
call. exception_str is in the format returned by traceback.format_exception.
|
|
|
|
error_list is a simple list. If the caller modifies it, info
|
|
will be lost.
|
|
'''
|
|
errors = []
|
|
|
|
def error_tracker(msg):
|
|
'''Log errors'''
|
|
exc_str = ''
|
|
if in_exception_handler():
|
|
exc_str = exc_info_to_str(sys.exc_info())
|
|
|
|
# don't display irrelevant gunicorn sync error
|
|
if (('python2.7/site-packages/gunicorn/workers/sync.py' in exc_str) and
|
|
('[Errno 11] Resource temporarily unavailable' in exc_str)):
|
|
exc_str = ''
|
|
|
|
errors.append((msg, exc_str))
|
|
|
|
return ErrorLog(error_tracker, errors)
|
|
|
|
|
|
def null_error_tracker(msg):
|
|
'''A dummy error tracker that just ignores the messages'''
|
|
pass
|