Skip to content

feat(scope): New set_tags function #2978

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

Merged
merged 6 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sentry_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"set_level",
"set_measurement",
"set_tag",
"set_tags",
"set_user",
"start_span",
"start_transaction",
Expand Down
9 changes: 9 additions & 0 deletions sentry_sdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from sentry_sdk.tracing import NoOpSpan, Transaction

if TYPE_CHECKING:
from collections.abc import Mapping

from typing import Any
from typing import Dict
from typing import Generator
Expand Down Expand Up @@ -64,6 +66,7 @@ def overload(x):
"set_level",
"set_measurement",
"set_tag",
"set_tags",
"set_user",
"start_span",
"start_transaction",
Expand Down Expand Up @@ -239,6 +242,12 @@ def set_tag(key, value):
return Scope.get_isolation_scope().set_tag(key, value)


@scopemethod
def set_tags(tags):
# type: (Mapping[str, object]) -> None
Scope.get_isolation_scope().set_tags(tags)


@scopemethod
def set_context(key, value):
# type: (str, Dict[str, Any]) -> None
Expand Down
21 changes: 20 additions & 1 deletion sentry_sdk/scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
)

if TYPE_CHECKING:
from collections.abc import MutableMapping
from collections.abc import Mapping, MutableMapping

from typing import Any
from typing import Callable
Expand Down Expand Up @@ -799,6 +799,25 @@ def set_tag(self, key, value):
"""
self._tags[key] = value

def set_tags(self, tags):
# type: (Mapping[str, object]) -> None
"""Sets multiple tags at once.

This method updates multiple tags at once. The tags are passed as a dictionary
or other mapping type.

Calling this method is equivalent to calling `set_tag` on each key-value pair
in the mapping. If a tag key already exists in the scope, its value will be
updated. If the tag key does not exist in the scope, the key-value pair will
be added to the scope.

This method only modifies tag keys in the `tags` mapping passed to the method.
`scope.set_tags({})` is, therefore, a no-op.

:param tags: A mapping of tag keys to tag values to set.
"""
self._tags.update(tags)

def remove_tag(self, key):
# type: (str) -> None
"""
Expand Down
44 changes: 44 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
from unittest import mock

from sentry_sdk import (
capture_exception,
continue_trace,
get_baggage,
get_client,
get_current_span,
get_traceparent,
is_initialized,
start_transaction,
set_tags,
)

from sentry_sdk.client import Client, NonRecordingClient
Expand Down Expand Up @@ -135,3 +137,45 @@ def test_get_client():
assert client is not None
assert client.__class__ == NonRecordingClient
assert not client.is_active()


def raise_and_capture():
"""Raise an exception and capture it.

This is a utility function for test_set_tags.
"""
try:
1 / 0
except ZeroDivisionError:
capture_exception()


def test_set_tags(sentry_init, capture_events):
sentry_init()
events = capture_events()

set_tags({"tag1": "value1", "tag2": "value2"})
raise_and_capture()

(*_, event) = events
assert event["tags"] == {"tag1": "value1", "tag2": "value2"}, "Setting tags failed"

set_tags({"tag2": "updated", "tag3": "new"})
raise_and_capture()

(*_, event) = events
assert event["tags"] == {
"tag1": "value1",
"tag2": "updated",
"tag3": "new",
}, "Updating tags failed"

set_tags({})
raise_and_capture()

(*_, event) = events
assert event["tags"] == {
"tag1": "value1",
"tag2": "updated",
"tag3": "new",
}, "Updating tags with empty dict changed tags"
26 changes: 26 additions & 0 deletions tests/test_scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,3 +796,29 @@ def test_should_send_default_pii_false(sentry_init):
sentry_init(send_default_pii=False)

assert should_send_default_pii() is False


def test_set_tags():
scope = Scope()
scope.set_tags({"tag1": "value1", "tag2": "value2"})
event = scope.apply_to_event({}, {})

assert event["tags"] == {"tag1": "value1", "tag2": "value2"}, "Setting tags failed"

scope.set_tags({"tag2": "updated", "tag3": "new"})
event = scope.apply_to_event({}, {})

assert event["tags"] == {
"tag1": "value1",
"tag2": "updated",
"tag3": "new",
}, "Updating tags failed"

scope.set_tags({})
event = scope.apply_to_event({}, {})

assert event["tags"] == {
"tag1": "value1",
"tag2": "updated",
"tag3": "new",
}, "Updating tags with empty dict changed tags"