diff --git a/src/debugpy/server/tracing/__init__.py b/src/debugpy/server/tracing/__init__.py index 3195d8a2f..4413d424c 100644 --- a/src/debugpy/server/tracing/__init__.py +++ b/src/debugpy/server/tracing/__init__.py @@ -38,6 +38,12 @@ class Thread: DAP "thread" event with "reason":"started". """ + is_traced: bool + """ + Whether this thread is traced. Threads are normally traced, but API clients + can exclude a specific thread from tracing. + """ + _last_id = 0 _all: ClassVar[Dict[int, "Thread"]] = {} @@ -48,6 +54,7 @@ def __init__(self, python_thread): """ self.python_thread = python_thread self.is_known_to_adapter = False + self.is_traced = True with _cvar: # Thread IDs are serialized as JSON numbers in DAP, which are handled as 64-bit @@ -71,14 +78,6 @@ def __getstate__(self): "name": self.name, } - @property - def is_debugpy_thread(self): - return getattr(self.python_thread, "is_debugpy_thread", False) - - @property - def is_traced(self): - return not self.is_debugpy_thread - @property def name(self): return self.python_thread.name @@ -88,10 +87,13 @@ def from_python_thread(self, python_thread: threading.Thread = None) -> "Thread" """ Returns the DAP Thread object corresponding to the given Python thread, or for the current Python thread if None, creating it and reporting it to adapter if - necessary. + necessary. If the current thread is internal debugpy thread, returns None. """ + if python_thread is None: python_thread = threading.current_thread() + if getattr(python_thread, "is_debugpy_thread", False): + return None with _cvar: for thread in self._all.values(): if thread.python_thread is python_thread: @@ -118,7 +120,7 @@ def enumerate(self) -> List["Thread"]: thread for python_thread in threading.enumerate() for thread in [Thread.from_python_thread(python_thread)] - if thread.is_traced + if thread is not None and thread.is_traced ] def make_known_to_adapter(self): diff --git a/src/debugpy/server/tracing/tracer.py b/src/debugpy/server/tracing/tracer.py index 71f2ca509..fc3853071 100644 --- a/src/debugpy/server/tracing/tracer.py +++ b/src/debugpy/server/tracing/tracer.py @@ -238,7 +238,7 @@ def _stop( def _trace_line(self, code: CodeType, line_number: int): thread = self.Thread.from_python_thread() - if not thread.is_traced: + if thread is None or not thread.is_traced: return self.monitoring.DISABLE self.log.debug(f"sys.monitoring event: LINE({line_number}, {code})") @@ -347,19 +347,19 @@ def _trace_line(self, code: CodeType, line_number: int): def _trace_py_start(self, code: CodeType, ip: int): thread = self.Thread.from_python_thread() - if not thread.is_traced: + if thread is None or not thread.is_traced: return self.monitoring.DISABLE self.log.debug(f"sys.monitoring event: PY_START({code}, {ip})") def _trace_py_resume(self, code: CodeType, ip: int): thread = self.Thread.from_python_thread() - if not thread.is_traced: + if thread is None or not thread.is_traced: return self.monitoring.DISABLE self.log.debug(f"sys.monitoring event: PY_RESUME({code}, {ip})") def _trace_py_return(self, code: CodeType, ip: int, retval: object): thread = self.Thread.from_python_thread() - if not thread.is_traced: + if thread is None or not thread.is_traced: return self.monitoring.DISABLE self.log.debug(f"sys.monitoring event: PY_RETURN({code}, {ip})") # TODO: capture returned value to report it when client requests locals. @@ -367,7 +367,7 @@ def _trace_py_return(self, code: CodeType, ip: int, retval: object): def _trace_py_yield(self, code: CodeType, ip: int, retval: object): thread = self.Thread.from_python_thread() - if not thread.is_traced: + if thread is None or not thread.is_traced: return self.monitoring.DISABLE self.log.debug(f"sys.monitoring event: PY_YIELD({code}, {ip})") # TODO: capture yielded value to report it when client requests locals. @@ -375,7 +375,7 @@ def _trace_py_yield(self, code: CodeType, ip: int, retval: object): def _trace_py_throw(self, code: CodeType, ip: int, exc: BaseException): thread = self.Thread.from_python_thread() - if not thread.is_traced: + if thread is None or not thread.is_traced: return self.log.debug( f"sys.monitoring event: PY_THROW({code}, {ip}, {type(exc).__qualname__})" @@ -383,7 +383,7 @@ def _trace_py_throw(self, code: CodeType, ip: int, exc: BaseException): def _trace_py_unwind(self, code: CodeType, ip: int, exc: BaseException): thread = self.Thread.from_python_thread() - if not thread.is_traced: + if thread is None or not thread.is_traced: return self.log.debug( f"sys.monitoring event: PY_UNWIND({code}, {ip}, {type(exc).__qualname__})" @@ -391,7 +391,7 @@ def _trace_py_unwind(self, code: CodeType, ip: int, exc: BaseException): def _trace_raise(self, code: CodeType, ip: int, exc: BaseException): thread = self.Thread.from_python_thread() - if not thread.is_traced: + if thread is None or not thread.is_traced: return self.log.debug( f"sys.monitoring event: RAISE({code}, {ip}, {type(exc).__qualname__})" @@ -399,7 +399,7 @@ def _trace_raise(self, code: CodeType, ip: int, exc: BaseException): def _trace_reraise(self, code: CodeType, ip: int, exc: BaseException): thread = self.Thread.from_python_thread() - if not thread.is_traced: + if thread is None or not thread.is_traced: return self.log.debug( f"sys.monitoring event: RERAISE({code}, {ip}, {type(exc).__qualname__})" @@ -407,7 +407,7 @@ def _trace_reraise(self, code: CodeType, ip: int, exc: BaseException): def _trace_exception_handled(self, code: CodeType, ip: int, exc: BaseException): thread = self.Thread.from_python_thread() - if not thread.is_traced: + if thread is None or not thread.is_traced: return self.log.debug( f"sys.monitoring event: EXCEPTION_HANDLED({code}, {ip}, {type(exc).__qualname__})"