Browse Source

fix(custom-measurements): Update custom measurement logic (#36066)

- This updates the lgoic that determines if a mri represents a custom
  measurements to instead of checking for a custom namespace, that its a
  transaction MRI, but one that isn't in the hardcoded list in
  TransactionMRI
William Mak 2 years ago
parent
commit
546e692a86

+ 16 - 1
src/sentry/snuba/metrics/naming_layer/mri.py

@@ -113,6 +113,10 @@ class ParsedMRI:
     name: str
     unit: str
 
+    @property
+    def mri_string(self) -> str:
+        return f"{self.entity}:{self.namespace}/{self.name}@{self.unit}"
+
 
 def parse_mri(mri_string: str) -> Optional[ParsedMRI]:
     """Parse a mri string to determine its entity, namespace, name and unit"""
@@ -124,4 +128,15 @@ def parse_mri(mri_string: str) -> Optional[ParsedMRI]:
 
 
 def is_custom_measurement(parsed_mri: ParsedMRI) -> bool:
-    return parsed_mri.namespace == "custom"
+    """A custom measurement won't use the custom namespace, but will be under the transaction namespace
+
+    This checks the namespace, and name to match what we expect first before iterating through the
+    members of the transaction MRI enum to make sure it isn't a standard measurement
+    """
+    return (
+        parsed_mri.namespace == "transactions"
+        and parsed_mri.name.startswith("measurements.")
+        and
+        # Iterate through the transaction MRI and check that this parsed_mri isn't in there
+        parsed_mri.mri_string not in [mri.value for mri in TransactionMRI.__members__.values()]
+    )

+ 4 - 4
tests/sentry/snuba/metrics/test_datasource.py

@@ -84,8 +84,8 @@ class DataSourceTestCase(TestCase, SessionMetricsTestCase):
 
 class GetCustomMeasurementsTest(MetricsEnhancedPerformanceTestCase):
     METRIC_STRINGS = [
-        "d:custom/measurements.something_custom@millisecond",
-        "d:custom/measurements.something_else@byte",
+        "d:transactions/measurements.something_custom@millisecond",
+        "d:transactions/measurements.something_else@byte",
     ]
 
     def setUp(self):
@@ -96,7 +96,7 @@ class GetCustomMeasurementsTest(MetricsEnhancedPerformanceTestCase):
         self.store_metric(
             1,
             metric="measurements.something_custom",
-            internal_metric="d:custom/measurements.something_custom@millisecond",
+            internal_metric="d:transactions/measurements.something_custom@millisecond",
             entity="metrics_distributions",
             timestamp=self.day_ago + timedelta(hours=1, minutes=0),
         )
@@ -127,7 +127,7 @@ class GetCustomMeasurementsTest(MetricsEnhancedPerformanceTestCase):
         self.store_metric(
             1,
             metric="measurements.something_custom",
-            internal_metric="d:custom/measurements.something_custom@millisecond",
+            internal_metric="d:transactions/measurements.something_custom@millisecond",
             entity="metrics_distributions",
             timestamp=self.day_ago + timedelta(hours=1, minutes=0),
         )

+ 34 - 2
tests/sentry/snuba/metrics/test_naming_layer.py

@@ -2,7 +2,12 @@ import re
 
 import pytest
 
-from sentry.snuba.metrics.naming_layer.mri import MRI_SCHEMA_REGEX, ParsedMRI, parse_mri
+from sentry.snuba.metrics.naming_layer.mri import (
+    MRI_SCHEMA_REGEX,
+    ParsedMRI,
+    is_custom_measurement,
+    parse_mri,
+)
 from sentry.snuba.metrics.naming_layer.public import PUBLIC_NAME_REGEX
 
 
@@ -107,4 +112,31 @@ def test_invalid_mri_schema_regex(name):
     ],
 )
 def test_parse_mri(name, expected):
-    assert parse_mri(name) == expected
+    parsed_mri = parse_mri(name)
+    assert parsed_mri == expected
+    assert parsed_mri.mri_string == name
+
+
+@pytest.mark.parametrize(
+    "parsed_mri, expected",
+    [
+        (
+            ParsedMRI("d", "transactions", "measurements.stall_longest_time", "millisecond"),
+            False,
+        ),
+        (
+            ParsedMRI("d", "transactions", "breakdowns.span_ops.http", "millisecond"),
+            False,
+        ),
+        (
+            ParsedMRI("c", "transactions", "measurements.db_calls", "none"),
+            True,
+        ),
+        (
+            ParsedMRI("s", "sessions", "error", "none"),
+            False,
+        ),
+    ],
+)
+def test_is_custom_measurement(parsed_mri, expected):
+    assert is_custom_measurement(parsed_mri) == expected

+ 3 - 3
tests/snuba/api/endpoints/test_organization_measurements_meta.py

@@ -9,7 +9,7 @@ from sentry.testutils.helpers.datetime import before_now
 class OrganizationMeasurementsMetaEndpoint(MetricsEnhancedPerformanceTestCase):
     endpoint = "sentry-api-0-organization-measurements-meta"
     METRIC_STRINGS = [
-        "d:custom/measurements.something_custom@millisecond",
+        "d:transactions/measurements.something_custom@millisecond",
     ]
 
     def setUp(self):
@@ -33,7 +33,7 @@ class OrganizationMeasurementsMetaEndpoint(MetricsEnhancedPerformanceTestCase):
         self.store_metric(
             1,
             metric="measurements.something_custom",
-            internal_metric="d:custom/measurements.something_custom@millisecond",
+            internal_metric="d:transactions/measurements.something_custom@millisecond",
             entity="metrics_distributions",
             timestamp=self.day_ago + timedelta(hours=1, minutes=0),
         )
@@ -67,7 +67,7 @@ class OrganizationMeasurementsMetaEndpoint(MetricsEnhancedPerformanceTestCase):
         self.store_metric(
             1,
             metric="measurements.something_custom",
-            internal_metric="d:custom/measurements.something_custom@millisecond",
+            internal_metric="d:transactions/measurements.something_custom@millisecond",
             entity="metrics_distributions",
             timestamp=self.day_ago - timedelta(days=15, minutes=0),
         )