Skip to content

docs(python): Draft New Spans and Migration Guide pages#18456

Draft
inventarSarah wants to merge 3 commits into
masterfrom
smi/span-first/python
Draft

docs(python): Draft New Spans and Migration Guide pages#18456
inventarSarah wants to merge 3 commits into
masterfrom
smi/span-first/python

Conversation

@inventarSarah

Copy link
Copy Markdown
Collaborator

DESCRIBE YOUR PR

This PR adds the initial docs for Python span streaming: a New Spans page (intro to stream mode) and a Migration Guide (how to update existing custom instrumentation).

Context
For Python, the new Span API and stream mode ship together, so migrating to stream mode means migrating to the new Span API at the same time abd there's no way to use the new API while staying in transaction mode.
Because of that, putting the migration steps into the New Spans was way too much content and I split that content out into a new Migration guide. This guide is basically a human-readable version of the migration content from the engineering skill file.

Considerations

  • Content here may still change once I go through the existing Tracing, Option, Filtering, etc. pages
  • The Migration Guide is currently nested under New Spans in the nav. But it could also live under the main "Migration Guides" section instead. Let me know if it makes sense to move the guide.
  • I reused content from the JS New Spans page -> I will create includes for these later when the content is fixed :)

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 17, 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 17, 2026 9:29am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
develop-docs Ignored Ignored Preview Jun 17, 2026 9:29am

Request Review

@ericapisani ericapisani left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looking good so far!

I have questions about the use of the term "service span" vs "segment span" as the latter is what we've been using thus far.

Additionally, should we keep the term "service", referring to these spans as "service entry points" could be a point of confusion because I can see this being mixed up with entry points for a request in the context of a web framework, even though these could be placed/started anywhere (which one of the examples in the documentation show).

---

By default, the Sentry Python SDK collects all spans in memory and sends them to Sentry as a single transaction once the root span ends. This is called transaction mode.
Stream mode changes this by sending spans to Sentry in batches as they finish. Service spans, which represent a service's entry point, replace transactions as the main grouping for each service.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Service spans, which represent a service's entry point, replace transactions as the main grouping for each service.

This is my first time seeing the term "service" used for what we've been calling "segments". I'm not sure if this is a term that we plan on using for user-facing comms going forward, but wanted to highlight the discrepency.

I'm also not sure that the main grouping of spans is always a service's entry point. If we refer to transactions in the same way, then leave as-is, but would want to double check with @sentrivana or @alexander-alderman-webb

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I thought I brought this up in some sync (😇), but service span is the canonical, user facing term of these kind of spans.

<Expandable title="Why use stream mode?">

- **No 1,000-span limit.** In transaction mode, transactions are capped at 1,000 spans. Stream mode has no upper limit since spans are sent in batches.
- **Lower memory usage.** Spans are flushed periodically and don't need to be held in memory until the root span ends. This is especially useful for long-running processes like queue consumers or cron jobs.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it could be worth calling out the benefits for AI monitoring since generative AI spans emitted by our SDKs are one of the main beneficiaries of this change

Comment on lines +145 to +155
To start a service span (the equivalent of a transaction), set `parent_span=None`:

</SplitSectionText>
<SplitSectionCode>

```python
import sentry_sdk

with sentry_sdk.traces.start_span(name="task-name", parent_span=None) as span:
do_work()
```

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This example is why I think referring to what are currently called "segment spans" as "service entry points" above will be a bit confusing since this code snippet could be placed anywhere, not just at an "entry point" in a web framework/service.

</SplitSection>
</SplitLayout>

Find more examples in our <PlatformLink to="/tracing/span-metrics/">Sending Span Metrics</PlatformLink> documentation.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder if it's worth mentioning our Sentry Convention/Attribute docs to users here.

These are attributes that we may set within the SDK that users will want to be aware of so they don't accidentally overwrite them when setting their own attributes (unless that's what they want 😄 )

+ service_span = span._segment
```

`_segment` returns the service span of the current trace (the equivalent of what used to be the transaction). It is a private API — prefer restructuring the code to avoid needing the service span where possible.

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 part is confusing. A private API is returning service span data? Or will this data become unavailable. Let's reword this to make it clearer, and remove reference to private APIs if we can, since customers won't be able to use it.

# Getting the service span (formerly the transaction)
- scope = sentry_sdk.get_current_scope()
- transaction = scope.transaction
+ service_span = sentry_sdk.traces.get_current_span()._segment

@alexander-alderman-webb alexander-alderman-webb Jun 18, 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.

There should be no references to underscored things from our SDK (single leading underscore).
These are private, which means we can change them whenver and however we want. If users are relying on _ prefixed stuff, it's a world of pain for them in the future.

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.

That doesn't include _experiments, which is fine to advertise to users.

+ span_id = span.span_id
```

If you genuinely need the full trace context dict, for example to pass it to an external system, use the private `span._get_trace_context()` method instead. Prefer the direct properties where possible.

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.

Same here, please don't advertise _get_trace_context().

For many of the wacky things possible in transaction land there is no alternative.

)
```

Both `ignore_spans` and `before_send_span` only have access to the span name and attributes set at creation time — not attributes added later in the span's lifetime, like an HTTP status code set after the request completes. If your `before_send_transaction` logic depended on that kind of late-set data, it can't be replicated in stream mode. Consider server-side filtering with Sentry inbound data filters or Relay rules instead.

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.

"Consider server-side filtering with Sentry inbound data filters or Relay rules instead." <-- let's link to these, if we have documentation on them.

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.

5 participants