Skip to content

Commit 1af5d93

Browse files
authored
feat(tracemetrics): Try out sample rate and timing (#102587)
### Summary This adds sample rate code and allows 'timing' to be sent (as a gauge, but for us it doesn't matter functionally).
1 parent b01e2ba commit 1af5d93

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

src/sentry/metrics/sentry_sdk.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ def incr(
4747
if instance:
4848
metric_attributes["instance"] = instance
4949

50+
if sample_rate != 1.0:
51+
metric_attributes["sentry.client_sample_rate"] = sample_rate
52+
5053
metrics.count(
5154
full_key,
5255
amount,
@@ -63,7 +66,29 @@ def timing(
6366
sample_rate: float = 1,
6467
stacklevel: int = 0,
6568
) -> None:
66-
pass
69+
70+
full_key = self._get_key(key)
71+
if not self._should_send(full_key):
72+
return
73+
74+
if not self._should_sample(sample_rate):
75+
return
76+
77+
metric_attributes = dict(tags) if tags else {}
78+
if instance:
79+
metric_attributes["instance"] = instance
80+
81+
if sample_rate != 1.0:
82+
metric_attributes["sentry.client_sample_rate"] = sample_rate
83+
84+
metric_attributes["is_timing"] = True
85+
86+
metrics.distribution(
87+
full_key,
88+
value,
89+
unit="millisecond",
90+
attributes=metric_attributes,
91+
)
6792

6893
def gauge(
6994
self,
@@ -86,6 +111,9 @@ def gauge(
86111
if instance:
87112
metric_attributes["instance"] = instance
88113

114+
if sample_rate != 1.0:
115+
metric_attributes["sentry.client_sample_rate"] = sample_rate
116+
89117
metrics.gauge(
90118
full_key,
91119
value,
@@ -114,6 +142,9 @@ def distribution(
114142
if instance:
115143
metric_attributes["instance"] = instance
116144

145+
if sample_rate != 1.0:
146+
metric_attributes["sentry.client_sample_rate"] = sample_rate
147+
117148
metrics.distribution(
118149
full_key,
119150
value,

tests/sentry/metrics/test_sentry_sdk.py

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,17 @@ def test_incr_with_instance(self, mock_count, backend):
7070
attributes={"x": "y", "instance": "web"},
7171
)
7272

73-
def test_timing_noop(self, backend):
74-
backend.timing("foo", 42.0)
73+
@mock.patch("sentry_sdk.metrics.distribution")
74+
def test_timing(self, mock_distribution, backend):
75+
with mock.patch.object(backend, "_should_send", return_value=True):
76+
backend.timing("foo", 42.0, tags={"x": "y"})
77+
78+
mock_distribution.assert_called_once_with(
79+
"test.foo",
80+
42.0,
81+
unit="millisecond",
82+
attributes={"x": "y", "is_timing": True},
83+
)
7584

7685
def test_event_noop(self, backend):
7786
backend.event("title", "message")
@@ -92,3 +101,65 @@ def test_incr_deny_list(self, mock_count):
92101

93102
backend.incr("allowed.metric", amount=1)
94103
mock_count.assert_called_once()
104+
105+
@mock.patch("sentry_sdk.metrics.count")
106+
def test_incr_with_sample_rate(self, mock_count, backend):
107+
with (
108+
mock.patch.object(backend, "_should_send", return_value=True),
109+
mock.patch.object(backend, "_should_sample", return_value=True),
110+
):
111+
backend.incr("foo", tags={"x": "y"}, amount=2, sample_rate=0.5)
112+
113+
mock_count.assert_called_once_with(
114+
"test.foo",
115+
2,
116+
unit=None,
117+
attributes={"x": "y", "sentry.client_sample_rate": 0.5},
118+
)
119+
120+
@mock.patch("sentry_sdk.metrics.gauge")
121+
def test_gauge_with_sample_rate(self, mock_gauge, backend):
122+
with (
123+
mock.patch.object(backend, "_should_send", return_value=True),
124+
mock.patch.object(backend, "_should_sample", return_value=True),
125+
):
126+
backend.gauge("bar", value=42.0, tags={"x": "y"}, sample_rate=0.25, unit="bytes")
127+
128+
mock_gauge.assert_called_once_with(
129+
"test.bar",
130+
42.0,
131+
unit="bytes",
132+
attributes={"x": "y", "sentry.client_sample_rate": 0.25},
133+
)
134+
135+
@mock.patch("sentry_sdk.metrics.distribution")
136+
def test_distribution_with_sample_rate(self, mock_distribution, backend):
137+
with (
138+
mock.patch.object(backend, "_should_send", return_value=True),
139+
mock.patch.object(backend, "_should_sample", return_value=True),
140+
):
141+
backend.distribution(
142+
"baz", value=100.0, tags={"x": "y"}, sample_rate=0.1, unit="millisecond"
143+
)
144+
145+
mock_distribution.assert_called_once_with(
146+
"test.baz",
147+
100.0,
148+
unit="millisecond",
149+
attributes={"x": "y", "sentry.client_sample_rate": 0.1},
150+
)
151+
152+
@mock.patch("sentry_sdk.metrics.distribution")
153+
def test_timing_with_sample_rate(self, mock_distribution, backend):
154+
with (
155+
mock.patch.object(backend, "_should_send", return_value=True),
156+
mock.patch.object(backend, "_should_sample", return_value=True),
157+
):
158+
backend.timing("foo", 42.0, tags={"x": "y"}, sample_rate=0.75)
159+
160+
mock_distribution.assert_called_once_with(
161+
"test.foo",
162+
42.0,
163+
unit="millisecond",
164+
attributes={"x": "y", "sentry.client_sample_rate": 0.75, "is_timing": True},
165+
)

0 commit comments

Comments
 (0)