From 71fe7d65147d2fc66e0d1dd824a291c943243b9d 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 | 11 +++++++---- tests/test_fastapi.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/json_logging/util.py b/json_logging/util.py index c69d98a..45301ea 100644 --- a/json_logging/util.py +++ b/json_logging/util.py @@ -187,9 +187,12 @@ 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 key, value in tuple(f_locals.items()): + if ( + key not in {'request', 'req'} + and isinstance(value, class_type) + ): + return value if f.f_back is not None: f = f.f_back else: @@ -207,4 +210,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 3cd3493..5dcbedd 100644 --- a/tests/test_fastapi.py +++ b/tests/test_fastapi.py @@ -3,6 +3,7 @@ import logging import pathlib import re +import sys import fastapi import fastapi.testclient @@ -147,6 +148,37 @@ def test_get_correlation_id(client_and_log_handler): assert response.json()["correlation_id"] == "abc-def" +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 "key" 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