Просмотр исходного кода

fix(trace-explorer): Query trace meta across all projects (#69062)

The meta data needs to be queried across all projects or it will be
incomplete as spans from other projects will augment the result.
Tony Xiao 10 месяцев назад
Родитель
Сommit
8aec3dd6e2

+ 18 - 1
src/sentry/api/endpoints/organization_traces.py

@@ -9,7 +9,7 @@ from rest_framework.request import Request
 from rest_framework.response import Response
 from snuba_sdk import Column, Condition, Op
 
-from sentry import options
+from sentry import features, options
 from sentry.api.api_owners import ApiOwner
 from sentry.api.api_publish_status import ApiPublishStatus
 from sentry.api.base import region_silo_endpoint
@@ -57,6 +57,11 @@ class OrganizationTracesEndpoint(OrganizationEventsV2EndpointBase):
     owner = ApiOwner.PERFORMANCE
 
     def get(self, request: Request, organization: Organization) -> Response:
+        if not features.has(
+            "organizations:performance-trace-explorer", organization, actor=request.user
+        ):
+            return Response(status=404)
+
         try:
             snuba_params, params = self.get_snuba_dataclass(request, organization)
         except NoProjects:
@@ -135,6 +140,18 @@ class OrganizationTracesEndpoint(OrganizationEventsV2EndpointBase):
             snuba_params.start = min_timestamp - buffer
             snuba_params.end = max_timestamp + buffer
 
+            all_projects = self.get_projects(
+                request,
+                organization,
+                project_ids={-1},
+                project_slugs=None,
+                include_all_accessible=True,
+            )
+            snuba_params.projects = all_projects
+            params["projects"] = snuba_params.projects
+            params["projects_objects"] = snuba_params.projects
+            params["projects_id"] = snuba_params.project_ids
+
             trace_condition = f"trace:[{', '.join(spans_by_trace.keys())}]"
 
             with handle_query_errors():

+ 53 - 14
tests/sentry/api/endpoints/test_organization_traces.py

@@ -16,13 +16,25 @@ class OrganizationTracesEndpointTest(BaseSpansTestCase, APITestCase):
         super().setUp()
         self.login_as(user=self.user)
 
-    def do_request(self, query, **kwargs):
-        return self.client.get(
-            reverse(self.view, kwargs={"organization_slug": self.organization.slug}),
-            query,
-            format="json",
-            **kwargs,
-        )
+    def do_request(self, query, features=None, **kwargs):
+        if features is None:
+            features = ["organizations:performance-trace-explorer"]
+        with self.feature(features):
+            return self.client.get(
+                reverse(self.view, kwargs={"organization_slug": self.organization.slug}),
+                query,
+                format="json",
+                **kwargs,
+            )
+
+    def test_no_feature(self):
+        query = {
+            "field": ["id"],
+            "project": [self.project.id],
+        }
+
+        response = self.do_request(query, features=[])
+        assert response.status_code == 404, response.data
 
     def test_no_project(self):
         query = {
@@ -131,6 +143,9 @@ class OrganizationTracesEndpointTest(BaseSpansTestCase, APITestCase):
         }
 
     def test_matching_tag(self):
+        project_1 = self.create_project()
+        project_2 = self.create_project()
+
         # Hack: ensure that no span ids with leading 0s are generated for the test
         span_ids = ["1" + uuid4().hex[:15] for _ in range(7)]
         timestamps = []
@@ -138,7 +153,7 @@ class OrganizationTracesEndpointTest(BaseSpansTestCase, APITestCase):
         trace_id_1 = uuid4().hex
         timestamps.append(before_now(days=0, minutes=10).replace(microsecond=0))
         self.store_segment(
-            self.project.id,
+            project_1.id,
             trace_id_1,
             uuid4().hex,
             span_id=span_ids[0],
@@ -150,7 +165,7 @@ class OrganizationTracesEndpointTest(BaseSpansTestCase, APITestCase):
         for idx, i in enumerate(range(1, 4)):
             timestamps.append(before_now(days=0, minutes=9, seconds=45 - i).replace(microsecond=0))
             self.store_segment(
-                self.project.id,
+                project_2.id,
                 trace_id_1,
                 uuid4().hex,
                 span_id=span_ids[i],
@@ -165,7 +180,7 @@ class OrganizationTracesEndpointTest(BaseSpansTestCase, APITestCase):
         trace_id_2 = uuid4().hex
         timestamps.append(before_now(days=0, minutes=20).replace(microsecond=0))
         self.store_segment(
-            self.project.id,
+            project_1.id,
             trace_id_2,
             uuid4().hex,
             span_id=span_ids[4],
@@ -177,7 +192,7 @@ class OrganizationTracesEndpointTest(BaseSpansTestCase, APITestCase):
         for i in range(5, 7):
             timestamps.append(before_now(days=0, minutes=19, seconds=55 - i).replace(microsecond=0))
             self.store_segment(
-                self.project.id,
+                project_2.id,
                 trace_id_2,
                 uuid4().hex,
                 span_id=span_ids[i],
@@ -190,7 +205,7 @@ class OrganizationTracesEndpointTest(BaseSpansTestCase, APITestCase):
             )
 
         query = {
-            "project": [self.project.id],
+            "project": [project_2.id],
             "field": ["id", "parent_span"],
             "query": "foo:bar",
             "maxSpansPerTrace": 2,
@@ -230,8 +245,20 @@ class OrganizationTracesEndpointTest(BaseSpansTestCase, APITestCase):
                     "end": int(timestamps[0].timestamp() * 1000) + 60_100,
                     "breakdowns": [
                         {
-                            "project": self.project.slug,
+                            "project": project_1.slug,
                             "start": int(timestamps[0].timestamp() * 1000),
+                            "end": int(timestamps[1].timestamp() * 1000),
+                            "kind": "project",
+                        },
+                        {
+                            "project": project_2.slug,
+                            "start": int(timestamps[1].timestamp() * 1000),
+                            "end": int(timestamps[3].timestamp() * 1000) + 30_000,
+                            "kind": "project",
+                        },
+                        {
+                            "project": project_1.slug,
+                            "start": int(timestamps[3].timestamp() * 1000) + 30_000,
                             "end": int(timestamps[0].timestamp() * 1000) + 60_100,
                             "kind": "project",
                         },
@@ -254,8 +281,20 @@ class OrganizationTracesEndpointTest(BaseSpansTestCase, APITestCase):
                     "end": int(timestamps[4].timestamp() * 1000) + 90_123,
                     "breakdowns": [
                         {
-                            "project": self.project.slug,
+                            "project": project_1.slug,
                             "start": int(timestamps[4].timestamp() * 1000),
+                            "end": int(timestamps[5].timestamp() * 1000),
+                            "kind": "project",
+                        },
+                        {
+                            "project": project_2.slug,
+                            "start": int(timestamps[5].timestamp() * 1000),
+                            "end": int(timestamps[6].timestamp() * 1000) + 20_000,
+                            "kind": "project",
+                        },
+                        {
+                            "project": project_1.slug,
+                            "start": int(timestamps[6].timestamp() * 1000) + 20_000,
                             "end": int(timestamps[4].timestamp() * 1000) + 90_123,
                             "kind": "project",
                         },