Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add decorator for Sentry tracing #1089

Merged
merged 51 commits into from Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
bd86719
Add decorator for Sentry tracing
ynouri Apr 15, 2021
23d23de
Update decorators.py
ynouri Dec 30, 2021
af136a7
Merge branch 'master' into feature/tracing-decorator
antonpirker Mar 28, 2022
146c8ad
Merge branch 'master' into feature/tracing-decorator
antonpirker Mar 3, 2023
c0bc0d8
Linting
antonpirker Mar 3, 2023
fa6c550
Merge branch 'master' into feature/tracing-decorator
antonpirker Mar 3, 2023
9d1fb9a
Fixed syntax errors
antonpirker Mar 3, 2023
c272e17
Merge branch 'feature/tracing-decorator' of https://github.com/ynouri…
antonpirker Mar 3, 2023
b795e19
Fixed syntax error
antonpirker Mar 3, 2023
e839e4c
Try to make it work in Python 2.x
antonpirker Mar 3, 2023
99d5485
Removed transaction generation and made OP set to .
antonpirker Mar 6, 2023
1a6958f
Added function name as descripion to span.
antonpirker Mar 6, 2023
aecfda9
Merge branch 'master' into feature/tracing-decorator
antonpirker Mar 6, 2023
f8138b8
Try to make it run in Python 2
antonpirker Mar 6, 2023
c885e4c
Merge branch 'feature/tracing-decorator' of https://github.com/ynouri…
antonpirker Mar 6, 2023
05a7caa
Trying something else.
antonpirker Mar 6, 2023
33ecfcf
Merge branch 'master' into feature/tracing-decorator
antonpirker Mar 6, 2023
0160be0
Reverted changes to tracing_utils
antonpirker Mar 6, 2023
17eb234
Merge branch 'feature/tracing-decorator' of https://github.com/ynouri…
antonpirker Mar 6, 2023
1589a56
Added warning message in case there is no transaction
antonpirker Mar 6, 2023
639e190
Update sentry_sdk/tracing.py
antonpirker Mar 7, 2023
37a1b9c
Merge branch 'master' into feature/tracing-decorator
antonpirker Mar 7, 2023
0b26cf1
Added tests
antonpirker Mar 8, 2023
6635d62
Updated how to run tests
antonpirker Mar 8, 2023
10fe566
Fixed invocation of tests
antonpirker Mar 8, 2023
b293047
Fixed invocation (again)
antonpirker Mar 8, 2023
b40578a
Fixed tests
antonpirker Mar 8, 2023
333286f
Linting
antonpirker Mar 8, 2023
3e0e769
Fixed typing
antonpirker Mar 8, 2023
1bdf047
.
antonpirker Mar 8, 2023
95e877e
Create span under current span
antonpirker Mar 8, 2023
4c7f8eb
.
antonpirker Mar 8, 2023
6cf968a
More test coverage
antonpirker Mar 8, 2023
0ec4f56
Cleanup
antonpirker Mar 8, 2023
a882f54
Fixed typing
antonpirker Mar 8, 2023
e51a93f
Better naming
antonpirker Mar 8, 2023
4af3170
Added top level api to get current span and transaction
antonpirker Mar 14, 2023
4efec57
Split out function in separate PR
antonpirker Mar 14, 2023
0b3c227
Merge branch 'antonpirker/top-level-get-current-span-transaction' int…
antonpirker Mar 14, 2023
a1e49c8
Always install pytest-asyncio in Python3 to run new async tests in co…
antonpirker Mar 14, 2023
3265709
Updated test config to make it possible to have dependencies only nee…
antonpirker Mar 15, 2023
933535f
Fixed minimum Python versions the tests should run in.
antonpirker Mar 15, 2023
c124a7d
Dont run common tests in py3.4 (like it was before)
antonpirker Mar 15, 2023
d5e10fb
Updated test matrix
antonpirker Mar 15, 2023
2ede736
Trying normal fixture
antonpirker Mar 15, 2023
cefd2bc
Run asyncio tests only in python >3.6
antonpirker Mar 15, 2023
535eb74
Remove check because it is not really useful and breaks when asyncio …
antonpirker Mar 15, 2023
c1b6a6b
Fixed some tests
antonpirker Mar 15, 2023
62e5719
Use get_current_span, because it also returns the transaction if no s…
antonpirker Mar 15, 2023
6b90c09
Merge branch 'master' into feature/tracing-decorator
antonpirker Mar 15, 2023
524fb88
Linting
antonpirker Mar 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions sentry_sdk/__init__.py
Expand Up @@ -7,6 +7,8 @@

from sentry_sdk.consts import VERSION # noqa

from sentry_sdk.tracing import trace # noqa

__all__ = [ # noqa
"Hub",
"Scope",
Expand Down
38 changes: 35 additions & 3 deletions sentry_sdk/tracing.py
Expand Up @@ -6,21 +6,23 @@
import sentry_sdk
from sentry_sdk.consts import INSTRUMENTER
from sentry_sdk.utils import logger, nanosecond_time
from sentry_sdk._compat import PY2
from sentry_sdk._types import TYPE_CHECKING


if TYPE_CHECKING:
import typing

from typing import Optional
from typing import Any
from typing import Dict
from typing import Iterator
from typing import List
from typing import Optional
from typing import Tuple
from typing import Iterator

import sentry_sdk.profiler
from sentry_sdk._types import Event, SamplingContext, MeasurementUnit
from sentry_sdk._types import Event, MeasurementUnit, SamplingContext


BAGGAGE_HEADER_NAME = "baggage"
SENTRY_TRACE_HEADER_NAME = "sentry-trace"
Expand Down Expand Up @@ -803,6 +805,36 @@ def finish(self, hub=None, end_timestamp=None):
pass


def trace(func=None):
# type: (Any) -> Any
"""
Decorator to start a child span under the existing current transaction.
If there is no current transaction, than nothing will be traced.

Usage:
import sentry_sdk

@sentry_sdk.trace
def my_function():
...

@senrty_sdk.trace
antonpirker marked this conversation as resolved.
Show resolved Hide resolved
async def my_async_function():
...
"""
if PY2:
sl0thentr0py marked this conversation as resolved.
Show resolved Hide resolved
from sentry_sdk.tracing_utils_python2 import start_child_span_decorator
else:
from sentry_sdk.tracing_utils_python3 import start_child_span_decorator

# This patterns allows usage of both @sentry_traced and @sentry_traced(...)
# See https://stackoverflow.com/questions/52126071/decorator-with-arguments-avoid-parenthesis-when-no-arguments/52126278
if func:
return start_child_span_decorator(func)
else:
return start_child_span_decorator


# Circular imports

from sentry_sdk.tracing_utils import (
Expand Down
53 changes: 53 additions & 0 deletions sentry_sdk/tracing_utils_python2.py
@@ -0,0 +1,53 @@
from functools import wraps

import sentry_sdk
from sentry_sdk._types import TYPE_CHECKING
from sentry_sdk.consts import OP
from sentry_sdk.utils import logger, qualname_from_function


if TYPE_CHECKING:
from typing import Any, Optional

from sentry_sdk.tracing import Transaction


def start_child_span_decorator(func):
# type: (Any) -> Any
"""
Decorator to add child spans for functions.

This is the Python 2 compatible version of the decorator.
Duplicated code from ``sentry_sdk.tracing_utils_python3.start_child_span_decorator``.

See also ``sentry_sdk.tracing.trace()``.
"""

def _get_transaction():
# type: () -> Optional[Transaction]
transaction = sentry_sdk.Hub.current.scope.transaction
return transaction

@wraps(func)
def func_with_tracing(*args, **kwargs):
# type: (*Any, **Any) -> Any

transaction = _get_transaction()

# If no transaction, do nothing
if transaction is None:
logger.warning(
"No transaction found. Not creating a child span for %s. "
"Please start a Sentry transaction before calling this function.",
qualname_from_function(func),
)
return func(*args, **kwargs)

# If we have a transaction, we decorate the function!
with transaction.start_child(
op=OP.FUNCTION,
description=qualname_from_function(func),
):
return func(*args, **kwargs)

return func_with_tracing
82 changes: 82 additions & 0 deletions sentry_sdk/tracing_utils_python3.py
@@ -0,0 +1,82 @@
import inspect
from functools import wraps

import sentry_sdk
from sentry_sdk._types import TYPE_CHECKING
from sentry_sdk.consts import OP
from sentry_sdk.utils import logger, qualname_from_function


if TYPE_CHECKING:
from typing import Any, Optional

from sentry_sdk.tracing import Transaction


def start_child_span_decorator(func):
# type: (Any) -> Any
"""
Decorator to add child spans for functions.

This is the Python 3 compatible version of the decorator.
For Python 2 there is duplicated code here: ``sentry_sdk.tracing_utils_python2.start_child_span_decorator()``.

See also ``sentry_sdk.tracing.trace()``.
"""

def _get_transaction():
# type: () -> Optional[Transaction]
transaction = sentry_sdk.Hub.current.scope.transaction
return transaction

# Asynchronous case
if inspect.iscoroutinefunction(func):

@wraps(func)
async def func_with_tracing(*args, **kwargs):
# type: (*Any, **Any) -> Any

transaction = _get_transaction()

# If no transaction, do nothing
if transaction is None:
logger.warning(
"No transaction found. Not creating a child span for %s. "
"Please start a Sentry transaction before calling this function.",
qualname_from_function(func),
)
return await func(*args, **kwargs)

# If we have a transaction, we wrap the function.
with transaction.start_child(
op=OP.FUNCTION,
description=qualname_from_function(func),
):
return await func(*args, **kwargs)

# Synchronous case
else:

@wraps(func)
def func_with_tracing(*args, **kwargs):
# type: (*Any, **Any) -> Any

transaction = _get_transaction()

# If no transaction, do nothing
if transaction is None:
logger.warning(
"No transaction found. Not creating a child span for %s. "
"Please start a Sentry transaction before calling this function.",
qualname_from_function(func),
)
return func(*args, **kwargs)

# If we have a transaction, we decorate the function!
with transaction.start_child(
op=OP.FUNCTION,
description=qualname_from_function(func),
):
return func(*args, **kwargs)

return func_with_tracing