feat: ESG logging updates (#29895)

* feat: log exceptions for fall-through exceptions

* chore: remove unused XBlock handler

* refactor: log errors for XBlock handlers

* refactor: log bad ORA locations

* feat: log lock/grade contest errors

* feat: log output data for ESG endpoints

* feat: unpack extra error info from more endpoints
This commit is contained in:
Nathan Sprenkle
2022-02-11 13:56:25 -05:00
committed by GitHub
parent 8c0db8ddff
commit 6ae626a5d5
4 changed files with 80 additions and 49 deletions

View File

@@ -23,6 +23,9 @@ class ExceptionWithContext(Exception):
class XBlockInternalError(ExceptionWithContext):
"""Errors from XBlock handlers"""
def __str__(self):
return str(self.context)
class LockContestedError(ExceptionWithContext):
"""Signal for trying to operate on a lock owned by someone else"""

View File

@@ -17,7 +17,7 @@ from lms.djangoapps.ora_staff_grader.errors import (
XBlockInternalError,
)
from lms.djangoapps.ora_staff_grader.utils import call_xblock_json_handler
from lms.djangoapps.ora_staff_grader.utils import call_xblock_json_handler, is_json
def get_submissions(request, usage_id):
@@ -33,29 +33,6 @@ def get_submissions(request, usage_id):
return json.loads(response.content)
def get_rubric_config(request, usage_id):
"""
Get rubric data from the ORA's 'get_rubric' XBlock.json_handler
"""
handler_name = "get_rubric"
data = {"target_rubric_block_id": usage_id}
response = call_xblock_json_handler(request, usage_id, handler_name, data)
# Unhandled errors might not be JSON, catch before loading
if response.status_code != 200:
raise XBlockInternalError(context={"handler": handler_name})
response_data = json.loads(response.content)
# Handled faillure still returns HTTP 200 but with 'success': False and supplied error message "msg"
if not response_data.get("success", False):
raise XBlockInternalError(
context={"handler": handler_name, "msg": response_data.get("msg", "")}
)
return response_data["rubric"]
def get_submission_info(request, usage_id, submission_uuid):
"""
Get submission content from ORA 'get_submission_info' XBlock.json_handler
@@ -65,6 +42,11 @@ def get_submission_info(request, usage_id, submission_uuid):
response = call_xblock_json_handler(request, usage_id, handler_name, data)
if response.status_code != 200:
details = (
json.loads(response.content).get("error", "")
if is_json(response.content)
else ""
)
raise XBlockInternalError(context={"handler": handler_name})
return json.loads(response.content)
@@ -79,7 +61,12 @@ def get_assessment_info(request, usage_id, submission_uuid):
response = call_xblock_json_handler(request, usage_id, handler_name, data)
if response.status_code != 200:
raise XBlockInternalError(context={"handler": handler_name})
details = (
json.loads(response.content).get("error", "")
if is_json(response.content)
else ""
)
raise XBlockInternalError(context={"handler": handler_name, "details": details})
return json.loads(response.content)

View File

@@ -43,7 +43,16 @@ def require_params(param_names):
return decorator
def call_xblock_json_handler(request, usage_id, handler_name, data):
def is_json(input_string):
"""Quick True/False check to see if a value is JSON"""
try:
json.loads(input_string)
except ValueError:
return False
return True
def call_xblock_json_handler(request, usage_id, handler_name, data, auth=False):
"""
WARN: Tested only for use in ESG. Consult before use outside of ESG.

View File

@@ -6,6 +6,7 @@ Views for Enhanced Staff Grader
# NOTE: we intentionally add extra args using @require_params
# pylint: disable=arguments-differ
import logging
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
from edx_rest_framework_extensions.auth.session.authentication import (
@@ -54,6 +55,8 @@ from openedx.core.djangoapps.content.course_overviews.api import (
)
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
log = logging.getLogger(__name__)
class StaffGraderBaseView(RetrieveAPIView):
"""
@@ -102,18 +105,23 @@ class InitializeView(StaffGraderBaseView):
# Get list of submissions for this ORA
init_data["submissions"] = get_submissions(request, ora_location)
return Response(InitializeSerializer(init_data).data)
response_data = InitializeSerializer(init_data).data
log.info(response_data)
return Response(response_data)
# Catch bad ORA location
except (InvalidKeyError, ItemNotFoundError):
log.error(f"Bad ORA location provided: {ora_location}")
return BadOraLocationResponse()
# Issues with the XBlock handlers
except XBlockInternalError as ex:
log.error(ex)
return InternalErrorResponse(context=ex.context)
# Blanket exception handling
except Exception:
# Blanket exception handling in case something blows up
except Exception as ex:
log.exception(ex)
return UnknownErrorResponse()
@@ -162,22 +170,25 @@ class SubmissionFetchView(StaffGraderBaseView):
)
lock_info = check_submission_lock(request, ora_location, submission_uuid)
serializer = SubmissionFetchSerializer(
response_data = SubmissionFetchSerializer(
{
"submission_info": submission_info,
"assessment_info": assessment_info,
"lock_info": lock_info,
}
)
).data
return Response(serializer.data)
log.info(response_data)
return Response(response_data)
# Issues with the XBlock handlers
except XBlockInternalError as ex:
log.error(ex)
return InternalErrorResponse(context=ex.context)
# Blanket exception handling
except Exception:
# Blanket exception handling in case something blows up
except Exception as ex:
log.exception(ex)
return UnknownErrorResponse()
@@ -217,21 +228,24 @@ class SubmissionStatusFetchView(StaffGraderBaseView):
)
lock_info = check_submission_lock(request, ora_location, submission_uuid)
serializer = SubmissionStatusFetchSerializer(
response_data = SubmissionStatusFetchSerializer(
{
"assessment_info": assessment_info,
"lock_info": lock_info,
}
)
).data
return Response(serializer.data)
log.info(response_data)
return Response(response_data)
# Issues with the XBlock handlers
except XBlockInternalError as ex:
log.error(ex)
return InternalErrorResponse(context=ex.context)
# Blanket exception handling
except Exception:
# Blanket exception handling in case something blows up
except Exception as ex:
log.exception(ex)
return UnknownErrorResponse()
@@ -291,6 +305,7 @@ class UpdateGradeView(StaffGraderBaseView):
"lock_info": lock_info,
}
).data
log.error(f"Grade contested for submission: {submission_uuid}")
return GradeContestedResponse(context=submission_status)
# Transform grade data and submit assessment, rasies on failure
@@ -306,20 +321,24 @@ class UpdateGradeView(StaffGraderBaseView):
request, ora_location, submission_uuid
)
lock_info = check_submission_lock(request, ora_location, submission_uuid)
serializer = SubmissionStatusFetchSerializer(
response_data = SubmissionStatusFetchSerializer(
{
"assessment_info": assessment_info,
"lock_info": lock_info,
}
)
return Response(serializer.data)
).data
log.info(response_data)
return Response(response_data)
# Issues with the XBlock handlers
except XBlockInternalError as ex:
log.error(ex)
return InternalErrorResponse(context=ex.context)
# Blanket exception handling
except Exception:
# Blanket exception handling in case something blows up
except Exception as ex:
log.exception(ex)
return UnknownErrorResponse()
@@ -350,24 +369,31 @@ class SubmissionLockView(StaffGraderBaseView):
# Validate ORA location
UsageKey.from_string(ora_location)
lock_info = claim_submission_lock(request, ora_location, submission_uuid)
return Response(LockStatusSerializer(lock_info).data)
response_data = LockStatusSerializer(lock_info).data
log.info(response_data)
return Response(response_data)
# Catch bad ORA location
except (InvalidKeyError, ItemNotFoundError):
log.error(f"Bad ORA location provided: {ora_location}")
return BadOraLocationResponse()
# Return updated lock info on error
except LockContestedError:
lock_info = check_submission_lock(request, ora_location, submission_uuid)
lock_status = LockStatusSerializer(lock_info).data
log.error(f"Lock contested for submission: {submission_uuid}")
return LockContestedResponse(context=lock_status)
# Issues with the XBlock handlers
except XBlockInternalError as ex:
log.error(ex)
return InternalErrorResponse(context=ex.context)
# Blanket exception handling
except Exception:
except Exception as ex:
log.exception(ex)
return UnknownErrorResponse()
@require_params([PARAM_ORA_LOCATION, PARAM_SUBMISSION_ID])
@@ -377,10 +403,14 @@ class SubmissionLockView(StaffGraderBaseView):
# Validate ORA location
UsageKey.from_string(ora_location)
lock_info = delete_submission_lock(request, ora_location, submission_uuid)
return Response(LockStatusSerializer(lock_info).data)
response_data = LockStatusSerializer(lock_info).data
log.info(response_data)
return Response(response_data)
# Catch bad ORA location
except (InvalidKeyError, ItemNotFoundError):
log.error(f"Bad ORA location provided: {ora_location}")
return BadOraLocationResponse()
# Return updated lock info on error
@@ -391,8 +421,10 @@ class SubmissionLockView(StaffGraderBaseView):
# Issues with the XBlock handlers
except XBlockInternalError as ex:
log.error(ex)
return InternalErrorResponse(context=ex.context)
# Blanket exception handling
except Exception:
# Blanket exception handling in case something blows up
except Exception as ex:
log.exception(ex)
return UnknownErrorResponse()