|
7 | 7 | from types import ModuleType
|
8 | 8 | from typing import Any
|
9 | 9 | from typing import Dict
|
| 10 | +from typing import List |
10 | 11 | from typing import Mapping
|
11 | 12 | from typing import Optional
|
12 | 13 | from typing import cast
|
13 | 14 |
|
14 | 15 | from ddtrace.debugging._expressions import DDExpressionEvaluationError
|
15 | 16 | from ddtrace.debugging._probe.model import DEFAULT_CAPTURE_LIMITS
|
| 17 | +from ddtrace.debugging._probe.model import CaptureExpression |
16 | 18 | from ddtrace.debugging._probe.model import CaptureLimits
|
17 | 19 | from ddtrace.debugging._probe.model import FunctionLocationMixin
|
18 | 20 | from ddtrace.debugging._probe.model import LineLocationMixin
|
@@ -85,6 +87,26 @@ def timeout(_):
|
85 | 87 | }
|
86 | 88 |
|
87 | 89 |
|
| 90 | +def _capture_expressions( |
| 91 | + exprs: List[CaptureExpression], |
| 92 | + scope: Mapping[str, Any], |
| 93 | + limits: CaptureLimits = DEFAULT_CAPTURE_LIMITS, |
| 94 | +) -> Dict[str, Any]: |
| 95 | + with HourGlass(duration=CAPTURE_TIME_BUDGET) as hg: |
| 96 | + |
| 97 | + def timeout(_): |
| 98 | + return not hg.trickling() |
| 99 | + |
| 100 | + return { |
| 101 | + "captureExpressions": { |
| 102 | + e.name: utils.capture_value( |
| 103 | + e.expr.eval(scope), limits.max_level, limits.max_len, limits.max_size, limits.max_fields, timeout |
| 104 | + ) |
| 105 | + for e in exprs |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + |
88 | 110 | _EMPTY_CAPTURED_CONTEXT: Dict[str, Any] = {"arguments": {}, "locals": {}, "staticFields": {}, "throwable": None}
|
89 | 111 |
|
90 | 112 |
|
@@ -131,7 +153,13 @@ def _do(self, retval, exc_info, scope):
|
131 | 153 |
|
132 | 154 | self._stack = utils.capture_stack(self.frame)
|
133 | 155 |
|
134 |
| - return _capture_context(frame, exc_info, retval=retval, limits=probe.limits) if probe.take_snapshot else None |
| 156 | + if probe.take_snapshot: |
| 157 | + return _capture_context(frame, exc_info, retval=retval, limits=probe.limits) |
| 158 | + |
| 159 | + if probe.capture_expressions: |
| 160 | + return _capture_expressions(probe.capture_expressions, scope, probe.limits) |
| 161 | + |
| 162 | + return None |
135 | 163 |
|
136 | 164 | def enter(self, scope: Mapping[str, Any]) -> None:
|
137 | 165 | self.entry_capture = self._do(_NOTSET, (None, None, None), scope)
|
@@ -166,7 +194,7 @@ def data(self):
|
166 | 194 | probe = self.probe
|
167 | 195 |
|
168 | 196 | captures = {}
|
169 |
| - if isinstance(probe, LogProbeMixin) and probe.take_snapshot: |
| 197 | + if isinstance(probe, LogProbeMixin) and (probe.take_snapshot or probe.capture_expressions): |
170 | 198 | if isinstance(probe, LineLocationMixin):
|
171 | 199 | captures = {"lines": {str(probe.line): self.line_capture or _EMPTY_CAPTURED_CONTEXT}}
|
172 | 200 | elif isinstance(probe, FunctionLocationMixin):
|
|
0 commit comments