|
5 | 5 | Future, or function has already been instrumented by the OpenTelemetry |
6 | 6 | asyncio instrumentation layer. |
7 | 7 |
|
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. |
12 | 12 |
|
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. |
15 | 14 |
|
16 | 15 | Usage: |
17 | 16 | if not _is_instrumented(obj): |
|
21 | 20 |
|
22 | 21 | import weakref |
23 | 22 |
|
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() |
27 | 26 |
|
28 | 27 |
|
29 | | -def _get_weak_key(obj): |
| 28 | +def _is_instrumented(obj) -> bool: |
30 | 29 | """ |
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. |
35 | 31 |
|
36 | 32 | Args: |
37 | | - obj: The object to generate a weak reference for. |
| 33 | + obj: A coroutine, function, or Future. |
38 | 34 |
|
39 | 35 | 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. |
41 | 38 | """ |
42 | 39 | try: |
43 | | - return weakref.ref(obj) |
| 40 | + return _instrumented_tasks.get(obj, False) |
44 | 41 | 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 |
60 | 44 |
|
61 | 45 |
|
62 | 46 | def _mark_instrumented(obj): |
63 | 47 | """ |
64 | | - Mark the object as instrumented to avoid double-instrumentation. |
| 48 | + Mark the given object as instrumented. |
65 | 49 |
|
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. |
68 | 52 |
|
69 | 53 | Args: |
70 | | - obj: The coroutine, function, or Future to mark. |
| 54 | + obj: A coroutine, function, or Future. |
71 | 55 | """ |
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