Skip to content

Commit 5bc0581

Browse files
authored
feat: Improve codejail darklaunch logging (#36671)
This is intended to make logs more or less a standalone source for analyzing mismatches. - Only log mismatches or exceptions - Merge local and remote log messages into one so they can be correlated more easily - Different log messages for mismatch vs. unexpected exceptions - Include course ID (as limit overrides context) in log message
1 parent 0d20b49 commit 5bc0581

2 files changed

Lines changed: 45 additions & 42 deletions

File tree

xmodule/capa/safe_exec/safe_exec.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ def safe_exec(
272272
local_exc_unexpected = None if isinstance(exception, SafeExecException) else exception
273273

274274
report_darklaunch_results(
275-
slug=slug,
275+
limit_overrides_context=limit_overrides_context, slug=slug,
276276
globals_local=globals_dict, emsg_local=emsg, unexpected_exc_local=local_exc_unexpected,
277277
globals_remote=darklaunch_globals, emsg_remote=remote_emsg, unexpected_exc_remote=remote_exception,
278278
)
@@ -347,14 +347,19 @@ def normalize_error_message(emsg):
347347

348348

349349
def report_darklaunch_results(
350-
*, slug,
350+
*, limit_overrides_context, slug,
351351
globals_local, emsg_local, unexpected_exc_local,
352352
globals_remote, emsg_remote, unexpected_exc_remote,
353353
):
354354
"""Send telemetry for results of darklaunch."""
355355
can_compare_output = True
356356

357-
def report_arm(arm, globals_dict, emsg, unexpected_exception):
357+
def report_arm(arm, emsg, unexpected_exception):
358+
"""
359+
Set custom attributes for each arm of the darklaunch experiment.
360+
361+
`arm` should be 'local' or 'remote'.
362+
"""
358363
nonlocal can_compare_output
359364
if unexpected_exception:
360365
# .. custom_attribute_name: codejail.darklaunch.status.{local,remote}
@@ -373,25 +378,33 @@ def report_arm(arm, globals_dict, emsg, unexpected_exception):
373378
set_custom_attribute(f'codejail.darklaunch.status.{arm}', 'ok' if emsg is None else 'safe_error')
374379
set_custom_attribute(f'codejail.darklaunch.exception.{arm}', None)
375380

376-
# Logs include full globals and emsg
377-
log.info(
378-
f"Codejail darklaunch {arm} results for slug={slug}: globals={globals_dict!r}, "
379-
f"emsg={emsg!r}, exception={unexpected_exception!r}"
380-
)
381-
382-
report_arm('local', globals_local, emsg_local, unexpected_exc_local)
383-
report_arm('remote', globals_remote, emsg_remote, unexpected_exc_remote)
381+
report_arm('local', emsg_local, unexpected_exc_local)
382+
report_arm('remote', emsg_remote, unexpected_exc_remote)
384383

385384
# If the arms can't be compared (unexpected errors), stop early -- the rest
386385
# is about output comparison.
387386
if not can_compare_output:
388387
set_custom_attribute('codejail.darklaunch.globals_match', 'N/A')
389388
set_custom_attribute('codejail.darklaunch.emsg_match', 'N/A')
389+
log.info(
390+
"Codejail darklaunch had unexpected exception for "
391+
f"course={limit_overrides_context!r}, slug={slug!r}:\n"
392+
f"Local exception: {unexpected_exc_local!r}\n"
393+
f"Remote exception: {unexpected_exc_remote!r}"
394+
)
390395
return
391396

392397
globals_match = globals_local == globals_remote
393398
emsg_match = normalize_error_message(emsg_local) == normalize_error_message(emsg_remote)
394399

400+
if not globals_match or not emsg_match:
401+
log.info(
402+
f"Codejail darklaunch had mismatch for course={limit_overrides_context!r}, slug={slug!r}:\n"
403+
f"{emsg_match=}, {globals_match=}\n"
404+
f"Local: globals={globals_local!r}, emsg={emsg_local!r}\n"
405+
f"Remote: globals={globals_remote!r}, emsg={emsg_remote!r}"
406+
)
407+
395408
# .. custom_attribute_name: codejail.darklaunch.globals_match
396409
# .. custom_attribute_description: True if local and remote globals_dict
397410
# values match, False otherwise. 'N/A' when either arm raised an

xmodule/capa/safe_exec/tests/test_safe_exec.py

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,10 @@ def run_dark_launch(
195195
mock_remote_exec.side_effect = remote
196196

197197
try:
198-
safe_exec("<IGNORED BY MOCKS>", globals_dict)
198+
safe_exec(
199+
"<IGNORED BY MOCKS>", globals_dict,
200+
limit_overrides_context="course-v1:org+course+run", slug="hw1",
201+
)
199202
except BaseException as e:
200203
safe_exec_e = e
201204
else:
@@ -215,8 +218,8 @@ def run_dark_launch(
215218

216219
# These don't change between the tests
217220
standard_codejail_attr_calls = [
218-
call('codejail.slug', None),
219-
call('codejail.limit_overrides_context', None),
221+
call('codejail.slug', 'hw1'),
222+
call('codejail.limit_overrides_context', 'course-v1:org+course+run'),
220223
call('codejail.extra_files_count', 0),
221224
]
222225

@@ -256,12 +259,11 @@ def remote_exec(data):
256259
],
257260
expect_log_info_calls=[
258261
call(
259-
"Codejail darklaunch local results for slug=None: globals={'overwrite': 'mock local'}, "
260-
"emsg=None, exception=None"
261-
),
262-
call(
263-
"Codejail darklaunch remote results for slug=None: globals={'overwrite': 'mock remote'}, "
264-
"emsg=None, exception=None"
262+
"Codejail darklaunch had mismatch for "
263+
"course='course-v1:org+course+run', slug='hw1':\n"
264+
"emsg_match=True, globals_match=False\n"
265+
"Local: globals={'overwrite': 'mock local'}, emsg=None\n"
266+
"Remote: globals={'overwrite': 'mock remote'}, emsg=None"
265267
),
266268
],
267269
# Should only see behavior of local exec
@@ -296,12 +298,10 @@ def remote_exec(data):
296298
],
297299
expect_log_info_calls=[
298300
call(
299-
"Codejail darklaunch local results for slug=None: globals={}, "
300-
"emsg='unexpected', exception=BaseException('unexpected')"
301-
),
302-
call(
303-
"Codejail darklaunch remote results for slug=None: globals={}, "
304-
"emsg=None, exception=None"
301+
"Codejail darklaunch had unexpected exception "
302+
"for course='course-v1:org+course+run', slug='hw1':\n"
303+
"Local exception: BaseException('unexpected')\n"
304+
"Remote exception: None"
305305
),
306306
],
307307
expect_globals_contains={},
@@ -332,12 +332,11 @@ def remote_exec(data):
332332
],
333333
expect_log_info_calls=[
334334
call(
335-
"Codejail darklaunch local results for slug=None: globals={}, "
336-
"emsg='oops', exception=None"
337-
),
338-
call(
339-
"Codejail darklaunch remote results for slug=None: globals={}, "
340-
"emsg='OH NO', exception=None"
335+
"Codejail darklaunch had mismatch for "
336+
"course='course-v1:org+course+run', slug='hw1':\n"
337+
"emsg_match=False, globals_match=True\n"
338+
"Local: globals={}, emsg='oops'\n"
339+
"Remote: globals={}, emsg='OH NO'"
341340
),
342341
],
343342
expect_globals_contains={},
@@ -365,16 +364,7 @@ def remote_exec(data):
365364
call('codejail.darklaunch.globals_match', True),
366365
call('codejail.darklaunch.emsg_match', True), # even though not exact match
367366
],
368-
expect_log_info_calls=[
369-
call(
370-
"Codejail darklaunch local results for slug=None: globals={}, "
371-
"emsg='stack trace involving /tmp/codejail-1234567/whatever.py', exception=None"
372-
),
373-
call(
374-
"Codejail darklaunch remote results for slug=None: globals={}, "
375-
"emsg='stack trace involving /tmp/codejail-abcd_EFG/whatever.py', exception=None"
376-
),
377-
],
367+
expect_log_info_calls=[],
378368
expect_globals_contains={},
379369
)
380370
assert isinstance(results['raised'], SafeExecException)

0 commit comments

Comments
 (0)