Skip to content

docs(python): Update stream mode in main tracing files (tracing part 1/3)#18531

Open
inventarSarah wants to merge 4 commits into
masterfrom
smi/span-first/python-tracing-1
Open

docs(python): Update stream mode in main tracing files (tracing part 1/3)#18531
inventarSarah wants to merge 4 commits into
masterfrom
smi/span-first/python-tracing-1

Conversation

@inventarSarah

Copy link
Copy Markdown
Collaborator

DESCRIBE YOUR PR

This PR updates pages under Tracing with information about the new stream mode and the new Span APIs.

Part 1 out of 3
(result of splitting up PR #18511 into smaller parts)

Important

Broken links: I added links to the New Spans guide on these pages, but since this guide does not exist in this branch, we get a linting error.
Should only be merged after #18456

IS YOUR CHANGE URGENT?

Help us prioritize incoming PRs by letting us know when the change needs to go live.

  • Urgent deadline (GA date, etc.):
  • Other deadline:
  • None: Not urgent, can wait up to 1 week+

SLA

  • Teamwork makes the dream work, so please add a reviewer to your PRs.
  • Please give the docs team up to 1 week to review your PR unless you've added an urgent due date to it.
    Thanks in advance for your help!

PRE-MERGE CHECKLIST

Make sure you've checked the following before merging your changes:

  • Checked Vercel preview for correctness, including links
  • PR was reviewed and approved by any necessary SMEs (subject matter experts)
  • PR was reviewed and approved by a member of the Sentry docs team

LEGAL BOILERPLATE

Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.

EXTRA RESOURCES

@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sentry-docs Ready Ready Preview, Comment Jun 24, 2026 1:18pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
develop-docs Ignored Ignored Preview Jun 24, 2026 1:18pm

Request Review

@inventarSarah inventarSarah force-pushed the smi/span-first/python-tracing-1 branch from 09d3da9 to 1125f9f Compare June 24, 2026 11:50
@inventarSarah inventarSarah marked this pull request as ready for review June 24, 2026 11:50
Comment thread docs/platforms/python/tracing/span-lifecycle/index.mdx Outdated
Comment thread docs/platforms/python/tracing/span-lifecycle/index.mdx Outdated
Comment thread docs/platforms/python/tracing/instrumentation/custom-instrumentation/index.mdx Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 01ddcd6. Configure here.

Comment thread docs/platforms/python/tracing/span-metrics/index.mdx
Comment thread docs/platforms/python/tracing/instrumentation/custom-instrumentation/index.mdx Outdated
Comment thread docs/platforms/python/tracing/instrumentation/custom-instrumentation/index.mdx Outdated
def before_send_span(span, hint):
# Runs once per span, as it's flushed.
# Only attributes set at span-creation time are available here.
span["attributes"].update({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The before_send_span example accesses span["attributes"] without checking if the key exists, which could cause a KeyError at runtime.
Severity: MEDIUM

Suggested Fix

Update the code example to be more defensive. Before accessing span["attributes"], check if the key exists. If it does not, initialize it as an empty dictionary. For example: if "attributes" not in span: span["attributes"] = {}.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: platform-includes/tracing/span-metrics/add-all-spans/python.mdx#L45

Potential issue: The Python code example for the `before_send_span` callback directly
accesses `span["attributes"]` to update it. However, the span protocol specifies that
the `attributes` field is optional. If a span is processed that does not have an
`attributes` key, this code will raise a `KeyError`, crashing the callback. The example
code does not defensively check for the existence of the `attributes` key before
attempting to access it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexander-alderman-webb @ericapisani
is attributes always present on the span object here or can it be missing? This also affects one example on the New Spans page

Comment on lines 337 to +343
root_function()
```

```python {tabTitle:Stream Mode}
import sentry_sdk

@sentry_sdk.traces.trace(name="Paul", attributes={"sentry.op": "my_op", "x": True})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The Python code examples for custom instrumentation have incorrect leading spaces, which will cause an IndentationError when copied and run.
Severity: MEDIUM

Suggested Fix

Remove the extra leading spaces from the lines within the Python code blocks in the index.mdx file. Ensure that the indentation level is correct for all lines of code in both the 'Transaction Mode' and 'Stream Mode' examples.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location:
docs/platforms/python/tracing/instrumentation/custom-instrumentation/index.mdx#L337-L343

Potential issue: The Python code examples for custom instrumentation using the
`@sentry_sdk.trace` decorator have incorrect indentation. In the 'Transaction Mode'
example, most lines have an extra leading space. In the 'Stream Mode' example, lines
after the `import` statement also have an extra leading space. This will cause a Python
`IndentationError: unexpected indent` for users who copy and paste the code, preventing
them from running the examples successfully.

@sentrivana sentrivana left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving to not block, but please see comments.

with sentry_sdk.traces.start_span(
name="Eat Pizza",
attributes={"sentry.op": "task"},
# remove the parent span to create service span

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# remove the parent span to create service span
# set parent span to None to create service span

<Alert>

Note that `sentry_sdk.start_transaction()` is meant be used as a context manager. This ensures that the transaction will be properly set as active and any spans created within will be attached to it.
Note that `sentry_sdk.start_transaction()` (transaction mode) and `sentry_sdk.traces.start_span()` (stream mode) are meant be used as context managers. This ensures that the transaction/service span will be properly set as active and any spans created within will be attached to it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Note that `sentry_sdk.start_transaction()` (transaction mode) and `sentry_sdk.traces.start_span()` (stream mode) are meant be used as context managers. This ensures that the transaction/service span will be properly set as active and any spans created within will be attached to it.
Note that `sentry_sdk.start_transaction()` (transaction mode) is meant be used as a context manager. This ensures that the transaction/service span will be properly set as active and any spans created within will be attached to it.
In stream mode, `sentry_sdk.traces.start_span()` can, but doesn't have to be, used as a context manager. If you don't use it as a context manager, make sure to call `span.end()` to finish the span.

<Alert level="warning" title="Static & class methods">

When tracing a static or class method, you **must** add the `@sentry_sdk.trace` decorator **after** the `@staticmethod` or `@classmethod` decorator (i.e., **closer** to the function definition). Otherwise, your function will break!
When tracing a static or class method, you **must** add the `@sentry_sdk.trace` decorator **after** the `@staticmethod` or `@classmethod` decorator (i.e., **closer** to the function definition). Otherwise, your function will break! This applies in both transaction mode and stream mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
When tracing a static or class method, you **must** add the `@sentry_sdk.trace` decorator **after** the `@staticmethod` or `@classmethod` decorator (i.e., **closer** to the function definition). Otherwise, your function will break! This applies in both transaction mode and stream mode.
When tracing a static or class method, you **must** add the `@sentry_sdk.trace` (transaction mode)/`@sentry.sdk.traces.trace` (stream mode) decorator **after** the `@staticmethod` or `@classmethod` decorator (i.e., **closer** to the function definition). Otherwise, your function will break! This applies in both transaction mode and stream mode.

while pizza.slices > 0:
span = sentry_sdk.traces.start_span(name="Eat Slice")
eat_slice(pizza.slices.pop())
span.finish()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

finish will work too, but it's deprecated.

Suggested change
span.finish()
span.end()

Comment on lines +275 to +277
child_span.finish()

parent_span.finish()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
child_span.finish()
parent_span.finish()
child_span.end()
parent_span.end()


The parameters of `start_span()` and `start_child()` are the same. See the [API reference](https://getsentry.github.io/sentry-python/api.html#sentry_sdk.api.start_span) for more details.
In transaction mode, the parameters of `start_span()` and `start_child()` are the same. See the [API reference](https://getsentry.github.io/sentry-python/api.html#sentry_sdk.api.start_span) for more details.
In stream mode, however, there's no separate `start_child()` method. Instead, pass the parent span explicitly via `parent_span` when starting the child (as shown in the example above).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In stream mode, however, there's no separate `start_child()` method. Instead, pass the parent span explicitly via `parent_span` when starting the child (as shown in the example above).
In stream mode, however, there's no separate `start_child()` method. Instead, the span will become the child of the currently active span. Alternatively, you can pass the parent span explicitly via `parent_span` when starting the child (as shown in the example above).

| `name` | `string` | The name of the span. |
| `attributes` | `dict` | Structured metadata for the span, including `sentry.op` for the operation. |
| `start_timestamp` | `datetime/float` | The start time of the span. |
| `parent_span` | `Span/None` | The parent to attach to. Pass None to force a service span. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| `parent_span` | `Span/None` | The parent to attach to. Pass None to force a service span. |
| `parent_span` | `StreamedSpan/None` | The parent to attach to. Pass None to force a service span. |


<Alert>Service spans are only available in stream mode.</Alert>

In stream mode, a service span (the equivalent of a transaction) is just a span started with no parent. Pass `parent_span=None` to force this, even if a span is currently active:

@sentrivana sentrivana Jun 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In stream mode, a service span (the equivalent of a transaction) is just a span started with no parent. Pass `parent_span=None` to force this, even if a span is currently active:
In stream mode, a service span (the equivalent of a transaction) is just a span started with no parent in the current application. Pass `parent_span=None` to force this, even if a span is currently active:

Not sure if this is worth adding though. Might make things more confusing. But the service span might have an external parent from another service.

Comment on lines +3 to +4
- Transaction mode: `before_send_transaction` runs after the entire transaction finishes and has access to all data set during the span's lifetime.
- Stream mode: `before_send_span` (set under `_experiments`) can only work with attributes set at span start time. Attributes added later during the span's lifetime are **not available**.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect -- before_send_span, unlike ignore_spans, is called on the span before it's sent, with all attributes on it.

Since there's no distinction between tracing and stream mode, maybe we can remove this list altogether?

Suggested change
- Transaction mode: `before_send_transaction` runs after the entire transaction finishes and has access to all data set during the span's lifetime.
- Stream mode: `before_send_span` (set under `_experiments`) can only work with attributes set at span start time. Attributes added later during the span's lifetime are **not available**.


def before_send_span(span, hint):
# Runs once per span, as it's flushed.
# Only attributes set at span-creation time are available here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Only attributes set at span-creation time are available here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants