Skip to content

Commit a1371c0

Browse files
authored
Replace the precise metrics flag with a dedicated backend (#97749)
This reverts all the changes related to the `precise` flag, and having two different metrics backends. Instead, it adds a new `PreciseDogStatsd` backend. The difference to the normal `DogStatsd` backend is that it constructs a instance-local `DogStatsd` client, instead of messing with the global `statsd` singleton. And of course, it emits distributions and timings as the proper datadog `distribution` type.
1 parent f81814e commit a1371c0

File tree

15 files changed

+173
-107
lines changed

15 files changed

+173
-107
lines changed

src/sentry/conf/server.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,8 +2206,6 @@ def custom_parameter_sort(parameter: dict) -> tuple[str, int]:
22062206
# Internal metrics
22072207
SENTRY_METRICS_BACKEND = "sentry.metrics.dummy.DummyMetricsBackend"
22082208
SENTRY_METRICS_OPTIONS: dict[str, Any] = {}
2209-
SENTRY_METRICS_PRECISE_BACKEND: str | None = None
2210-
SENTRY_METRICS_PRECISE_OPTIONS: dict[str, Any] = {}
22112209
SENTRY_METRICS_SAMPLE_RATE = 1.0
22122210
SENTRY_METRICS_PREFIX = "sentry."
22132211
SENTRY_METRICS_SKIP_INTERNAL_PREFIXES: list[str] = [] # Order this by most frequent prefixes.

src/sentry/metrics/base.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ def distribution(
7676
sample_rate: float = 1,
7777
unit: str | None = None,
7878
stacklevel: int = 0,
79-
precise: bool = False,
8079
) -> None:
8180
raise NotImplementedError
8281

src/sentry/metrics/datadog.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -108,23 +108,9 @@ def distribution(
108108
sample_rate: float = 1,
109109
unit: str | None = None,
110110
stacklevel: int = 0,
111-
precise: bool = False,
112111
) -> None:
113-
if not precise:
114-
# We keep the same implementation for Datadog.
115-
return self.timing(key, value, instance, tags, sample_rate)
116-
117-
tags = dict(tags or ())
118-
119-
if self.tags:
120-
tags.update(self.tags)
121-
if instance:
122-
tags["instance"] = instance
123-
124-
tags_list = [f"{k}:{v}" for k, v in tags.items()]
125-
self.stats.distribution(
126-
self._get_key(key), value, sample_rate=sample_rate, tags=tags_list, host=self.host
127-
)
112+
# We keep the same implementation for Datadog.
113+
return self.timing(key, value, instance, tags, sample_rate)
128114

129115
def event(
130116
self,

src/sentry/metrics/dogstatsd.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -110,21 +110,9 @@ def distribution(
110110
sample_rate: float = 1,
111111
unit: str | None = None,
112112
stacklevel: int = 0,
113-
precise: bool = False,
114113
) -> None:
115-
if not precise:
116-
# We keep the same implementation for Datadog.
117-
return self.timing(key, value, instance, tags, sample_rate)
118-
119-
tags = dict(tags or ())
120-
121-
if self.tags:
122-
tags.update(self.tags)
123-
if instance:
124-
tags["instance"] = instance
125-
126-
tags_list = [f"{k}:{v}" for k, v in tags.items()]
127-
statsd.distribution(self._get_key(key), value, sample_rate=sample_rate, tags=tags_list)
114+
# We keep the same implementation for Datadog.
115+
return self.timing(key, value, instance, tags, sample_rate)
128116

129117
def event(
130118
self,

src/sentry/metrics/dummy.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ def distribution(
4848
sample_rate: float = 1,
4949
unit: str | None = None,
5050
stacklevel: int = 0,
51-
precise: bool = False,
5251
) -> None:
5352
pass
5453

src/sentry/metrics/logging.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ def distribution(
5252
sample_rate: float = 1,
5353
unit: str | None = None,
5454
stacklevel: int = 0,
55-
precise: bool = False,
5655
) -> None:
5756
logger.debug("%r: %+g", key, value, extra={"instance": instance, "tags": tags or {}})
5857

src/sentry/metrics/middleware.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,15 +180,14 @@ def distribution(
180180
sample_rate: float = 1,
181181
unit: str | None = None,
182182
stacklevel: int = 0,
183-
precise: bool = False,
184183
) -> None:
185184
current_tags = get_current_global_tags()
186185
if tags is not None:
187186
current_tags.update(tags)
188187
current_tags = _filter_tags(key, current_tags)
189188

190189
return self.inner.distribution(
191-
key, value, instance, current_tags, sample_rate, unit, stacklevel + 1, precise
190+
key, value, instance, current_tags, sample_rate, unit, stacklevel + 1
192191
)
193192

194193
def event(
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import atexit
2+
from typing import Any
3+
4+
from datadog.dogstatsd.base import DogStatsd
5+
6+
from .base import MetricsBackend, Tags
7+
8+
__all__ = ["PreciseDogStatsdMetricsBackend"]
9+
10+
11+
class PreciseDogStatsdMetricsBackend(MetricsBackend):
12+
def __init__(self, prefix: str | None = None, **kwargs: Any) -> None:
13+
self.tags = kwargs.pop("tags", None)
14+
15+
instance_kwargs: dict[str, Any] = {
16+
"disable_telemetry": True,
17+
"disable_buffering": False,
18+
# When enabled, a background thread will be used to send metric payloads to the Agent.
19+
"disable_background_sender": False,
20+
}
21+
if socket_path := kwargs.get("statsd_socket_path"):
22+
instance_kwargs["socket_path"] = socket_path
23+
else:
24+
if host := kwargs.get("statsd_host"):
25+
instance_kwargs["host"] = host
26+
if port := kwargs.get("statsd_port"):
27+
instance_kwargs["port"] = int(port)
28+
29+
self.statsd = DogStatsd(**instance_kwargs)
30+
31+
# Origin detection is enabled after 0.45 by default.
32+
# Disable it since it silently fails.
33+
# Ref: https://github.com/DataDog/datadogpy/issues/764
34+
self.statsd._container_id = None
35+
36+
# Applications should call wait_for_pending() before exiting to make sure all pending payloads are sent.
37+
atexit.register(self.statsd.wait_for_pending)
38+
39+
super().__init__(prefix=prefix)
40+
41+
def incr(
42+
self,
43+
key: str,
44+
instance: str | None = None,
45+
tags: Tags | None = None,
46+
amount: float | int = 1,
47+
sample_rate: float = 1,
48+
unit: str | None = None,
49+
stacklevel: int = 0,
50+
) -> None:
51+
tags = dict(tags or ())
52+
53+
if self.tags:
54+
tags.update(self.tags)
55+
if instance:
56+
tags["instance"] = instance
57+
58+
tags_list = [f"{k}:{v}" for k, v in tags.items()]
59+
self.statsd.increment(self._get_key(key), amount, sample_rate=sample_rate, tags=tags_list)
60+
61+
def timing(
62+
self,
63+
key: str,
64+
value: float,
65+
instance: str | None = None,
66+
tags: Tags | None = None,
67+
sample_rate: float = 1,
68+
stacklevel: int = 0,
69+
) -> None:
70+
tags = dict(tags or ())
71+
72+
if self.tags:
73+
tags.update(self.tags)
74+
if instance:
75+
tags["instance"] = instance
76+
77+
tags_list = [f"{k}:{v}" for k, v in tags.items()]
78+
self.statsd.distribution(self._get_key(key), value, sample_rate=sample_rate, tags=tags_list)
79+
80+
def gauge(
81+
self,
82+
key: str,
83+
value: float,
84+
instance: str | None = None,
85+
tags: Tags | None = None,
86+
sample_rate: float = 1,
87+
unit: str | None = None,
88+
stacklevel: int = 0,
89+
) -> None:
90+
tags = dict(tags or ())
91+
92+
if self.tags:
93+
tags.update(self.tags)
94+
if instance:
95+
tags["instance"] = instance
96+
97+
tags_list = [f"{k}:{v}" for k, v in tags.items()]
98+
self.statsd.gauge(self._get_key(key), value, sample_rate=sample_rate, tags=tags_list)
99+
100+
def distribution(
101+
self,
102+
key: str,
103+
value: float,
104+
instance: str | None = None,
105+
tags: Tags | None = None,
106+
sample_rate: float = 1,
107+
unit: str | None = None,
108+
stacklevel: int = 0,
109+
) -> None:
110+
tags = dict(tags or ())
111+
112+
if self.tags:
113+
tags.update(self.tags)
114+
if instance:
115+
tags["instance"] = instance
116+
117+
tags_list = [f"{k}:{v}" for k, v in tags.items()]
118+
self.statsd.distribution(self._get_key(key), value, sample_rate=sample_rate, tags=tags_list)
119+
120+
def event(
121+
self,
122+
title: str,
123+
message: str,
124+
alert_type: str | None = None,
125+
aggregation_key: str | None = None,
126+
source_type_name: str | None = None,
127+
priority: str | None = None,
128+
instance: str | None = None,
129+
tags: Tags | None = None,
130+
stacklevel: int = 0,
131+
) -> None:
132+
tags = dict(tags or ())
133+
134+
if self.tags:
135+
tags.update(self.tags)
136+
if instance:
137+
tags["instance"] = instance
138+
139+
tags_list = [f"{k}:{v}" for k, v in tags.items()]
140+
self.statsd.event(
141+
title=title,
142+
message=message,
143+
alert_type=alert_type,
144+
aggregation_key=aggregation_key,
145+
source_type_name=source_type_name,
146+
priority=priority,
147+
tags=tags_list,
148+
hostname=self.host,
149+
)

src/sentry/metrics/statsd.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ def distribution(
6161
sample_rate: float = 1,
6262
unit: str | None = None,
6363
stacklevel: int = 0,
64-
precise: bool = False,
6564
) -> None:
6665
# NOTE: the statsd client does not have a `distribution` method
6766
self.timing(key, value, instance, tags, sample_rate)

src/sentry/models/debugfile.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,6 @@ def create_dif_from_id(
323323
file.size,
324324
tags={"usecase": "debug-files", "compression": "none"},
325325
unit="byte",
326-
precise=True,
327326
)
328327

329328
dif = ProjectDebugFile.objects.create(

0 commit comments

Comments
 (0)