diff --git a/src/sentry/api/endpoints/group_details.py b/src/sentry/api/endpoints/group_details.py index 461bd86fc00566..b547c40969ee55 100644 --- a/src/sentry/api/endpoints/group_details.py +++ b/src/sentry/api/endpoints/group_details.py @@ -185,7 +185,12 @@ def get(self, request: Request, group) -> Response: } ) - tags = tagstore.get_group_tag_keys(group, environment_ids, limit=100) + tags = tagstore.get_group_tag_keys( + group, + environment_ids, + limit=100, + tenant_ids={"organization_id": group.project.organization_id}, + ) user_reports = ( UserReport.objects.filter(group_id=group.id) diff --git a/src/sentry/api/endpoints/group_tagkey_details.py b/src/sentry/api/endpoints/group_tagkey_details.py index 8210d05a9adad4..65111d041e9123 100644 --- a/src/sentry/api/endpoints/group_tagkey_details.py +++ b/src/sentry/api/endpoints/group_tagkey_details.py @@ -23,7 +23,7 @@ def get(self, request: Request, group, key) -> Response: :auth: required """ lookup_key = tagstore.prefix_reserved_key(key) - + tenant_ids = {"organization_id": group.project.organization_id} try: environment_id = self._get_environment_id_from_request( request, group.project.organization_id @@ -33,18 +33,23 @@ def get(self, request: Request, group, key) -> Response: raise ResourceDoesNotExist try: - group_tag_key = tagstore.get_group_tag_key(group, environment_id, lookup_key) + group_tag_key = tagstore.get_group_tag_key( + group, + environment_id, + lookup_key, + tenant_ids=tenant_ids, + ) except tagstore.GroupTagKeyNotFound: raise ResourceDoesNotExist if group_tag_key.count is None: group_tag_key.count = tagstore.get_group_tag_value_count( - group.project_id, group.id, environment_id, lookup_key + group.project_id, group.id, environment_id, lookup_key, tenant_ids=tenant_ids ) if group_tag_key.top_values is None: group_tag_key.top_values = tagstore.get_top_group_tag_values( - group, environment_id, lookup_key + group, environment_id, lookup_key, tenant_ids=tenant_ids ) return Response(serialize(group_tag_key, request.user)) diff --git a/src/sentry/api/endpoints/group_tagkey_values.py b/src/sentry/api/endpoints/group_tagkey_values.py index 6940e8a20d793f..86e0dcd3479cc5 100644 --- a/src/sentry/api/endpoints/group_tagkey_values.py +++ b/src/sentry/api/endpoints/group_tagkey_values.py @@ -27,9 +27,14 @@ def get(self, request: Request, group, key) -> Response: lookup_key = tagstore.prefix_reserved_key(key) environment_ids = [e.id for e in get_environments(request, group.project.organization)] - + tenant_ids = {"organization_id": group.project.organization_id} try: - tagstore.get_group_tag_key(group, None, lookup_key) + tagstore.get_group_tag_key( + group, + None, + lookup_key, + tenant_ids=tenant_ids, + ) except tagstore.GroupTagKeyNotFound: raise ResourceDoesNotExist sort = request.GET.get("sort") @@ -48,7 +53,7 @@ def get(self, request: Request, group, key) -> Response: serializer_cls = None paginator = tagstore.get_group_tag_value_paginator( - group, environment_ids, lookup_key, order_by=order_by + group, environment_ids, lookup_key, order_by=order_by, tenant_ids=tenant_ids ) return self.paginate( diff --git a/src/sentry/api/endpoints/group_tags.py b/src/sentry/api/endpoints/group_tags.py index d2b0afcccd6ff9..ee1d4c89f279c5 100644 --- a/src/sentry/api/endpoints/group_tags.py +++ b/src/sentry/api/endpoints/group_tags.py @@ -39,7 +39,11 @@ def get(self, request: Request, group: Group) -> Response: environment_ids = [e.id for e in get_environments(request, group.project.organization)] tag_keys = tagstore.get_group_tag_keys_and_top_values( - group, environment_ids, keys=keys, value_limit=value_limit + group, + environment_ids, + keys=keys, + value_limit=value_limit, + tenant_ids={"organization_id": group.project.organization_id}, ) data = serialize(tag_keys, request.user) diff --git a/src/sentry/api/endpoints/organization_tagkey_values.py b/src/sentry/api/endpoints/organization_tagkey_values.py index 90acb8bd8d1f11..66f2768d42c4d4 100644 --- a/src/sentry/api/endpoints/organization_tagkey_values.py +++ b/src/sentry/api/endpoints/organization_tagkey_values.py @@ -46,6 +46,7 @@ def get(self, request: Request, organization, key) -> Response: include_transactions=request.GET.get("includeTransactions") == "1", include_sessions=request.GET.get("includeSessions") == "1", include_replays=request.GET.get("includeReplays") == "1", + tenant_ids={"organization_id": organization.id}, ) return self.paginate( diff --git a/src/sentry/api/endpoints/organization_tags.py b/src/sentry/api/endpoints/organization_tags.py index 9f9e588dbfa4c9..47db36e9385995 100644 --- a/src/sentry/api/endpoints/organization_tags.py +++ b/src/sentry/api/endpoints/organization_tags.py @@ -28,6 +28,7 @@ def get(self, request: Request, organization) -> Response: use_cache=request.GET.get("use_cache", "0") == "1", # Defaults to True, because the frontend caches these tags globally include_transactions=request.GET.get("include_transactions", "1") == "1", + tenant_ids={"organization_id": organization.id}, ) if not features.has( "organizations:javascript-console-error-tag", diff --git a/src/sentry/api/endpoints/organization_user_issues_search.py b/src/sentry/api/endpoints/organization_user_issues_search.py index 1e23517b1d004f..fef2c6417cabb0 100644 --- a/src/sentry/api/endpoints/organization_user_issues_search.py +++ b/src/sentry/api/endpoints/organization_user_issues_search.py @@ -38,6 +38,7 @@ def get(self, request: Request, organization) -> Response: project_ids=list({e.project_id for e in event_users}), event_users=event_users, limit=limit, + tenant_ids={"organization_id": organization.id}, ) ).order_by("-last_seen")[:limit] else: diff --git a/src/sentry/api/endpoints/project_tagkey_details.py b/src/sentry/api/endpoints/project_tagkey_details.py index fe12b640ea09c4..ffaacb9eca805a 100644 --- a/src/sentry/api/endpoints/project_tagkey_details.py +++ b/src/sentry/api/endpoints/project_tagkey_details.py @@ -32,7 +32,12 @@ def get(self, request: Request, project, key) -> Response: raise ResourceDoesNotExist try: - tagkey = tagstore.get_tag_key(project.id, environment_id, lookup_key) + tagkey = tagstore.get_tag_key( + project.id, + environment_id, + lookup_key, + tenant_ids={"organization_id": project.organization_id}, + ) except tagstore.TagKeyNotFound: raise ResourceDoesNotExist @@ -55,7 +60,7 @@ def delete(self, request: Request, project, key) -> Response: eventstream_state = eventstream.start_delete_tag(project.id, key) - deleted = self.get_tag_keys_for_deletion(project.id, lookup_key) + deleted = self.get_tag_keys_for_deletion(project, lookup_key) # NOTE: By sending the `end_delete_tag` message here we are making # the assumption that the `delete_tag_key` does its work @@ -77,8 +82,15 @@ def delete(self, request: Request, project, key) -> Response: return Response(status=204) - def get_tag_keys_for_deletion(self, project_id, key): + def get_tag_keys_for_deletion(self, project, key): try: - return [tagstore.get_tag_key(project_id=project_id, key=key, environment_id=None)] + return [ + tagstore.get_tag_key( + project_id=project.id, + key=key, + environment_id=None, + tenant_ids={"organization_id": project.organization_id}, + ) + ] except tagstore.TagKeyNotFound: return [] diff --git a/src/sentry/api/endpoints/project_tagkey_values.py b/src/sentry/api/endpoints/project_tagkey_values.py index f46774d93acf1a..55dbeb319c5876 100644 --- a/src/sentry/api/endpoints/project_tagkey_values.py +++ b/src/sentry/api/endpoints/project_tagkey_values.py @@ -28,7 +28,7 @@ def get(self, request: Request, project, key) -> Response: :auth: required """ lookup_key = tagstore.prefix_reserved_key(key) - + tenant_ids = {"organization_id": project.organization_id} try: environment_id = self._get_environment_id_from_request(request, project.organization_id) except Environment.DoesNotExist: @@ -36,7 +36,12 @@ def get(self, request: Request, project, key) -> Response: raise ResourceDoesNotExist try: - tagkey = tagstore.get_tag_key(project.id, environment_id, lookup_key) + tagkey = tagstore.get_tag_key( + project.id, + environment_id, + lookup_key, + tenant_ids=tenant_ids, + ) except tagstore.TagKeyNotFound: raise ResourceDoesNotExist @@ -50,6 +55,7 @@ def get(self, request: Request, project, key) -> Response: end=end, query=request.GET.get("query"), order_by="-last_seen", + tenant_ids=tenant_ids, ) return self.paginate( diff --git a/src/sentry/api/endpoints/project_tags.py b/src/sentry/api/endpoints/project_tags.py index b945f72aaa55e2..65a159ebb088d6 100644 --- a/src/sentry/api/endpoints/project_tags.py +++ b/src/sentry/api/endpoints/project_tags.py @@ -26,7 +26,12 @@ def get(self, request: Request, project) -> Response: kwargs.update(denylist=DS_DENYLIST) tag_keys = sorted( - tagstore.get_tag_keys(project.id, environment_id, **kwargs), + tagstore.get_tag_keys( + project.id, + environment_id, + tenant_ids={"organization_id": project.organization_id}, + **kwargs, + ), key=lambda x: x.key, ) diff --git a/src/sentry/api/serializers/models/group.py b/src/sentry/api/serializers/models/group.py index 0f698a060deb37..9f00c5d44f55ff 100644 --- a/src/sentry/api/serializers/models/group.py +++ b/src/sentry/api/serializers/models/group.py @@ -811,8 +811,12 @@ def __seen_stats_impl( project_id = issue_list[0].project_id item_ids = [g.id for g in issue_list] + tenant_ids = {"organization_id": issue_list[0].project.organization_id} user_counts: Mapping[int, int] = user_counts_func( - [project_id], item_ids, environment_ids=environment and [environment.id] + [project_id], + item_ids, + environment_ids=environment and [environment.id], + tenant_ids=tenant_ids, ) first_seen: MutableMapping[int, datetime] = {} last_seen: MutableMapping[int, datetime] = {} @@ -820,7 +824,12 @@ def __seen_stats_impl( if environment is not None: environment_seen_stats = environment_seen_stats_func( - [project_id], item_ids, [environment.id], "environment", environment.name + [project_id], + item_ids, + [environment.id], + "environment", + environment.name, + tenant_ids=tenant_ids, ) for item_id, value in environment_seen_stats.items(): first_seen[item_id] = value.first_seen diff --git a/src/sentry/data_export/processors/issues_by_tag.py b/src/sentry/data_export/processors/issues_by_tag.py index 35622067b5d2d8..753c67a31e7f4c 100644 --- a/src/sentry/data_export/processors/issues_by_tag.py +++ b/src/sentry/data_export/processors/issues_by_tag.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from sentry import tagstore from sentry.models import EventUser, Group, Project, get_group_with_redirect @@ -9,7 +11,14 @@ class IssuesByTagProcessor: Processor for exports of issues data based on a provided tag """ - def __init__(self, project_id, group_id, key, environment_id): + def __init__( + self, + project_id, + group_id, + key, + environment_id, + tenant_ids: dict[str, str | int] | None = None, + ): self.project = self.get_project(project_id) self.group = self.get_group(group_id, self.project) self.key = key @@ -18,7 +27,9 @@ def __init__(self, project_id, group_id, key, environment_id): self.lookup_key = self.get_lookup_key(self.key) # Ensure the tag key exists, as it may have been deleted try: - tagstore.get_tag_key(self.project.id, environment_id, self.lookup_key) + tagstore.get_tag_key( + self.project.id, environment_id, self.lookup_key, tenant_ids=tenant_ids + ) except tagstore.TagKeyNotFound: raise ExportError("Requested key does not exist") self.callbacks = self.get_callbacks(self.key, self.group.project_id) @@ -101,6 +112,7 @@ def get_raw_data(self, limit=1000, offset=0): callbacks=self.callbacks, limit=limit, offset=offset, + tenant_ids={"organization_id": self.project.organization_id}, ) def get_serialized_data(self, limit=1000, offset=0): diff --git a/src/sentry/models/group.py b/src/sentry/models/group.py index 1589c273a14f9d..2025c02cd8dfb3 100644 --- a/src/sentry/models/group.py +++ b/src/sentry/models/group.py @@ -627,7 +627,11 @@ def get_email_subject(self): def count_users_seen(self): return tagstore.get_groups_user_counts( - [self.project_id], [self.id], environment_ids=None, start=self.first_seen + [self.project_id], + [self.id], + environment_ids=None, + start=self.first_seen, + tenant_ids={"organization_id": self.project.organization_id}, )[self.id] @classmethod diff --git a/src/sentry/tagstore/base.py b/src/sentry/tagstore/base.py index 9cf1aafd20a273..af4815c956f01b 100644 --- a/src/sentry/tagstore/base.py +++ b/src/sentry/tagstore/base.py @@ -122,14 +122,21 @@ def get_tag_value_label(self, key, value): return label @raises([TagKeyNotFound]) - def get_tag_key(self, project_id, environment_id, key, status=TagKeyStatus.VISIBLE): + def get_tag_key( + self, project_id, environment_id, key, status=TagKeyStatus.VISIBLE, tenant_ids=None + ): """ >>> get_tag_key(1, 2, "key1") """ raise NotImplementedError def get_tag_keys( - self, project_id, environment_id, status=TagKeyStatus.VISIBLE, include_values_seen=False + self, + project_id, + environment_id, + status=TagKeyStatus.VISIBLE, + include_values_seen=False, + tenant_ids=None, ): """ >>> get_tag_keys(1, 2) @@ -137,7 +144,7 @@ def get_tag_keys( raise NotImplementedError def get_tag_keys_for_projects( - self, projects, environments, start, end, status=TagKeyStatus.VISIBLE + self, projects, environments, start, end, status=TagKeyStatus.VISIBLE, tenant_ids=None ): """ >>> get_tag_key([1], [2]) @@ -145,73 +152,74 @@ def get_tag_keys_for_projects( raise NotImplementedError @raises([TagValueNotFound]) - def get_tag_value(self, project_id, environment_id, key, value): + def get_tag_value(self, project_id, environment_id, key, value, tenant_ids=None): """ >>> get_tag_value(1, 2, "key1", "value1") """ raise NotImplementedError - def get_tag_values(self, project_id, environment_id, key): + def get_tag_values(self, project_id, environment_id, key, tenant_ids=None): """ >>> get_tag_values(1, 2, "key1") """ raise NotImplementedError @raises([GroupTagKeyNotFound]) - def get_group_tag_key(self, group, environment_id, key): + def get_group_tag_key(self, group, environment_id, key, tenant_ids=None): """ >>> get_group_tag_key(group, 3, "key1") """ raise NotImplementedError - def get_group_tag_keys(self, group, environment_ids, limit=None, keys=None): + def get_group_tag_keys(self, group, environment_ids, limit=None, keys=None, tenant_ids=None): """ >>> get_group_tag_key(group, 2, [3]) """ raise NotImplementedError @raises([GroupTagValueNotFound]) - def get_group_tag_value(self, project_id, group_id, environment_id, key, value): + def get_group_tag_value( + self, project_id, group_id, environment_id, key, value, tenant_ids=None + ): """ >>> get_group_tag_value(1, 2, 3, "key1", "value1") """ raise NotImplementedError - def get_group_tag_values(self, group, environment_id, key): + def get_group_tag_values(self, group, environment_id, key, tenant_ids=None): """ >>> get_group_tag_values(group, 3, "key1") """ raise NotImplementedError - def get_group_list_tag_value(self, project_ids, group_id_list, environment_ids, key, value): + def get_group_list_tag_value( + self, project_ids, group_id_list, environment_ids, key, value, tenant_ids=None + ): """ >>> get_group_list_tag_value([1, 2], [1, 2, 3, 4, 5], [3], "key1", "value1") """ raise NotImplementedError def get_perf_group_list_tag_value( - self, project_ids, group_id_list, environment_ids, key, value + self, project_ids, group_id_list, environment_ids, key, value, tenant_ids=None ): raise NotImplementedError def get_generic_group_list_tag_value( - self, project_ids, group_id_list, environment_ids, key, value + self, project_ids, group_id_list, environment_ids, key, value, tenant_ids=None ): raise NotImplementedError - def get_group_event_filter(self, project_id, group_id, environment_ids, tags, start, end): + def get_group_event_filter( + self, project_id, group_id, environment_ids, tags, start, end, tenant_ids=None + ): """ >>> get_group_event_filter(1, 2, 3, {'key1': 'value1', 'key2': 'value2'}) """ raise NotImplementedError def get_tag_value_paginator( - self, - project_id, - environment_id, - key, - query=None, - order_by="-last_seen", + self, project_id, environment_id, key, query=None, order_by="-last_seen", tenant_ids=None ): """ >>> get_tag_value_paginator(1, 2, 'environment', query='prod') @@ -227,6 +235,7 @@ def get_tag_value_paginator_for_projects( end, query=None, order_by="-last_seen", + tenant_ids=None, ): """ Includes tags and also snuba columns, with the arrayjoin when they are nested. @@ -235,13 +244,17 @@ def get_tag_value_paginator_for_projects( """ raise NotImplementedError - def get_group_tag_value_iter(self, group, environment_ids, key, callbacks=(), offset=0): + def get_group_tag_value_iter( + self, group, environment_ids, key, callbacks=(), offset=0, tenant_ids=None + ): """ >>> get_group_tag_value_iter(group, 2, 3, 'environment') """ raise NotImplementedError - def get_group_tag_value_paginator(self, group, environment_ids, key, order_by="-id"): + def get_group_tag_value_paginator( + self, group, environment_ids, key, order_by="-id", tenant_ids=None + ): """ >>> get_group_tag_value_paginator(group, 3, 'environment') """ @@ -253,7 +266,9 @@ def get_group_tag_value_qs(self, project_id, group_id, environment_id, key, valu """ raise NotImplementedError - def get_groups_user_counts(self, project_ids, group_ids, environment_ids, start=None, end=None): + def get_groups_user_counts( + self, project_ids, group_ids, environment_ids, start=None, end=None, tenant_ids=None + ): """ >>> get_groups_user_counts([1, 2], [2, 3], [4, 5]) `start` and `end` are only used by the snuba backend @@ -261,22 +276,24 @@ def get_groups_user_counts(self, project_ids, group_ids, environment_ids, start= raise NotImplementedError def get_perf_groups_user_counts( - self, project_ids, group_ids, environment_ids, start=None, end=None + self, project_ids, group_ids, environment_ids, start=None, end=None, tenant_ids=None ): raise NotImplementedError def get_generic_groups_user_counts( - self, project_ids, group_ids, environment_ids, start=None, end=None + self, project_ids, group_ids, environment_ids, start=None, end=None, tenant_ids=None ): raise NotImplementedError - def get_group_tag_value_count(self, group, environment_id, key): + def get_group_tag_value_count(self, group, environment_id, key, tenant_ids=None): """ >>> get_group_tag_value_count(group, 3, 'key1') """ raise NotImplementedError - def get_top_group_tag_values(self, group, environment_id, key, limit=TOP_VALUES_DEFAULT_LIMIT): + def get_top_group_tag_values( + self, group, environment_id, key, limit=TOP_VALUES_DEFAULT_LIMIT, tenant_ids=None + ): """ >>> get_top_group_tag_values(group, 3, 'key1') """ @@ -300,13 +317,13 @@ def get_release_tags(self, organization_id, project_ids, environment_id, version """ raise NotImplementedError - def get_group_ids_for_users(self, project_ids, event_users, limit=100): + def get_group_ids_for_users(self, project_ids, event_users, limit=100, tenant_ids=None): """ >>> get_group_ids_for_users([1,2], [EventUser(1), EventUser(2)]) """ raise NotImplementedError - def get_group_tag_values_for_users(self, event_users, limit=100): + def get_group_tag_values_for_users(self, event_users, limit=100, tenant_ids=None): """ >>> get_group_tag_values_for_users([EventUser(1), EventUser(2)]) """ @@ -318,6 +335,7 @@ def get_group_tag_keys_and_top_values( environment_ids, keys=None, value_limit=TOP_VALUES_DEFAULT_LIMIT, + tenant_ids=None, **kwargs, ): @@ -326,7 +344,7 @@ def get_group_tag_keys_and_top_values( environment_ids = environment_ids[:1] # If keys is unspecified, we will grab all tag keys for this group. - tag_keys = self.get_group_tag_keys(group, environment_ids, keys=keys) + tag_keys = self.get_group_tag_keys(group, environment_ids, keys=keys, tenant_ids=tenant_ids) environment_id = environment_ids[0] if environment_ids else None for tk in tag_keys: @@ -339,6 +357,6 @@ def get_group_tag_keys_and_top_values( return tag_keys def get_group_seen_values_for_environments( - self, project_ids, group_id_list, environment_ids, start=None, end=None + self, project_ids, group_id_list, environment_ids, start=None, end=None, tenant_ids=None ): raise NotImplementedError diff --git a/src/sentry/tagstore/snuba/backend.py b/src/sentry/tagstore/snuba/backend.py index be077f5b4185a9..1ce0f461786524 100644 --- a/src/sentry/tagstore/snuba/backend.py +++ b/src/sentry/tagstore/snuba/backend.py @@ -136,7 +136,15 @@ def __get_tag_key(self, project_id, group_id, environment_id, key): return GroupTagKey(group_id=group_id, **data) def __get_tag_key_and_top_values( - self, project_id, group, environment_id, key, limit=3, raise_on_empty=True, **kwargs + self, + project_id, + group, + environment_id, + key, + limit=3, + raise_on_empty=True, + tenant_ids=None, + **kwargs, ): tag = f"tags[{key}]" filters = {"project_id": get_project_list(project_id)} @@ -168,6 +176,7 @@ def __get_tag_key_and_top_values( limit=limit, totals=True, referrer="tagstore.__get_tag_key_and_top_values", + tenant_ids=tenant_ids, ) if raise_on_empty and (not result or totals.get("count", 0) == 0): @@ -208,6 +217,7 @@ def __get_tag_keys( include_values_seen=True, include_transactions=False, denylist=None, + tenant_ids=None, **kwargs, ): return self.__get_tag_keys_for_projects( @@ -221,6 +231,7 @@ def __get_tag_keys( include_values_seen=include_values_seen, include_transactions=include_transactions, denylist=denylist, + tenant_ids=tenant_ids, ) def __get_tag_keys_for_projects( @@ -345,7 +356,7 @@ def __get_tag_keys_for_projects( results.add(ctor(**params)) return results - def __get_tag_value(self, project_id, group_id, environment_id, key, value): + def __get_tag_value(self, project_id, group_id, environment_id, key, value, tenant_ids=None): tag = f"tags[{key}]" filters = {"project_id": get_project_list(project_id)} if environment_id: @@ -365,6 +376,7 @@ def __get_tag_value(self, project_id, group_id, environment_id, key, value): filter_keys=filters, aggregations=aggregations, referrer="tagstore.__get_tag_value", + tenant_ids=tenant_ids, ) if not data["times_seen"] > 0: raise TagValueNotFound if group_id is None else GroupTagValueNotFound @@ -375,9 +387,19 @@ def __get_tag_value(self, project_id, group_id, environment_id, key, value): else: return GroupTagValue(group_id=group_id, **fix_tag_value_data(data)) - def get_tag_key(self, project_id, environment_id, key, status=TagKeyStatus.VISIBLE, **kwargs): + def get_tag_key( + self, + project_id, + environment_id, + key, + status=TagKeyStatus.VISIBLE, + tenant_ids=None, + **kwargs, + ): assert status is TagKeyStatus.VISIBLE - return self.__get_tag_key_and_top_values(project_id, None, environment_id, key, **kwargs) + return self.__get_tag_key_and_top_values( + project_id, None, environment_id, key, tenant_ids=tenant_ids, **kwargs + ) def get_tag_keys( self, @@ -386,10 +408,15 @@ def get_tag_keys( status=TagKeyStatus.VISIBLE, include_values_seen=False, denylist=None, + tenant_ids=None, ): assert status is TagKeyStatus.VISIBLE return self.__get_tag_keys( - project_id, None, environment_id and [environment_id], denylist=denylist + project_id, + None, + environment_id and [environment_id], + denylist=denylist, + tenant_ids=tenant_ids, ) def get_tag_keys_for_projects( @@ -401,6 +428,7 @@ def get_tag_keys_for_projects( status=TagKeyStatus.VISIBLE, use_cache=False, include_transactions=False, + tenant_ids=None, ): max_unsampled_projects = _max_unsampled_projects # We want to disable FINAL in the snuba query to reduce load. @@ -420,24 +448,40 @@ def get_tag_keys_for_projects( include_values_seen=False, use_cache=use_cache, include_transactions=include_transactions, + tenant_ids=tenant_ids, **optimize_kwargs, ) - def get_tag_value(self, project_id, environment_id, key, value): - return self.__get_tag_value(project_id, None, environment_id, key, value) + def get_tag_value(self, project_id, environment_id, key, value, tenant_ids=None): + return self.__get_tag_value( + project_id, None, environment_id, key, value, tenant_ids=tenant_ids + ) - def get_tag_values(self, project_id, environment_id, key): + def get_tag_values(self, project_id, environment_id, key, tenant_ids=None): key = self.__get_tag_key_and_top_values( - project_id, None, environment_id, key, limit=None, raise_on_empty=False + project_id, + None, + environment_id, + key, + limit=None, + raise_on_empty=False, + tenant_ids=tenant_ids, ) return set(key.top_values) - def get_group_tag_key(self, group, environment_id, key): + def get_group_tag_key(self, group, environment_id, key, tenant_ids=None): return self.__get_tag_key_and_top_values( - group.project_id, group, environment_id, key, limit=TOP_VALUES_DEFAULT_LIMIT + group.project_id, + group, + environment_id, + key, + limit=TOP_VALUES_DEFAULT_LIMIT, + tenant_ids=tenant_ids, ) - def get_group_tag_keys(self, group, environment_ids, limit=None, keys=None, **kwargs): + def get_group_tag_keys( + self, group, environment_ids, limit=None, keys=None, tenant_ids=None, **kwargs + ): """Get tag keys for a specific group""" return self.__get_tag_keys( group.project_id, @@ -447,17 +491,28 @@ def get_group_tag_keys(self, group, environment_ids, limit=None, keys=None, **kw limit=limit, keys=keys, include_values_seen=False, + tenant_ids=tenant_ids, **kwargs, ) - def get_group_tag_value(self, project_id, group_id, environment_id, key, value): - return self.__get_tag_value(project_id, group_id, environment_id, key, value) + def get_group_tag_value( + self, project_id, group_id, environment_id, key, value, tenant_ids=None + ): + return self.__get_tag_value( + project_id, group_id, environment_id, key, value, tenant_ids=tenant_ids + ) - def get_group_tag_values(self, group, environment_id, key): + def get_group_tag_values(self, group, environment_id, key, tenant_ids=None): # NB this uses a 'top' values function, but the limit is None so it should # return all values for this key. key = self.__get_tag_key_and_top_values( - group.project_id, group, environment_id, key, limit=None, raise_on_empty=False + group.project_id, + group, + environment_id, + key, + limit=None, + raise_on_empty=False, + tenant_ids=tenant_ids, ) return set(key.top_values) @@ -472,6 +527,7 @@ def __get_group_list_tag_value( extra_conditions, extra_aggregations, referrer, + tenant_ids=None, ): filters = {"project_id": project_ids, "group_id": group_id_list} if environment_ids: @@ -490,6 +546,7 @@ def __get_group_list_tag_value( filter_keys=filters, aggregations=aggregations, referrer=referrer, + tenant_ids=tenant_ids, ) return { @@ -499,7 +556,9 @@ def __get_group_list_tag_value( for group_id, data in result.items() } - def get_group_list_tag_value(self, project_ids, group_id_list, environment_ids, key, value): + def get_group_list_tag_value( + self, project_ids, group_id_list, environment_ids, key, value, tenant_ids=None + ): return self.__get_group_list_tag_value( project_ids, group_id_list, @@ -510,10 +569,11 @@ def get_group_list_tag_value(self, project_ids, group_id_list, environment_ids, [DEFAULT_TYPE_CONDITION], [], "tagstore.get_group_list_tag_value", + tenant_ids=tenant_ids, ) def get_perf_group_list_tag_value( - self, project_ids, group_id_list, environment_ids, key, value + self, project_ids, group_id_list, environment_ids, key, value, tenant_ids=None ): filters = {"project_id": project_ids} if environment_ids: @@ -534,6 +594,7 @@ def get_perf_group_list_tag_value( ["max", SEEN_COLUMN, "last_seen"], ], referrer="tagstore.get_perf_group_list_tag_value", + tenant_ids=tenant_ids, ) return { @@ -542,7 +603,7 @@ def get_perf_group_list_tag_value( } def get_generic_group_list_tag_value( - self, project_ids, group_id_list, environment_ids, key, value + self, project_ids, group_id_list, environment_ids, key, value, tenant_ids=None ): translated_params = _translate_filter_keys(project_ids, group_id_list, environment_ids) organization_id = get_organization_id_from_project_ids(project_ids) @@ -577,6 +638,7 @@ def get_generic_group_list_tag_value( where=where_conditions, groupby=[Column("group_id")], ), + tenant_ids=tenant_ids, ) result_snql = raw_snql_query( snuba_request, referrer="tagstore.get_generic_group_list_tag_value", use_cache=True @@ -594,7 +656,7 @@ def get_generic_group_list_tag_value( } def get_group_seen_values_for_environments( - self, project_ids, group_id_list, environment_ids, start=None, end=None + self, project_ids, group_id_list, environment_ids, start=None, end=None, tenant_ids=None ): # Get the total times seen, first seen, and last seen across multiple environments filters = {"project_id": project_ids, "group_id": group_id_list} @@ -616,6 +678,7 @@ def get_group_seen_values_for_environments( filter_keys=filters, aggregations=aggregations, referrer="tagstore.get_group_seen_values_for_environments", + tenant_ids=tenant_ids, ) return {issue: fix_tag_value_data(data) for issue, data in result.items()} @@ -632,7 +695,7 @@ def apply_group_filters_conditions(self, group: Group, conditions, filters): dataset = Dataset.IssuePlatform return dataset, conditions, filters - def get_group_tag_value_count(self, group, environment_id, key): + def get_group_tag_value_count(self, group, environment_id, key, tenant_ids=None): tag = f"tags[{key}]" filters = {"project_id": get_project_list(group.project_id)} if environment_id: @@ -649,10 +712,15 @@ def get_group_tag_value_count(self, group, environment_id, key): filter_keys=filters, aggregations=aggregations, referrer="tagstore.get_group_tag_value_count", + tenant_ids=tenant_ids, ) - def get_top_group_tag_values(self, group, environment_id, key, limit=TOP_VALUES_DEFAULT_LIMIT): - tag = self.__get_tag_key_and_top_values(group.project_id, group, environment_id, key, limit) + def get_top_group_tag_values( + self, group, environment_id, key, limit=TOP_VALUES_DEFAULT_LIMIT, tenant_ids=None + ): + tag = self.__get_tag_key_and_top_values( + group.project_id, group, environment_id, key, limit, tenant_ids=tenant_ids + ) return tag.top_values def get_group_tag_keys_and_top_values( @@ -661,6 +729,7 @@ def get_group_tag_keys_and_top_values( environment_ids: Sequence[int], keys: Optional[Sequence[str]] = None, value_limit: int = TOP_VALUES_DEFAULT_LIMIT, + tenant_ids=None, **kwargs, ): # Similar to __get_tag_key_and_top_values except we get the top values @@ -669,7 +738,9 @@ def get_group_tag_keys_and_top_values( # num_keys * limit. # First get totals and unique counts by key. - keys_with_counts = self.get_group_tag_keys(group, environment_ids, keys=keys) + keys_with_counts = self.get_group_tag_keys( + group, environment_ids, keys=keys, tenant_ids=tenant_ids + ) # Then get the top values with first_seen/last_seen/count for each filters = {"project_id": get_project_list(group.project_id)} @@ -700,6 +771,7 @@ def get_group_tag_keys_and_top_values( orderby="-count", limitby=[value_limit, "tags_key"], referrer="tagstore._get_tag_keys_and_top_values", + tenant_ids=tenant_ids, ) # Then supplement the key objects with the top values for each. @@ -771,7 +843,7 @@ def get_min_start_date(self, organization_id, project_ids, environment_id, versi return None - def get_group_ids_for_users(self, project_ids, event_users, limit=100): + def get_group_ids_for_users(self, project_ids, event_users, limit=100, tenant_ids=None): filters = {"project_id": project_ids} conditions = [ ["tags[sentry:user]", "IN", [_f for _f in [eu.tag_value for eu in event_users] if _f]] @@ -787,10 +859,11 @@ def get_group_ids_for_users(self, project_ids, event_users, limit=100): limit=limit, orderby="-last_seen", referrer="tagstore.get_group_ids_for_users", + tenant_ids=tenant_ids, ) return set(result.keys()) - def get_group_tag_values_for_users(self, event_users, limit=100): + def get_group_tag_values_for_users(self, event_users, limit=100, tenant_ids=None): """While not specific to a group_id, this is currently only used in issues, so the Events dataset is used""" filters = {"project_id": [eu.project_id for eu in event_users]} conditions = [ @@ -811,6 +884,7 @@ def get_group_tag_values_for_users(self, event_users, limit=100): orderby="-last_seen", limit=limit, referrer="tagstore.get_group_tag_values_for_users", + tenant_ids=tenant_ids, ) values = [] @@ -833,6 +907,7 @@ def __get_groups_user_counts( dataset=Dataset.Events, extra_aggregations=None, referrer="tagstore.__get_groups_user_counts", + tenant_ids=None, ): filters = {"project_id": project_ids, "group_id": group_ids} if environment_ids: @@ -852,11 +927,14 @@ def __get_groups_user_counts( aggregations=aggregations, orderby="-count", referrer=referrer, + tenant_ids=tenant_ids, ) return defaultdict(int, {k: v for k, v in result.items() if v}) - def get_groups_user_counts(self, project_ids, group_ids, environment_ids, start=None, end=None): + def get_groups_user_counts( + self, project_ids, group_ids, environment_ids, start=None, end=None, tenant_ids=None + ): return self.__get_groups_user_counts( project_ids, group_ids, @@ -866,10 +944,11 @@ def get_groups_user_counts(self, project_ids, group_ids, environment_ids, start= Dataset.Events, [], "tagstore.get_groups_user_counts", + tenant_ids=tenant_ids, ) def get_perf_groups_user_counts( - self, project_ids, group_ids, environment_ids, start=None, end=None + self, project_ids, group_ids, environment_ids, start=None, end=None, tenant_ids=None ): filters_keys = {"project_id": project_ids} if environment_ids: @@ -887,6 +966,7 @@ def get_perf_groups_user_counts( ], groupby=["group_id"], referrer="tagstore.get_perf_groups_user_counts", + tenant_ids=tenant_ids, ) return defaultdict( @@ -899,7 +979,7 @@ def get_perf_groups_user_counts( ) def get_generic_groups_user_counts( - self, project_ids, group_ids, environment_ids, start=None, end=None + self, project_ids, group_ids, environment_ids, start=None, end=None, tenant_ids=None ): translated_params = _translate_filter_keys(project_ids, group_ids, environment_ids) organization_id = get_organization_id_from_project_ids(project_ids) @@ -933,6 +1013,7 @@ def get_generic_groups_user_counts( groupby=[Column("group_id")], orderby=[OrderBy(Column("count"), Direction.DESC)], ), + tenant_ids=tenant_ids, ) result_snql = raw_snql_query( @@ -952,6 +1033,7 @@ def get_tag_value_paginator( end=None, query=None, order_by="-last_seen", + tenant_ids=None, ): return self.get_tag_value_paginator_for_projects( get_project_list(project_id), @@ -961,6 +1043,7 @@ def get_tag_value_paginator( end=end, query=query, order_by=order_by, + tenant_ids=tenant_ids, ) def _get_semver_versions_for_package(self, projects, organization_id, package): @@ -1167,6 +1250,7 @@ def get_tag_value_paginator_for_projects( include_transactions=False, include_sessions=False, include_replays=False, + tenant_ids=None, ): from sentry.api.paginator import SequencePaginator @@ -1350,6 +1434,7 @@ def get_tag_value_paginator_for_projects( sample=1_000_000, arrayjoin=snuba.get_arrayjoin(snuba_key), referrer="tagstore.get_tag_value_paginator_for_projects", + tenant_ids=tenant_ids, ) if include_transactions: @@ -1391,7 +1476,7 @@ def score_field_to_int(tv: TagValue) -> int: ) def get_group_tag_value_iter( - self, group, environment_ids, key, callbacks=(), limit=1000, offset=0 + self, group, environment_ids, key, callbacks=(), limit=1000, offset=0, tenant_ids=None ): filters = { "project_id": get_project_list(group.project_id), @@ -1415,6 +1500,7 @@ def get_group_tag_value_iter( limit=limit, referrer="tagstore.get_group_tag_value_iter", offset=offset, + tenant_ids=tenant_ids, ) group_tag_values = [ @@ -1427,7 +1513,9 @@ def get_group_tag_value_iter( return group_tag_values - def get_group_tag_value_paginator(self, group, environment_ids, key, order_by="-id"): + def get_group_tag_value_paginator( + self, group, environment_ids, key, order_by="-id", tenant_ids=None + ): from sentry.api.paginator import SequencePaginator if order_by in ("-last_seen", "-first_seen", "-times_seen"): @@ -1438,7 +1526,9 @@ def get_group_tag_value_paginator(self, group, environment_ids, key, order_by="- else: raise ValueError("Unsupported order_by: %s" % order_by) - group_tag_values = self.get_group_tag_value_iter(group, environment_ids, key) + group_tag_values = self.get_group_tag_value_iter( + group, environment_ids, key, tenant_ids=tenant_ids + ) desc = order_by.startswith("-") score_field = order_by.lstrip("-") @@ -1461,7 +1551,9 @@ def get_group_tag_value_qs(self, project_id, group_id, environment_id, key, valu # search backend. raise NotImplementedError - def get_group_event_filter(self, project_id, group_id, environment_ids, tags, start, end): + def get_group_event_filter( + self, project_id, group_id, environment_ids, tags, start, end, tenant_ids=None + ): filters = {"project_id": get_project_list(project_id), "group_id": [group_id]} if environment_ids: filters["environment"] = environment_ids @@ -1481,6 +1573,7 @@ def get_group_event_filter(self, project_id, group_id, environment_ids, tags, st filter_keys=filters, limit=1000, referrer="tagstore.get_group_event_filter", + tenant_ids=tenant_ids, ) event_id_set = {row["event_id"] for row in result["data"]} diff --git a/src/sentry/tsdb/snuba.py b/src/sentry/tsdb/snuba.py index 779bf4d84fe28a..99a063e30630a0 100644 --- a/src/sentry/tsdb/snuba.py +++ b/src/sentry/tsdb/snuba.py @@ -442,7 +442,6 @@ def __get_data_snql( Condition(Column(time_column), Op.LT, end), ] - referrer = f"tsdb-modelid:{model.value}" snql_request = Request( dataset=model_dataset.value, app_id="tsdb.get_data", @@ -457,7 +456,9 @@ def __get_data_snql( ), tenant_ids=tenant_ids or dict(), ) - query_result = raw_snql_query(snql_request, referrer=referrer, use_cache=use_cache) + query_result = raw_snql_query( + snql_request, f"tsdb-modelid:{model.value}", use_cache=use_cache + ) if manual_group_on_time: translated_results = {"data": query_result["data"]} else: diff --git a/src/sentry/utils/snuba.py b/src/sentry/utils/snuba.py index bc2933af233e1c..004c11390e8330 100644 --- a/src/sentry/utils/snuba.py +++ b/src/sentry/utils/snuba.py @@ -717,7 +717,7 @@ def raw_query( """ if referrer: - kwargs["tenant_ids"] = kwargs["tenant_ids"] if "tenant_ids" in kwargs else dict() + kwargs["tenant_ids"] = kwargs.get("tenant_ids") or dict() kwargs["tenant_ids"]["referrer"] = referrer snuba_params = SnubaQueryParams( diff --git a/src/sentry/web/frontend/group_tag_export.py b/src/sentry/web/frontend/group_tag_export.py index 3892cf99e363b3..5f071c4825aa46 100644 --- a/src/sentry/web/frontend/group_tag_export.py +++ b/src/sentry/web/frontend/group_tag_export.py @@ -31,7 +31,11 @@ def get(self, request: Request, organization, project, group_id, key) -> Respons try: processor = IssuesByTagProcessor( - project_id=project.id, group_id=group_id, key=key, environment_id=environment_id + project_id=project.id, + group_id=group_id, + key=key, + environment_id=environment_id, + tenant_ids={"organization_id": project.organization_id}, ) except ExportError: raise Http404