فهرست مقاله
فرض کنید یک رویدادِ ساختگیِ حسگر را به دو مقصد میفرستیم: یک خروجی با برچسبِ کانالِ پوشاندهشده و یک خروجی برای بررسیِ مقدارِ اصلی. فیلتر را فقط روی مقصدِ اول گذاشتهایم، اما مقصدِ دوم هم برچسبِ تغییرکرده را میبیند. این رفتار لزوماً نشانهٔ اجرای دوبارهٔ تابع یا خرابیِ مقصد نیست؛ ممکن است دو handler همان شیء رکورد را دریافت کرده باشند. با یک آزمایشِ کوچکِ حافظهای، محدودهٔ این تغییر را روشن میکنیم.
۱. دو مقصد، یک رکورد؛ تغییرِ فیلد به کجا نشت میکند؟

نامهای public و private در کد فقط برچسبِ دو دریافتکنندهاند. هیچ خروجی عمومی، فایل خصوصی، سرور یا مرزِ دسترسیِ واقعی ساخته نمیشود. هر handler در emit سه مقدارِ ابتدایی را در حافظه ثبت میکند: شناسهٔ رویداد، کانال و ولتاژِ صحیح بر حسب میلیولت. عددها تألیفیاند و اندازهگیریِ حسگر یا نتیجهٔ کالیبراسیون نیستند؛ A، B و C هم نامِ واقعی یا اطلاعات محرمانه نیستند.
شاهدِ دستیِ ما رویدادِ دارای شناسهٔ ۱، کانال A و مقدارِ ۱۲۰۰ میلیولت است. اگر فیلترِ public کانالِ همان رکورد را به MASKED تغییر دهد و public زودتر اجرا شود، private نیز MASKED را میخواند. فیلتر روی private نصب نشده، ولی شیءِ موردِ مشاهده تغییر کرده است. تعدادِ محلهای نصبِ فیلتر، تعدادِ نسخههای مستقلِ داده را تعیین نمیکند.
این پرسش را از مسئلهٔ مسیرِ تحویل جدا نگه میداریم. درسِ propagate و آستانهٔ handler نشان میدهد چرا یک رویداد به چند مقصد میرسد. اینجا مسیر ثابت است: یک logger محلی، دو handler و سطحهای مجازِ ثابت. موضوعِ تازه، هویتِ رکورد و اثرِ تغییرِ یک فیلد در همان مسیر است.
تابع observe_filter_records یک تاپلِ حداکثر ششرویدادی میگیرد. هر رویداد تاپلِ سهتایی است؛ شناسه عددِ صحیحِ دقیق از یک تا شش، کانال یکی از سه رشتهٔ ثابت و مقدار از منفیِ دو هزار تا مثبتِ دو هزار است. بولی، زیرکلاس و تبدیلِ ضمنی پذیرفته نیست. شناسهٔ تکراری مجاز است، چون این آزمایش وقوعهای ورودی را نگه میدارد و سامانهٔ حذفِ رویدادِ تکراری نیست.
۲. برگرداندنِ LogRecord تازه، پیش از emit همان handler

