Skip to content

Commit 96c8ab7

Browse files
authored
feat(features) Add metrics to feature flag decisions (#68554)
I'd like to get baseline data for the current duration of feature flag checks and success ratios. In the future I'd like to have alerting on feature flags that are always on for extended periods of time. I've set the sample rate to 1% to keep overhead low as feature flags are a high throughput code path. Refs HC-848
1 parent d57dd04 commit 96c8ab7

File tree

1 file changed

+38
-13
lines changed

1 file changed

+38
-13
lines changed

src/sentry/features/manager.py

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import sentry_sdk
1313
from django.conf import settings
1414

15+
from sentry.utils import metrics
16+
1517
from .base import Feature, FeatureHandlerStrategy
1618
from .exceptions import FeatureNotRegistered
1719

@@ -210,26 +212,49 @@ def has(self, name: str, *args: Any, skip_entity: bool | None = False, **kwargs:
210212
>>> FeatureManager.has('organizations:feature', organization, actor=request.user)
211213
212214
"""
215+
sample_rate = 0.01
213216
try:
214-
actor = kwargs.pop("actor", None)
215-
feature = self.get(name, *args, **kwargs)
217+
with metrics.timer("features.has", tags={"name": name}, sample_rate=sample_rate):
218+
actor = kwargs.pop("actor", None)
219+
feature = self.get(name, *args, **kwargs)
216220

217-
# Check registered feature handlers
218-
rv = self._get_handler(feature, actor)
219-
if rv is not None:
220-
return rv
221+
# Check registered feature handlers
222+
rv = self._get_handler(feature, actor)
223+
if rv is not None:
224+
metrics.incr(
225+
"feature.has.result",
226+
tags={"name": name, "result": rv},
227+
sample_rate=sample_rate,
228+
)
229+
return rv
221230

222-
if self._entity_handler and not skip_entity:
223-
rv = self._entity_handler.has(feature, actor)
231+
if self._entity_handler and not skip_entity:
232+
rv = self._entity_handler.has(feature, actor)
233+
if rv is not None:
234+
metrics.incr(
235+
"feature.has.result",
236+
tags={"name": name, "result": rv},
237+
sample_rate=sample_rate,
238+
)
239+
return rv
240+
241+
rv = settings.SENTRY_FEATURES.get(feature.name, False)
224242
if rv is not None:
243+
metrics.incr(
244+
"feature.has.result",
245+
tags={"name": name, "result": rv},
246+
sample_rate=sample_rate,
247+
)
225248
return rv
226249

227-
rv = settings.SENTRY_FEATURES.get(feature.name, False)
228-
if rv is not None:
229-
return rv
250+
# Features are by default disabled if no plugin or default enables them
251+
metrics.incr(
252+
"feature.has.result",
253+
tags={"name": name, "result": False},
254+
sample_rate=sample_rate,
255+
)
230256

231-
# Features are by default disabled if no plugin or default enables them
232-
return False
257+
return False
233258
except Exception:
234259
logging.exception("Failed to run feature check")
235260
return False

0 commit comments

Comments
 (0)