Commit ac13894
feat(tracer): add support for generators (#13377)
# PR Description
**Fix support for wrapping generator functions with `tracer.wrap()` and
ensure they generate traces in Datadog**
Related issue:
[#5403](#5403)
---
## Summary of the problem
Currently, when a generator function is wrapped with `tracer.wrap()`,
two major issues arise:
1. **Accessing the current span fails:**
Inside the wrapped generator, `tracer.current_span()` returns `None`.
As a result, any attempt to set tags or interact with the span raises:
```
AttributeError: 'NoneType' object has no attribute 'set_tag'
```
Example:
```python
@tracer.wrap()
def foobar():
current_span = tracer.current_span()
current_span.set_tag("hello", "world")
yield 1
```
Calling `list(foobar())` → crashes with `AttributeError`.
2. **Traces are reported to Datadog with incorrect duration:**
Even if the generator runs without explicit span interaction, traces
emitted to Datadog do not correctly report the execution time of the
function.
This is because the `tracer.wrap()` decorator does not maintain the span
context during generator iteration (`next()` or `async for`), so the
span gets opened and closed at the same time.
---
## Root cause
- The `wrap()` logic does not correctly handle Python generators (`def
... yield`) or async generators (`async def ... yield`).
- Without this, both local span interactions (`current_span()`) and
backend reporting (sending traces to Datadog) break.
---
## Proposed fix
This PR updates the `tracer.wrap()` decorator to:
- Add proper handling for **sync generators**:
- Ensure `tracer.current_span()` is available.
- Finalize the span after the generator is exhausted or on error.
- Report traces to Datadog as expected.
- Add dedicated support for **async generators**:
- Use an `async for` wrapper.
- Maintain the tracing context.
With this change:
- Spans inside generators work (`current_span()` is valid).
- Traces from generator functions are correctly sent to Datadog.
---
## How to reproduce + verify the fix
Minimal reproducible example:
```python
@tracer.wrap()
def foobar():
current_span = tracer.current_span()
current_span.set_tag("hello", "world")
yield 1
assert list(foobar()) == [1]
```
**Expected result:**
- No errors.
- Span is created and tagged.
- Trace is visible in Datadog with the tag `hello: world`.
**Added test cases:**
- Sync generator with span tags.
- Async generator with span tags.
- Backward compatibility for sync/async functions.
---
## Checklist
- [x] PR author has checked that all the criteria below are met
- The PR description includes an overview of the change
- The PR description articulates the motivation for the change
- The change includes tests OR the PR description describes a testing
strategy
- The PR description notes risks associated with the change, if any
- Newly-added code is easy to change
- The change follows the [library release note
guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html)
- The change includes or references documentation updates if necessary
- Backport labels are set (if
[applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting))
## Reviewer Checklist
- [x] Reviewer has checked that all the criteria below are met
- Title is accurate
- All changes are related to the pull request's stated goal
- Avoids breaking
[API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces)
changes
- Testing strategy adequately addresses listed risks
- Newly-added code is easy to change
- Release note makes sense to a user of the library
- If necessary, author has acknowledged and discussed the performance
implications of this PR as reported in the benchmarks PR comment
- Backport labels are set in a manner that is consistent with the
[release branch maintenance
policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)
---------
Co-authored-by: Brett Langdon <brett.langdon@datadoghq.com>
Co-authored-by: Brett Langdon <me@brett.is>1 parent 4607d9e commit ac13894
File tree
4 files changed
+141
-3
lines changed- ddtrace/_trace
- releasenotes/notes
- tests
- contrib/asyncio
- tracer
4 files changed
+141
-3
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
775 | 776 | | |
776 | 777 | | |
777 | 778 | | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
778 | 829 | | |
779 | 830 | | |
780 | 831 | | |
| |||
812 | 863 | | |
813 | 864 | | |
814 | 865 | | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
815 | 875 | | |
816 | 876 | | |
817 | 877 | | |
| |||
825 | 885 | | |
826 | 886 | | |
827 | 887 | | |
828 | | - | |
829 | | - | |
| 888 | + | |
| 889 | + | |
830 | 890 | | |
831 | | - | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
832 | 908 | | |
833 | 909 | | |
834 | 910 | | |
| |||
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
223 | 224 | | |
224 | 225 | | |
225 | 226 | | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
284 | 285 | | |
285 | 286 | | |
286 | 287 | | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
287 | 316 | | |
288 | 317 | | |
289 | 318 | | |
| |||
0 commit comments