در بخشِ کاملِ Filter Objects، علاوه بر تغییرِ درجا، برگرداندنِ LogRecord جایگزین توضیح داده شده است. این قابلیت از پایتون ۳٫۱۲ پشتیبانی میشود. فیلترِ متصل به handler میتواند رکوردِ تازه را پیش از emit همان مقصد برگرداند و اصلِ رکوردِ مشترک را دستنخورده باقی بگذارد.
در حالت replace، فیلتر با copy.copy از رکوردِ ساختهشده در همین تابع کپیِ کمعمق میگیرد، فقط channel را تغییر میدهد و نسخه را برمیگرداند. انتظارِ دستی روشن است: public مقدارِ MASKED میگیرد؛ private و رکوردِ اصلی هنوز A دارند. در حالت inplace، همان تغییر روی اصل انجام میشود و فیلتر True برمیگرداند. این حالت را عمداً بهعنوان شاهدِ اثر جانبی نگه داشتهایم.
منبعِ نسخهدارِ logging در CPython تفاوتِ متغیرها را دقیقتر نشان میدهد. Filterer نتیجهٔ رکوردیِ فیلتر را دنبال میکند و Handler.handle از آن نتیجه برای پردازشِ محلی استفاده میکند. حلقهٔ Logger.callHandlers همچنان رکوردِ خودش را به handler بعدی میدهد. این مطالعهٔ کدِ نسخهٔ مشخص است؛ نسخهٔ عمومیِ همهٔ کتابخانههای گزارشگیری نیست.
جای نصب نیز بخشی از قرارداد است. فیلترِ ما روی public نصب میشود، نه روی logger. جایگزینی در فیلترِ logger پیش از توزیع میانِ handlerها رخ میدهد و پرسشِ دیگری است. صرفِ ساختنِ یک شیء تازه کافی نیست؛ باید دید آن شیء در کدام مرحله جای رکوردِ قبلی را میگیرد.
۳. ترتیبِ تحویل و محدودهٔ کپیِ کمعمق را جدا ببینیم

اگر در حالت inplace، private را زودتر اجرا کنیم، تصویرِ ثبتشدهٔ آن هنوز A است. سپس public اصلِ رکورد را تغییر میدهد و وضعیتِ پایانیِ اصل MASKED میشود. handlerهای این نمونه تاپلِ مقدارها را هنگامِ emit ذخیره میکنند؛ بنابراین مشاهدهٔ قبلی بهطورِ بازگشتی عوض نمیشود. نگهداشتنِ ارجاعِ رکورد تا زمانی بعد، میتوانست پرسشِ متفاوتی بسازد.
جابهجاییِ مقصدها راهِ جداسازیِ داده نیست. تنها زمانِ مشاهده را عوض کردهایم و اصلِ رکورد همچنان تغییر میکند. در replace، مقدارهای دو مقصد، پس از گروهبندی با برچسبِ مقصد، برای هر دو ترتیب برابر میمانند. مشاهدهٔ هویت نیز نشان میدهد public نسخهٔ دیگری گرفته، اما private همان اصل را دریافت کرده است؛ شناسهٔ حافظهٔ وابسته به اجرا را واردِ خروجی نمیکنیم.
کپیِ کمعمق را به جداسازیِ دلخواه تعمیم نمیدهیم. فیلدهای قابلگزارشِ این آزمایش فقط رشته و عددِ صحیحاند و رکورد را خودمان میسازیم. payload تودرتو، شیءِ دارای hook، زیرکلاسِ رکورد و loggerِ ارسالیِ کاربر واردِ رابط نیستند. همچنین پوشاندنِ channel به معنیِ پاکسازیِ پیام، traceback یا همهٔ فیلدهای logging نیست.
انتخابِ فیلد و قالبِ خروجی مسئولیتِ جدا دارد. درسِ JSON محدود برای رویدادِ حسگر این مرز را بررسی میکند. نمونهٔ حاضر نه فراردهیِ عمومیِ متن است، نه سامانهٔ تشخیصِ راز و نه تضمینِ محرمانگیِ مقصدها؛ فقط اثرِ تغییرِ یک فیلدِ تألیفی را قابلِ مشاهده میکند.
۴. کدِ کامل و مرجعِ مستقل برای بررسیِ خروجی

