Skip to content

Commit aba1f57

Browse files
committed
Use WeakKeyDictionary to safely track instrumented objects
1 parent dfd7713 commit aba1f57

File tree

1 file changed

+25
-39
lines changed

1 file changed

+25
-39
lines changed

instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/instrumentation_state.py

Lines changed: 25 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
Future, or function has already been instrumented by the OpenTelemetry
66
asyncio instrumentation layer.
77
8-
Because some Python objects (like coroutines or functions) may not support
9-
adding custom attributes or may not be weak-referenceable, we use a
10-
weak-reference-based dictionary to track instrumented objects safely and
11-
efficiently without causing memory leaks.
8+
Some Python objects (like coroutines or functions) may not support setting
9+
custom attributes or weak references. To avoid memory leaks and runtime
10+
errors, this module uses a WeakKeyDictionary to safely track instrumented
11+
objects.
1212
13-
If an object cannot be weak-referenced, we skip tracking it to avoid
14-
runtime errors.
13+
If an object cannot be weak-referenced, it is silently skipped.
1514
1615
Usage:
1716
if not _is_instrumented(obj):
@@ -21,54 +20,41 @@
2120

2221
import weakref
2322

24-
# A global dictionary to track whether an object has been instrumented.
25-
# Keys are weak references to avoid preventing garbage collection.
26-
_instrumented_tasks = {}
23+
# A global WeakKeyDictionary to track instrumented objects.
24+
# Entries are automatically removed when the objects are garbage collected.
25+
_instrumented_tasks = weakref.WeakKeyDictionary()
2726

2827

29-
def _get_weak_key(obj):
28+
def _is_instrumented(obj) -> bool:
3029
"""
31-
Attempt to create a weak reference key for the given object.
32-
33-
Some object types (e.g., built-in functions or async_generator_asend)
34-
do not support weak references. In those cases, return None.
30+
Check whether the given object has already been marked as instrumented.
3531
3632
Args:
37-
obj: The object to generate a weak reference for.
33+
obj: A coroutine, function, or Future.
3834
3935
Returns:
40-
A weakref.ref to the object if supported, otherwise None.
36+
True if the object has already been marked as instrumented.
37+
False if it has not, or if it does not support weak references.
4138
"""
4239
try:
43-
return weakref.ref(obj)
40+
return _instrumented_tasks.get(obj, False)
4441
except TypeError:
45-
return None
46-
47-
48-
def _is_instrumented(obj) -> bool:
49-
"""
50-
Check if the object has already been instrumented.
51-
52-
Args:
53-
obj: The coroutine, function, or Future to check.
54-
55-
Returns:
56-
True if the object is already marked as instrumented, False otherwise.
57-
"""
58-
key = _get_weak_key(obj)
59-
return key in _instrumented_tasks if key else False
42+
# The object does not support weak references.
43+
return False
6044

6145

6246
def _mark_instrumented(obj):
6347
"""
64-
Mark the object as instrumented to avoid double-instrumentation.
48+
Mark the given object as instrumented.
6549
66-
Only objects that support weak references are tracked. Unsupported
67-
objects are silently skipped.
50+
This function only tracks objects that support weak references.
51+
Unsupported objects are ignored without raising errors.
6852
6953
Args:
70-
obj: The coroutine, function, or Future to mark.
54+
obj: A coroutine, function, or Future.
7155
"""
72-
key = _get_weak_key(obj)
73-
if key:
74-
_instrumented_tasks[key] = True
56+
try:
57+
_instrumented_tasks[obj] = True
58+
except TypeError:
59+
# The object does not support weak references.
60+
pass

0 commit comments

Comments
 (0)