Custom Instrumentation
Learn how to capture performance data on any action in your app.
The Sentry SDK for Python does a very good job of auto instrumenting your application. If you use one of the popular frameworks, we've got you covered because well-known operations like HTTP calls and database queries will be instrumented out of the box. The Sentry SDK will also check your installed Python packages and auto enable the matching SDK integrations. If you want to enable tracing in a piece of code that performs some other operations, add the @sentry_sdk.trace decorator"
Adding transactions will allow you to instrument and capture certain regions of your code.
If you're using one of Sentry's SDK integrations, transactions will be created for you automatically.
The following example creates a transaction for an expensive operation (in this case, eat_pizza
), and then sends the result to Sentry:
import sentry_sdk
def eat_slice(slice):
...
def eat_pizza(pizza):
with sentry_sdk.start_transaction(op="task", name="Eat Pizza"):
while pizza.slices > 0:
eat_slice(pizza.slices.pop())
The API reference documents start_transaction
and all its parameters.
If you want to have more fine-grained performance monitoring, you can add child spans to your transaction, which can be done by either:
- Using a context manager
- Using a decorator (this works on sync and async functions)
- Manually starting and finishing a span
Calling a sentry_sdk.start_span()
will find the current active transaction and attach the span to it.
import sentry_sdk
def eat_slice(slice):
...
def eat_pizza(pizza):
with sentry_sdk.start_transaction(op="task", name="Eat Pizza"):
while pizza.slices > 0:
with sentry_sdk.start_span(name="Eat Slice"):
eat_slice(pizza.slices.pop())
Changed in 2.15.0
The parameter name
in start_span()
used to be called description
. In version 2.15.0 description
was deprecated and from 2.15.0 on, only name
should be used. description
will be removed in 3.0.0
.
import sentry_sdk
@sentry_sdk.trace
def eat_slice(slice):
...
def eat_pizza(pizza):
with sentry_sdk.start_transaction(op="task", name="Eat Pizza"):
while pizza.slices > 0:
eat_slice(pizza.slices.pop())
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!
import sentry_sdk
def eat_slice(slice):
...
def eat_pizza(pizza):
with sentry_sdk.start_transaction(op="task", name="Eat Pizza"):
while pizza.slices > 0:
span = sentry_sdk.start_span(name="Eat Slice")
eat_slice(pizza.slices.pop())
span.finish()
Changed in 2.15.0
The parameter name
in start_span()
used to be called description
. In version 2.15.0 description
was deprecated and from 2.15.0 on, only name
should be used. description
will be removed in 3.0.0
.
When you create your span manually, make sure to call span.finish()
after the block of code you want to wrap in a span to finish the span. If you do not finish the span it will not be sent to Sentry.
Spans can be nested to form a span tree. If you'd like to learn more, read our distributed tracing documentation.
import sentry_sdk
def chew():
...
def eat_slice(slice):
with sentry_sdk.start_span(name="Eat Slice"):
with sentry_sdk.start_span(name="Chew"):
chew()
Changed in 2.15.0
The parameter name
in start_span()
used to be called description
. In version 2.15.0 description
was deprecated and from 2.15.0 on, only name
should be used. description
will be removed in 3.0.0
.
import sentry_sdk
@sentry_sdk.trace
def chew():
...
@sentry_sdk.trace
def eat_slice(slice):
chew()
import sentry_sdk
def chew():
...
def eat_slice(slice):
parent_span = sentry_sdk.start_span(name="Eat Slice")
child_span = parent_span.start_child(name="Chew")
chew()
child_span.finish()
parent_span.finish()
Changed in 2.15.0
The parameter name
in start_span()
used to be called description
. In version 2.15.0 description
was deprecated and from 2.15.0 on, only name
should be used. description
will be removed in 3.0.0
.
The parameters of start_span()
and start_child()
are the same. See the API reference for more details.
When you create your span manually, make sure to call span.finish()
after the block of code you want to wrap in a span to finish the span. If you do not finish the span it will not be sent to Sentry.
To avoid having custom performance instrumentation code scattered all over your code base, pass a parameter functions_to_trace
to your sentry_sdk.init()
call.
import sentry_sdk
functions_to_trace = [
{"qualified_name": "myrootmodule.eat_slice"},
{"qualified_name": "myrootmodule.swallow"},
{"qualified_name": "myrootmodule.chew"},
{"qualified_name": "myrootmodule.someothermodule.another.some_function"},
{"qualified_name": "myrootmodule.SomePizzaClass.some_method"},
]
sentry_sdk.init(
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
functions_to_trace=functions_to_trace,
)
Now, whenever a function specified in functions_to_trace
will be executed, a span will be created and attached as a child to the currently running span.
Important
To enable performance monitoring for the functions specified in functions_to_trace
, the SDK needs to load the function modules. Be aware, there may be code being executed in modules during module loading. To avoid this, use the method described above to trace your functions.
The sentry_sdk.get_current_scope().transaction
property returns the active transaction or None
if no transaction is active. You can use this property to modify data on the transaction.
import sentry_sdk
def eat_pizza(pizza):
transaction = sentry_sdk.get_current_scope().transaction
if transaction is not None:
transaction.set_tag("num_of_slices", len(pizza.slices))
while pizza.slices > 0:
eat_slice(pizza.slices.pop())
To change data in the current span, use sentry_sdk.get_current_span()
. This function will return a span if there's one running, otherwise it will return None
.
In this example, we'll set a tag in the span created by the @sentry_sdk.trace
decorator.
import sentry_sdk
@sentry_sdk.trace
def eat_slice(slice):
span = sentry_sdk.get_current_span()
if span is not None:
span.set_tag("slice_id", slice.id)
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").