فایل logging_filter_record_isolation.py را در فرایندِ مستقل اجرا کنید. همهٔ ورودیها پیش از ساختِ Logger، Handler یا LogRecord بررسی میشوند؛ حتی رویدادِ نامعتبرِ انتهای دسته، پس از چند رویدادِ معتبر، نباید اثرِ ثبت ایجاد کند. شیءِ Logger مستقیماً برای همین فیکسچر ساخته میشود و در دفترِ نامهای برنامه جستوجو نمیشود.
"""Two local logging destinations: record replacement versus shared mutation.
Supplied primitive synthetic fields only; no secret scanner or logging service.
"""
import copy
from itertools import product
import json
import logging
import platform
import sys
from typing import NamedTuple
from unittest.mock import patch
AUTHOR_MAIN_ENABLED = True
ORDERS = (("public", "private"), ("private", "public"))
MODES = ("replace", "inplace")
CHANNELS = ("A", "B", "C")
EVENT_CAP = 6
class FilterReport(NamedTuple):
public_rows: tuple
private_rows: tuple
original_rows_after: tuple
public_received_original: tuple
private_received_original: tuple
public_filter_calls: int
created_records: int
closed_handlers: tuple
def _admit(events, mode, order):
if type(mode) is not str:
raise TypeError("exact mode string required")
if mode not in MODES:
raise ValueError("mode must be replace or inplace")
if type(order) is not tuple or len(order) != 2:
raise TypeError("exact two-destination tuple required")
if any(type(label) is not str for label in order):
raise TypeError("exact destination strings required")
if order not in ORDERS:
raise ValueError("each fixed destination must appear once")
if type(events) is not tuple:
raise TypeError("exact materialized event tuple required")
if len(events) > EVENT_CAP:
raise ValueError("own event count cap is six")
for event in events:
if type(event) is not tuple or len(event) != 3:
raise TypeError("exact three-field event tuple required")
event_id, channel, voltage_mv = event
if type(event_id) is not int or type(voltage_mv) is not int:
raise TypeError("exact integer ID and millivolts required")
if type(channel) is not str:
raise TypeError("exact channel string required")
if not 1 <= event_id <= 6 or not -2000 <= voltage_mv <= 2000:
raise ValueError("outside authored ID or millivolt bounds")
if channel not in CHANNELS:
raise ValueError("only synthetic A B C channels accepted")
def _event_fields(record):
return (record.event_id, record.channel, record.voltage_mv)
def _make_record(event):
record = logging.LogRecord("lesson.local.fixture", logging.INFO,
"", 0, "sample", (), None)
record.event_id, record.channel, record.voltage_mv = event
return record
class _SnapshotHandler(logging.Handler):
"""emit stores primitive snapshots and refs only; no logging or I/O."""
def __init__(self, label):
super().__init__(logging.NOTSET)
self.label = label
self.rows = []
self.records = []
def emit(self, record):
self.rows.append(_event_fields(record))
self.records.append(record)
def observe_filter_records(events, mode, order):
"""Observe a fixed two-handler dispatch after whole-declaration admission.
Logger.handle receives internally constructed records; this fixture does
not exercise Logger.log level admission, inheritance or global disable.
"""
_admit(events, mode, order)
# Direct local object, never getLogger(name): no registered application
# logger is configured. Ordinary Handler weakref bookkeeping still occurs.
logger = logging.Logger("lesson.local.fixture", logging.INFO)
logger.propagate = False
handlers = []
by_label = {}
originals = []
closed = []
filter_calls = 0
def public_filter(record):
nonlocal filter_calls
filter_calls += 1
if mode == "replace":
replacement = copy.copy(record)
replacement.channel = "MASKED"
return replacement
record.channel = "MASKED"
return True
try:
for label in order:
handler = _SnapshotHandler(label)
handlers.append(handler)
by_label[label] = handler
if label == "public":
handler.addFilter(public_filter)
logger.addHandler(handler)
for event in events:
record = _make_record(event)
originals.append(record)
logger.handle(record)
public, private = by_label["public"], by_label["private"]
result = (tuple(public.rows), tuple(private.rows),
tuple(_event_fields(record) for record in originals),
tuple(seen is original for seen, original in zip(public.records, originals)),
tuple(seen is original for seen, original in zip(private.records, originals)),
filter_calls, len(originals))
finally:
for handler in handlers:
logger.removeHandler(handler)
handler.close()
closed.append(handler.label)
return FilterReport(*result, tuple(closed))
def destination_relation_reference(events, mode, order):
"""Trusted-valid finite values only; no logging/copy/main helper calls.
A destination projection and an order predicate replace callback replay.
Every event occurrence is retained, even when event IDs are repeated.
"""
public_before_private = order == ("public", "private")
public_rows = tuple((identifier, "MASKED", mv) for identifier, channel, mv in events)
private_rows = tuple((identifier,
"MASKED" if mode == "inplace" and public_before_private else channel,
mv) for identifier, channel, mv in events)
after = tuple((identifier, "MASKED" if mode == "inplace" else channel, mv)
for identifier, channel, mv in events)
return {"public_rows": public_rows, "private_rows": private_rows,
"original_rows_after": after,
"public_received_original": (mode == "inplace",) * len(events),
"private_received_original": (True,) * len(events),
"public_filter_calls": len(events), "created_records": len(events),
"closed_handlers": order}
def _raises_exact(kind, call):
try:
call()
except Exception as error:
return type(error) is kind
return False
def _host_configuration():
root = logging.getLogger()
return (root.level, tuple(root.handlers), tuple(root.filters),
logging.getLogRecordFactory(), root.manager.disable,
tuple(sorted(root.manager.loggerDict.items())))
def run_example():
host_before = _host_configuration()
checks = {}
def check(name, value):
assert type(value) is bool and value, name
checks[name] = value
event = ((1, "A", 1200),)
replace = observe_filter_records(event, "replace", ORDERS[0])
unsafe_first = observe_filter_records(event, "inplace", ORDERS[0])
unsafe_last = observe_filter_records(event, "inplace", ORDERS[1])
replacement_last = observe_filter_records(event, "replace", ORDERS[1])
check("literal_replacement_changes_public_only_and_preserves_original",
replace.public_rows == ((1, "MASKED", 1200),)
and replace.private_rows == replace.original_rows_after == event)
check("public_first_inplace_change_reaches_later_private_handler",
unsafe_first.public_rows == unsafe_first.private_rows
== unsafe_first.original_rows_after == ((1, "MASKED", 1200),))
check("private_first_snapshot_is_not_retroactively_changed_by_later_mutation",
unsafe_last.private_rows == event
and unsafe_last.original_rows_after == ((1, "MASKED", 1200),)
and unsafe_last.public_rows == ((1, "MASKED", 1200),))
check("replacement_destination_values_are_invariant_to_handler_order",
(replace.public_rows, replace.private_rows, replace.original_rows_after)
== (replacement_last.public_rows, replacement_last.private_rows,
replacement_last.original_rows_after)
and replace.closed_handlers == ORDERS[0]
and replacement_last.closed_handlers == ORDERS[1])
check("actual_identity_distinguishes_handler_local_copy_from_shared_record",
replace.public_received_original == (False,)
and replace.private_received_original == (True,)
and unsafe_first.public_received_original == unsafe_first.private_received_original == (True,))
repeated = ((2, "B", 7), (2, "C", 7), (2, "B", 7))
duplicate = observe_filter_records(repeated, "replace", ORDERS[0])
check("repeated_IDs_preserve_distinct_event_occurrences_and_order",
duplicate.private_rows == repeated and duplicate.created_records == 3
and duplicate.public_rows == ((2, "MASKED", 7),) * 3)
units = ((1, "A", -2000), (6, "B", 2000), (3, "C", 0))
units_report = observe_filter_records(units, "replace", ORDERS[0])
check("inclusive_negative_zero_positive_millivolts_survive_single_field_change",
tuple(row[2] for row in units_report.public_rows) == (-2000, 2000, 0)
and units_report.private_rows == units)
preserved_input = tuple(tuple(row) for row in units)
inplace_units = observe_filter_records(units, "inplace", ORDERS[0])
check("only_internal_record_channel_changes_not_the_materialized_input",
units == preserved_input and units_report.original_rows_after == units
and tuple((row[0], row[2]) for row in inplace_units.original_rows_after)
== tuple((row[0], row[2]) for row in units))
empty = observe_filter_records((), "replace", ORDERS[0])
check("empty_batch_emits_nothing_and_closes_both_local_handlers",
empty.public_rows == empty.private_rows == empty.original_rows_after == ()
and empty.public_filter_calls == empty.created_records == 0
and empty.closed_handlers == ORDERS[0])
cap_events = tuple((i, CHANNELS[(i - 1) % 3], i - 3) for i in range(1, 7))
cap_report = observe_filter_records(cap_events, "replace", ORDERS[1])
check("inclusive_six_event_endpoint_and_exact_destination_shape",
cap_report.created_records == cap_report.public_filter_calls == 6
and cap_report.private_rows == cap_events
and cap_report.closed_handlers == ORDERS[1])
class IntChild(int):
pass
class StrChild(str):
pass
hook_calls = []
class TupleChild(tuple):
def __len__(self):
hook_calls.append("len")
raise AssertionError("tuple subclass hook called")
def lazy():
hook_calls.append("generator")
yield event[0]
bad = []
for value in (None, False, 1, StrChild("replace")):
bad.append((TypeError, (event, value, ORDERS[0])))
for value in ("", "copy", "REPLACE"):
bad.append((ValueError, (event, value, ORDERS[0])))
for value in ([], ("public",), TupleChild(ORDERS[0]), (StrChild("public"), "private")):
bad.append((TypeError, (event, "replace", value)))
for value in (("public", "public"), ("private", "unknown")):
bad.append((ValueError, (event, "replace", value)))
for value in ([], None, TupleChild(event), lazy()):
bad.append((TypeError, (value, "replace", ORDERS[0])))
for row in ([1, "A", 0], (1, "A"), (1, "A", 0, 1),
(True, "A", 0), (IntChild(1), "A", 0), (1, StrChild("A"), 0),
(1, "A", False), (1, "A", 0.0)):
bad.append((TypeError, (event + (row,), "replace", ORDERS[0])))
for row in ((0, "A", 0), (7, "A", 0), (1, "MASKED", 0),
(1, "A", -2001), (1, "A", 2001)):
bad.append((ValueError, (event + (row,), "replace", ORDERS[0])))
bad.append((ValueError, (event * 7, "replace", ORDERS[0])))
construction_calls = []
def forbidden_construction(*args, **kwargs):
construction_calls.append(True)
raise AssertionError("invalid declaration reached object construction")
with patch.object(logging, "Logger", side_effect=forbidden_construction), \
patch.object(logging, "LogRecord", side_effect=forbidden_construction), \
patch.object(sys.modules[__name__], "_SnapshotHandler", side_effect=forbidden_construction):
assert all(_raises_exact(kind, lambda args=args: observe_filter_records(*args))
for kind, args in bad)
check("whole_late_admission_rejects_before_any_logging_construction_or_hooks",
len(bad) == 31 and construction_calls == hook_calls == [])
class ControlledCopyFailure(Exception):
pass
sentinel = ControlledCopyFailure("controlled fixture callback error")
closed_after_failure = []
real_close = _SnapshotHandler.close
def observed_close(handler):
closed_after_failure.append(handler.label)
return real_close(handler)
observed_error = None
with patch.object(copy, "copy", side_effect=sentinel), \
patch.object(_SnapshotHandler, "close", observed_close):
try:
observe_filter_records(event, "replace", ORDERS[0])
except ControlledCopyFailure as error:
observed_error = error
check("controlled_filter_error_propagates_and_each_local_handler_closes_once",
observed_error is sentinel and closed_after_failure == ["public", "private"])
alphabet = ((1, "A", 0), (2, "B", -1), (1, "C", 2000), (6, "A", -2000))
family_profiles = family_occurrences = 0
for length in range(5):
for events in product(alphabet, repeat=length):
for mode in MODES:
for order in ORDERS:
actual = observe_filter_records(events, mode, order)
assert actual._asdict() == destination_relation_reference(events, mode, order)
family_profiles += 1
family_occurrences += length
check("independent_destination_order_relation_1364_profiles_ONE_family",
family_profiles == 1364 and family_occurrences == 5008)
again = observe_filter_records(event, "replace", ORDERS[0])
def assign_result():
again.public_rows = ()
def assign_inner():
again.private_rows[0][1] = "changed"
check("fresh_nested_immutable_results_and_selected_host_configuration_unchanged",
again == replace and again is not replace and hash(again) == hash(replace)
and _raises_exact(AttributeError, assign_result)
and _raises_exact(TypeError, assign_inner)
and _host_configuration() == host_before)
assert len(checks) == 14 and all(type(value) is bool and value for value in checks.values())
return {"runtime": {"python": platform.python_version(), "implementation": platform.python_implementation()},
"scope": "Two local in-memory handlers and internally constructed primitive-field LogRecords; no service, secret scanner, real calibration or security guarantee",
"units": "Supplied integer millivolts; event IDs and A/B/C are synthetic labels",
"manual": {"event": event, "replace_public_first": replace._asdict(),
"inplace_public_first": unsafe_first._asdict(),
"inplace_private_first": unsafe_last._asdict()},
"independent_expected_path": "Pure destination projection and order relation; no logging, copy, callback, main API or validator calls",
"family_profiles_ONE_group": family_profiles, "family_event_occurrences": family_occurrences,
"strict_invalid_profiles": len(bad), "invalid_logging_constructions": len(construction_calls),
"lazy_or_subclass_hook_calls": len(hook_calls),
"controlled_expected_filter_exception": {"caught_same_instance": observed_error is sentinel,
"closed_handlers": closed_after_failure, "not_an_author_process_failure": True},
"host_scope": "Root level/handlers/filters, global record factory/disable and existing logger registry unchanged. Ordinary Handler weakref bookkeeping is not claimed absent or fully restored.",
"own_limits": {"events": [0, EVENT_CAP], "event_ID": [1, 6], "voltage_mv": [-2000, 2000],
"channels": CHANNELS, "modes": MODES, "orders": ORDERS},
"checks": checks, "groups_total": len(checks),
"limits": "Handler-local replacement on Python3.12+; shallow copy of this internally controlled record only. No nested-payload isolation, arbitrary logger/record/hook, Logger.log severity admission, concurrent process, durable output or complete logging privacy claim."}
if __name__ == "__main__":
if not AUTHOR_MAIN_ENABLED:
raise SystemExit("Await ROOT registration and sole author main authorization")
sys.stdout.reconfigure(encoding="ascii", newline="\n")
print(json.dumps(run_example(), ensure_ascii=True, indent=2, allow_nan=False))
فراخوانیِ اصلی Logger.handle است و رکوردها از پیش در تابع ساخته شدهاند. پس این آزمایش دروازهٔ سطحِ Logger.log، ارثبریِ سطح یا سیاستِ خاموشسازیِ سراسری را نمیسنجد. دو handlerِ محلی در finally برداشته و بسته میشوند. آزمونِ خطای کنترلشدهٔ فیلتر نیز همین مسیرِ پاکسازی را بررسی میکند؛ استثنای موردانتظار با شکستِ اجرای برنامه یکی نیست.
مرجعِ مستقل، logging یا callbackها را دوباره اجرا نمیکند. از روی مقدارهای ورودی، مقصد و رابطهٔ تقدم، خروجیِ موردانتظار را میسازد: public همیشه برچسبِ پوشاندهشده دارد؛ private فقط در inplace و پس از public تغییرِ مشترک را میبیند. شاهدهای دستی جداگانهاند. خانوادهٔ برنامهریزیشده شامل ۱۳۶۴ حالت و ۵۰۰۸ وقوعِ رویداد است و داخلِ یک گروهِ مقایسه قرار میگیرد.
چهارده گروهِ نامدار، همین خانواده، هویتِ واقعیِ رکوردها، ترتیبِ مقصدها، حدود، ورودیِ نامعتبر، خطای کنترلشده و تغییرنکردنِ تنظیماتِ منتخبِ میزبان را در بر میگیرند. خروجیِ کامل، نسخهٔ اجرا و شمارهای واقعی را نگه میدارد. مستندِ خواندهشده ۳٫۱۴٫۹ و منبعِ پیادهسازیِ خواندهشده v3.14.5 است؛ هر دو از پروژهٔ Python هستند و دو اعتبارسنجیِ مستقلِ سازمانی به حساب نمیآیند.
{
"runtime": {
"python": "3.14.5",
"implementation": "CPython"
},
"scope": "Two local in-memory handlers and internally constructed primitive-field LogRecords; no service, secret scanner, real calibration or security guarantee",
"units": "Supplied integer millivolts; event IDs and A/B/C are synthetic labels",
"manual": {
"event": [
[
1,
"A",
1200
]
],
"replace_public_first": {
"public_rows": [
[
1,
"MASKED",
1200
]
],
"private_rows": [
[
1,
"A",
1200
]
],
"original_rows_after": [
[
1,
"A",
1200
]
],
"public_received_original": [
false
],
"private_received_original": [
true
],
"public_filter_calls": 1,
"created_records": 1,
"closed_handlers": [
"public",
"private"
]
},
"inplace_public_first": {
"public_rows": [
[
1,
"MASKED",
1200
]
],
"private_rows": [
[
1,
"MASKED",
1200
]
],
"original_rows_after": [
[
1,
"MASKED",
1200
]
],
"public_received_original": [
true
],
"private_received_original": [
true
],
"public_filter_calls": 1,
"created_records": 1,
"closed_handlers": [
"public",
"private"
]
},
"inplace_private_first": {
"public_rows": [
[
1,
"MASKED",
1200
]
],
"private_rows": [
[
1,
"A",
1200
]
],
"original_rows_after": [
[
1,
"MASKED",
1200
]
],
"public_received_original": [
true
],
"private_received_original": [
true
],
"public_filter_calls": 1,
"created_records": 1,
"closed_handlers": [
"private",
"public"
]
}
},
"independent_expected_path": "Pure destination projection and order relation; no logging, copy, callback, main API or validator calls",
"family_profiles_ONE_group": 1364,
"family_event_occurrences": 5008,
"strict_invalid_profiles": 31,
"invalid_logging_constructions": 0,
"lazy_or_subclass_hook_calls": 0,
"controlled_expected_filter_exception": {
"caught_same_instance": true,
"closed_handlers": [
"public",
"private"
],
"not_an_author_process_failure": true
},
"host_scope": "Root level/handlers/filters, global record factory/disable and existing logger registry unchanged. Ordinary Handler weakref bookkeeping is not claimed absent or fully restored.",
"own_limits": {
"events": [
0,
6
],
"event_ID": [
1,
6
],
"voltage_mv": [
-2000,
2000
],
"channels": [
"A",
"B",
"C"
],
"modes": [
"replace",
"inplace"
],
"orders": [
[
"public",
"private"
],
[
"private",
"public"
]
]
},
"checks": {
"literal_replacement_changes_public_only_and_preserves_original": true,
"public_first_inplace_change_reaches_later_private_handler": true,
"private_first_snapshot_is_not_retroactively_changed_by_later_mutation": true,
"replacement_destination_values_are_invariant_to_handler_order": true,
"actual_identity_distinguishes_handler_local_copy_from_shared_record": true,
"repeated_IDs_preserve_distinct_event_occurrences_and_order": true,
"inclusive_negative_zero_positive_millivolts_survive_single_field_change": true,
"only_internal_record_channel_changes_not_the_materialized_input": true,
"empty_batch_emits_nothing_and_closes_both_local_handlers": true,
"inclusive_six_event_endpoint_and_exact_destination_shape": true,
"whole_late_admission_rejects_before_any_logging_construction_or_hooks": true,
"controlled_filter_error_propagates_and_each_local_handler_closes_once": true,
"independent_destination_order_relation_1364_profiles_ONE_family": true,
"fresh_nested_immutable_results_and_selected_host_configuration_unchanged": true
},
"groups_total": 14,
"limits": "Handler-local replacement on Python3.12+; shallow copy of this internally controlled record only. No nested-payload isolation, arbitrary logger/record/hook, Logger.log severity admission, concurrent process, durable output or complete logging privacy claim."
}
ساختِ Handler بهطورِ عادی در ثبتِ ارجاعهای ضعیفِ داخلیِ logging مشارکت میکند. ادعای حذفِ همهٔ آثارِ داخلی یا بازگرداندنِ بایتبهبایتِ کلِ کتابخانه نداریم. تنظیماتِ root، کارخانهٔ رکورد، سطحِ خاموشسازی و دفترِ loggerهای موجود، فقط خوانده و مقایسه میشوند. مقصدِ حافظهای نیز ماندگاری، چندنخیبودن یا موفقیتِ انتقال به سرویس را ثابت نمیکند.
۵. چهار پرسشِ پاسخدار برای بازبینیِ فیلتر

