From ecf03e82029a623deba69df1086a651e7277a0c0 Mon Sep 17 00:00:00 2001 From: ducky_56789 <163338797+duclucky@users.noreply.github.com> Date: Thu, 13 Aug 2026 06:08:19 +0700 Subject: [PATCH] Fix frame locals mutation during request lookup --- json_logging/util.py | 8 ++++---- tests/test_fastapi.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/json_logging/util.py b/json_logging/util.py index c69d98a..062bde8 100644 --- a/json_logging/util.py +++ b/json_logging/util.py @@ -187,9 +187,9 @@ def get_request_from_call_stack(self, within_formatter=False): if isinstance(f_locals['req'], class_type): return f_locals['req'] - for key in f_locals: - if key not in {'request', 'req'} and isinstance(f_locals[key], class_type): - return f_locals[key] + for value in tuple(f_locals.values()): + if isinstance(value, class_type): + return value if f.f_back is not None: f = f.f_back else: @@ -207,4 +207,4 @@ def _get_correlation_id_in_request_header(request_adapter, request): def is_not_match_any_pattern(path, patterns): - return all(map(lambda pattern: re.search(pattern, path) is None, patterns)) \ No newline at end of file + return all(map(lambda pattern: re.search(pattern, path) is None, patterns)) diff --git a/tests/test_fastapi.py b/tests/test_fastapi.py index 8b69136..40970a0 100644 --- a/tests/test_fastapi.py +++ b/tests/test_fastapi.py @@ -437,6 +437,37 @@ def excluded_silent(): undo_imports_from_package("json_logging") +def test_get_request_from_call_stack_handles_frame_locals_mutation( + client_and_log_handler, +): + """Test stack inspection while a tracer changes the frame locals.""" + import json_logging + from json_logging.util import RequestUtil + + mutation_happened = False + + def tracer(frame, event, arg): + nonlocal mutation_happened + if ( + frame.f_code is RequestUtil.get_request_from_call_stack.__code__ + and event == "line" + and "value" in frame.f_locals + and not mutation_happened + ): + frame.f_locals["added_by_tracer"] = object() + mutation_happened = True + return tracer + + previous_trace = sys.gettrace() + sys.settrace(tracer) + try: + assert json_logging._request_util.get_request_from_call_stack() is None + finally: + sys.settrace(previous_trace) + + assert mutation_happened + + def test_extra_property(client_and_log_handler): """Test adding an extra property to a log message""" api_client, handler = client_and_log_handler