Skip to content

Commit ccd994d

Browse files
authored
chore(nimbus): add statsd metrics for user interaction counts and review timing (#13412)
Because - We want more visibility into experimenter activity This commit - Adds a count metric for every nimbus ui interaction that generates a changelog - Adds a timing metric for how long it takes experiments to be reviewed Fixes #13409
1 parent edb5bd3 commit ccd994d

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

experimenter/experimenter/nimbus_ui/forms.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from collections import defaultdict
2+
from datetime import UTC, datetime
23

4+
import markus
35
from django import forms
46
from django.contrib.auth.models import User
57
from django.forms import inlineformset_factory
@@ -30,6 +32,8 @@
3032
from experimenter.segments import Segments
3133
from experimenter.targeting.constants import NimbusTargetingConfig
3234

35+
metrics = markus.get_metrics("experimenter.nimbus_ui_forms")
36+
3337

3438
class NimbusChangeLogFormMixin:
3539
def __init__(self, *args, request: HttpRequest = None, **kwargs):
@@ -44,6 +48,7 @@ def save(self, *args, **kwargs):
4448
generate_nimbus_changelog(
4549
experiment, self.request.user, self.get_changelog_message()
4650
)
51+
metrics.incr("changelog_form.save", tags=[f"form:{type(self).__name__}"])
4752
return experiment
4853

4954

@@ -1209,6 +1214,7 @@ class Meta:
12091214
def save(self, commit=True):
12101215
self.instance.status = self.status
12111216
self.instance.status_next = self.status_next
1217+
previous_publish_status = self.instance.publish_status
12121218
self.instance.publish_status = self.publish_status
12131219

12141220
if self.is_paused is not None:
@@ -1217,6 +1223,20 @@ def save(self, commit=True):
12171223
if self.status == NimbusExperiment.Status.DRAFT:
12181224
self.instance.published_dto = None
12191225

1226+
if (
1227+
previous_publish_status == NimbusExperiment.PublishStatus.REVIEW
1228+
and self.publish_status != NimbusExperiment.PublishStatus.REVIEW
1229+
):
1230+
last_review_request = self.instance.changes.latest_review_request()
1231+
if last_review_request is not None:
1232+
delta = datetime.now(UTC) - last_review_request.changed_on
1233+
delta_ms = int(delta.total_seconds() * 1000)
1234+
metrics.timing(
1235+
"review_timing",
1236+
value=delta_ms,
1237+
tags=[f"status:{self.publish_status}"],
1238+
)
1239+
12201240
return super().save(commit=commit)
12211241

12221242

experimenter/experimenter/nimbus_ui/tests/test_forms.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,29 @@ def test_review_to_approve_form(self):
845845
)
846846
self.mock_allocate_bucket_range.assert_called_once()
847847

848+
def test_review_timing_metric(self):
849+
data = {
850+
"owner": self.user,
851+
"name": "Test Experiment",
852+
"hypothesis": "test hypothesis",
853+
"application": NimbusExperiment.Application.DESKTOP,
854+
}
855+
form = NimbusExperimentCreateForm(data, request=self.request)
856+
self.assertTrue(form.is_valid(), form.errors)
857+
experiment = form.save()
858+
859+
form = DraftToReviewForm(data={}, instance=experiment, request=self.request)
860+
self.assertTrue(form.is_valid(), form.errors)
861+
experiment = form.save()
862+
863+
form = ReviewToApproveForm(data={}, instance=experiment, request=self.request)
864+
self.assertTrue(form.is_valid(), form.errors)
865+
866+
with patch("experimenter.nimbus_ui.forms.metrics") as mock_metrics:
867+
experiment = form.save()
868+
869+
mock_metrics.timing.assert_called_once()
870+
848871
def test_live_to_end_enrollment_form(self):
849872
experiment = NimbusExperimentFactory.create(
850873
status=NimbusExperiment.Status.LIVE,

0 commit comments

Comments
 (0)