پرسش اول: چرا فیلترِ یک مقصد، مقدارِ مقصدِ دیگر را هم عوض کرده است؟ پاسخ: دو handler همان اصلِ LogRecord را دریافت کردهاند. تغییرِ درجا پیش از مشاهدهٔ مقصدِ بعدی رخ داده است؛ نصبنبودنِ فیلتر روی آن مقصد، اصلِ مشترک را مستقل نمیکند.
پرسش دوم: آیا جابهجاییِ handlerها مشکل را حل میکند؟ پاسخ: فقط مشاهدهٔ زودتر و دیرتر را عوض میکند. در شاهدِ private-first، تصویرِ قبلی A میماند، اما اصلِ رکورد در پایان تغییر کرده است. برای محدودکردنِ تبدیل به همان مقصد، جایگزینیِ محلی را با انتظارِ روشن بررسی میکنیم.
پرسش سوم: آیا copy.copy برای رکوردِ دارای دادهٔ تودرتو جداسازیِ کامل میدهد؟ پاسخ: خیر؛ کپیِ کمعمق میتواند ارجاعهای داخلی را مشترک نگه دارد. قراردادِ این درس آن نوع داده را نمیپذیرد. افزودنِ payload، صرفاً بزرگکردنِ یک ثابت نیست و به قرارداد و مرجعِ تازه نیاز دارد.
پرسش چهارم: آیا MASKED شدنِ برچسب، امنیتِ گزارش را اثبات میکند؟ پاسخ: خیر؛ دسترسی، نگهداری، انتقال، سایرِ فیلدها و مسیرهای ثبت بررسی نشدهاند. نتیجه فقط میگوید در فیکسچرِ محدودِ ما، تبدیلِ یک فیلد در کدام شیء و کدام مرحله اثر میگذارد.
منابع و مطالعهٔ بیشتر
- Python3.14.9؛ Filter Objects و رکوردِ جایگزینِ handler
- CPythonv3.14.5؛ Filterer و مسیرهای کاملِ Handler و Logger
بررسی منابع: ۳۰ مهر ۱۴۰۵. تحلیلها و پیشنهادهای اجرایی، جمعبندی نویسندهاند.

