Browse Source

chore(trace_view): Add perf issues to the mock trace (#45794)

- Only adding n+1 for now, but should be fairly easy to add other ones
in the future
William Mak 2 years ago
parent
commit
33a2b8b148
2 changed files with 105 additions and 0 deletions
  1. 41 0
      bin/mock-traces
  2. 64 0
      src/sentry/utils/samples.py

+ 41 - 0
bin/mock-traces

@@ -94,6 +94,47 @@ def main(slow=False):
         },
     )
 
+    print(f"    > Loading normal trace, but with performance issue")  # NOQA
+    # Normal trace
+    create_trace(
+        slow,
+        timestamp - timedelta(milliseconds=random_normal(4000, 250, 1000)),
+        timestamp,
+        generate_user(),
+        uuid4().hex,
+        None,
+        {
+            "project": frontend_project,
+            "transaction": "/plants/:plantId/",
+            "frontend": True,
+            "errors": 1,
+            "children": [
+                {
+                    "project": backend_project,
+                    "transaction": "/api/plants/",
+                    "performance_issues": ["n+1"],
+                    "children": [
+                        {
+                            "project": service_projects[0],
+                            "transaction": "/products/all/",
+                            "children": [],
+                        },
+                        {
+                            "project": service_projects[1],
+                            "transaction": "/analytics/",
+                            "children": [],
+                        },
+                        {
+                            "project": service_projects[2],
+                            "transaction": "tasks.create_invoice",
+                            "children": [],
+                        },
+                    ],
+                },
+            ],
+        },
+    )
+
     print(f"    > Loading orphan data")  # NOQA
     # Trace only with orphans
     create_trace(

+ 64 - 0
src/sentry/utils/samples.py

@@ -290,6 +290,64 @@ def load_data(
     return data
 
 
+def create_n_plus_one_issue(data):
+    timestamp = datetime.fromtimestamp(data["start_timestamp"])
+    n_plus_one_db_duration = timedelta(milliseconds=100)
+    n_plus_one_db_current_offset = timestamp
+    parent_span_id = data["spans"][0]["parent_span_id"]
+    trace_id = data["contexts"]["trace"]["trace_id"]
+    data["spans"].append(
+        {
+            "timestamp": (timestamp + n_plus_one_db_duration).timestamp(),
+            "start_timestamp": (timestamp + timedelta(milliseconds=10)).timestamp(),
+            "description": "SELECT `books_book`.`id`, `books_book`.`title`, `books_book`.`author_id` FROM `books_book` ORDER BY `books_book`.`id` DESC LIMIT 10",
+            "op": "db",
+            "parent_span_id": parent_span_id,
+            "span_id": uuid4().hex[:16],
+            "hash": "858fea692d4d93e8",
+            "trace_id": trace_id,
+        }
+    )
+    for i in range(200):
+        n_plus_one_db_duration += timedelta(milliseconds=200) + timedelta(milliseconds=1)
+        n_plus_one_db_current_offset = timestamp + n_plus_one_db_duration
+        data["spans"].append(
+            {
+                "timestamp": (
+                    n_plus_one_db_current_offset + timedelta(milliseconds=200)
+                ).timestamp(),
+                "start_timestamp": (
+                    n_plus_one_db_current_offset + timedelta(milliseconds=1)
+                ).timestamp(),
+                "description": "SELECT `books_author`.`id`, `books_author`.`name` FROM `books_author` WHERE `books_author`.`id` = %s LIMIT 21",
+                "op": "db",
+                "span_id": uuid4().hex[:16],
+                "parent_span_id": parent_span_id,
+                "hash": "63f1e89e6a073441",
+                "trace_id": trace_id,
+            }
+        )
+    data["spans"].append(
+        {
+            "timestamp": (
+                timestamp + n_plus_one_db_duration + timedelta(milliseconds=200)
+            ).timestamp(),
+            "start_timestamp": timestamp.timestamp(),
+            "description": "new",
+            "op": "django.view",
+            "parent_span_id": uuid4().hex[:16],
+            "span_id": parent_span_id,
+            "hash": "0f43fb6f6e01ca52",
+            "trace_id": trace_id,
+        }
+    )
+
+
+PERFORMANCE_ISSUE_CREATORS = {
+    "n+1": create_n_plus_one_issue,
+}
+
+
 def create_sample_event(
     project,
     platform=None,
@@ -302,6 +360,7 @@ def create_sample_event(
     span_id=None,
     spans=None,
     tagged=False,
+    performance_issues=None,
     **kwargs,
 ):
     if not platform and not default:
@@ -323,6 +382,10 @@ def create_sample_event(
     for key in ["parent_span_id", "hash", "exclusive_time"]:
         if key in kwargs:
             data["contexts"]["trace"][key] = kwargs.pop(key)
+    if performance_issues:
+        for issue in performance_issues:
+            if issue in PERFORMANCE_ISSUE_CREATORS:
+                PERFORMANCE_ISSUE_CREATORS[issue](data)
 
     data.update(kwargs)
     return create_sample_event_basic(data, project.id, raw=raw, tagged=tagged)
@@ -413,6 +476,7 @@ def create_trace(slow, start_timestamp, timestamp, user, trace_id, parent_span_i
         trace=trace_id,
         spans=spans,
         hash=hash_values([data["transaction"]]),
+        performance_issues=data.get("performance_issues"),
         # not the best but just set the exclusive time
         # equal to the duration to get some span data
         exclusive_time=(timestamp - start_timestamp).total_seconds(),