Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report app dependency addition/removal to DataDog #35455

Merged
merged 12 commits into from
Dec 10, 2024
24 changes: 24 additions & 0 deletions corehq/apps/app_manager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@
from corehq.blobs.mixin import CODES, BlobMixin
from corehq.const import USER_DATE_FORMAT, USER_TIME_FORMAT
from corehq.util import bitly, view_utils
from corehq.util.metrics import metrics_counter
from corehq.util.quickcache import quickcache
from corehq.util.timer import TimingContext, time_method
from corehq.util.timezones.conversions import ServerTime
Expand Down Expand Up @@ -4467,8 +4468,31 @@ def make_build(self, comment=None, user_id=None):
assert copy._id
prune_auto_generated_builds.delay(self.domain, self._id)

self.check_build_dependencies(new_build=copy)

return copy

def check_build_dependencies(self, new_build):
"""
Reports whether the app dependencies have been added or removed.
"""

def has_dependencies(build):
return bool(
build.profile.get('features', {}).get('dependencies')
)

new_build_has_dependencies = has_dependencies(new_build)

last_build = get_latest_build_doc(self.domain, self.id)
last_build = self.__class__.wrap(last_build) if last_build else None
last_build_has_dependencies = has_dependencies(last_build) if last_build else False

if not last_build_has_dependencies and new_build_has_dependencies:
metrics_counter('commcare.app_build.dependencies_added')
elif last_build_has_dependencies and not new_build_has_dependencies:
metrics_counter('commcare.app_build.dependencies_removed')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that we have simplified the approach here.

Wanted to check if this metric in itself would be useful? Don't we need the uptake as well?
I believe on datadog you can have a counter with both positive and negative values, so you get a graph with both additions and removals at once.
example here

Or we could report uptake separately, which seems easy enough to add now.

if (not latest_build or not has_dependencies(latest_build)) and has_dependencies(new_build):
    metrics_counter('commcare.app_build.dependencies_added')

I would vote for the single counter with both +/-

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe on datadog you can have a counter with both positive and negative values, so you get a graph with both additions and removals at once.

I'll check this out. Thanks for the suggestion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, these will show as two separate metrics right? not as one? or they can be combined if needed on the datadog UI?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mkangia They can be combined as needed on Data Dog.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great 👍


def convert_app_to_build(self, copy_of, user_id, comment=None):
self.copy_of = copy_of
built_on = datetime.datetime.utcnow()
Expand Down
45 changes: 45 additions & 0 deletions corehq/apps/app_manager/tests/test_apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,48 @@ def test_get_latest_enabled_build_with_loc_flag(self):
location_flag_enabled=True,
)
self.assertIsNone(build)

def test_dependencies_feature_added(self):
factory = AppFactory(build_version='2.40.0')
m0, f0 = factory.new_basic_module('register', 'case')
f0.source = get_simple_form(xmlns=f0.unique_id)
factory.app.profile = {'features': {'dependencies': ['coffee']}}
factory.app.save()
self.addCleanup(factory.app.delete)

with patch("corehq.apps.app_manager.models.metrics_counter") as metric_counter_mock:
factory.app.make_build()
metric_counter_mock.assert_called_with('commcare.app_build.dependencies_added')

def test_dependencies_feature_removed(self):
factory = AppFactory(build_version='2.40.0')
m0, f0 = factory.new_basic_module('register', 'case')
f0.source = get_simple_form(xmlns=f0.unique_id)
factory.app.profile = {'features': {'dependencies': ['coffee']}}
factory.app.save()
self.addCleanup(factory.app.delete)
build1 = factory.app.make_build()
build1.save()

factory.app.profile = {'features': {'dependencies': []}}
factory.app.save()

with patch("corehq.apps.app_manager.models.metrics_counter") as metric_counter_mock:
factory.app.make_build()
metric_counter_mock.assert_called_with('commcare.app_build.dependencies_removed')

def test_dependencies_feature_metrics_not_triggerd(self):
factory = AppFactory(build_version='2.40.0')
m0, f0 = factory.new_basic_module('register', 'case')
f0.source = get_simple_form(xmlns=f0.unique_id)
factory.app.profile = {'features': {'dependencies': []}}
factory.app.save()
self.addCleanup(factory.app.delete)
build1 = factory.app.make_build()
build1.save()

factory.app.save()

with patch("corehq.apps.app_manager.models.metrics_counter") as metric_counter_mock:
factory.app.make_build()
metric_counter_mock.assert_not_called()
Loading