From a1ab33901dd0b43ac9ce9302c84fce76ca0ba3be Mon Sep 17 00:00:00 2001 From: Ivana Kellyerova Date: Wed, 10 Apr 2024 13:22:23 +0200 Subject: [PATCH] feat(metrics): Add value, unit to before_emit_metric (#2958) --- sentry_sdk/consts.py | 6 +++++- sentry_sdk/metrics.py | 31 ++++++++++++++++++++++--------- tests/test_metrics.py | 7 +++++-- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index b25a63840f..8e2bd00d38 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -24,10 +24,12 @@ Event, EventProcessor, Hint, + MeasurementUnit, ProfilerMode, TracesSampler, TransactionProcessor, MetricTags, + MetricValue, ) # Experiments are feature flags to enable and disable certain unstable SDK @@ -47,7 +49,9 @@ "transport_zlib_compression_level": Optional[int], "transport_num_pools": Optional[int], "enable_metrics": Optional[bool], - "before_emit_metric": Optional[Callable[[str, MetricTags], bool]], + "before_emit_metric": Optional[ + Callable[[str, MetricValue, MeasurementUnit, MetricTags], bool] + ], "metric_code_locations": Optional[bool], }, total=False, diff --git a/sentry_sdk/metrics.py b/sentry_sdk/metrics.py index f021f8031a..57f44e6533 100644 --- a/sentry_sdk/metrics.py +++ b/sentry_sdk/metrics.py @@ -703,8 +703,8 @@ def _get_aggregator(): ) -def _get_aggregator_and_update_tags(key, tags): - # type: (str, Optional[MetricTags]) -> Tuple[Optional[MetricsAggregator], Optional[LocalAggregator], Optional[MetricTags]] +def _get_aggregator_and_update_tags(key, value, unit, tags): + # type: (str, Optional[MetricValue], MeasurementUnit, Optional[MetricTags]) -> Tuple[Optional[MetricsAggregator], Optional[LocalAggregator], Optional[MetricTags]] hub = sentry_sdk.Hub.current client = hub.client if client is None or client.metrics_aggregator is None: @@ -732,7 +732,7 @@ def _get_aggregator_and_update_tags(key, tags): if before_emit_callback is not None: with recursion_protection() as in_metrics: if not in_metrics: - if not before_emit_callback(key, updated_tags): + if not before_emit_callback(key, value, unit, updated_tags): return None, None, updated_tags return client.metrics_aggregator, local_aggregator, updated_tags @@ -748,7 +748,9 @@ def increment( ): # type: (...) -> None """Increments a counter.""" - aggregator, local_aggregator, tags = _get_aggregator_and_update_tags(key, tags) + aggregator, local_aggregator, tags = _get_aggregator_and_update_tags( + key, value, unit, tags + ) if aggregator is not None: aggregator.add( "c", key, value, unit, tags, timestamp, local_aggregator, stacklevel @@ -809,7 +811,10 @@ def __exit__(self, exc_type, exc_value, tb): # type: (Any, Any, Any) -> None assert self._span, "did not enter" aggregator, local_aggregator, tags = _get_aggregator_and_update_tags( - self.key, self.tags + self.key, + self.value, + self.unit, + self.tags, ) if aggregator is not None: elapsed = TIMING_FUNCTIONS[self.unit]() - self.entered # type: ignore @@ -864,7 +869,9 @@ def timing( - it can be used as a decorator """ if value is not None: - aggregator, local_aggregator, tags = _get_aggregator_and_update_tags(key, tags) + aggregator, local_aggregator, tags = _get_aggregator_and_update_tags( + key, value, unit, tags + ) if aggregator is not None: aggregator.add( "d", key, value, unit, tags, timestamp, local_aggregator, stacklevel @@ -882,7 +889,9 @@ def distribution( ): # type: (...) -> None """Emits a distribution.""" - aggregator, local_aggregator, tags = _get_aggregator_and_update_tags(key, tags) + aggregator, local_aggregator, tags = _get_aggregator_and_update_tags( + key, value, unit, tags + ) if aggregator is not None: aggregator.add( "d", key, value, unit, tags, timestamp, local_aggregator, stacklevel @@ -899,7 +908,9 @@ def set( ): # type: (...) -> None """Emits a set.""" - aggregator, local_aggregator, tags = _get_aggregator_and_update_tags(key, tags) + aggregator, local_aggregator, tags = _get_aggregator_and_update_tags( + key, value, unit, tags + ) if aggregator is not None: aggregator.add( "s", key, value, unit, tags, timestamp, local_aggregator, stacklevel @@ -916,7 +927,9 @@ def gauge( ): # type: (...) -> None """Emits a gauge.""" - aggregator, local_aggregator, tags = _get_aggregator_and_update_tags(key, tags) + aggregator, local_aggregator, tags = _get_aggregator_and_update_tags( + key, value, unit, tags + ) if aggregator is not None: aggregator.add( "g", key, value, unit, tags, timestamp, local_aggregator, stacklevel diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 5f2278d0a0..48b4436df0 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -734,9 +734,10 @@ def test_tag_normalization( def test_before_emit_metric( sentry_init, capture_envelopes, maybe_monkeypatched_threading ): - def before_emit(key, tags): - if key == "removed-metric": + def before_emit(key, value, unit, tags): + if key == "removed-metric" or value == 47 or unit == "unsupported": return False + tags["extra"] = "foo" del tags["release"] # this better be a noop! @@ -755,6 +756,8 @@ def before_emit(key, tags): envelopes = capture_envelopes() metrics.increment("removed-metric", 1.0) + metrics.increment("another-removed-metric", 47) + metrics.increment("yet-another-removed-metric", 1.0, unit="unsupported") metrics.increment("actual-metric", 1.0) Hub.current.flush()