-
-
Notifications
You must be signed in to change notification settings - Fork 218
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
Changes from 7 commits
2056cc2
7179077
a94b241
c2ef0d0
af3a6a1
08b1425
1823cbd
319593f
293fcaa
1c71a7b
cbd65ab
aee1a9a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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 = ApplicationBase.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') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? Or we could report uptake separately, which seems easy enough to add now.
I would vote for the single counter with both +/- There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'll check this out. Thanks for the suggestion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mkangia They can be combined as needed on Data Dog. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Not sure the difference but should this be
cls.wrap
? just like when the copy is created.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is in instance method, so either
self.__class__.wrap
orApplicationBase
- I prefer the latter.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will that impact if the function is called by inherited classes instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if a subclass calls this method that would mean the ApplicationBase wrap method is still called and not the subclass's
wrap
method. I think this is OK, since we don't use anything except the profile attribute. But that is a good point, maybe it should take the subclass's own implementation ofwrap
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya. We would be wrapping data for a different class on ApplicationBase which isn't ideal and would further lead to issues if the subclass adds more properties than ApplicationBase, which will get skipped leading to loss of data in case a save is performed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I'll update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might check out wrap_app for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@orangejenny What is the exact benefit of using
wrap_app(last_build, self.__class__)
instead of simplyself.__class__.wrap(last_build)
? I see thewrap_doc
function have theget_correct_app_class
addition, but that's only coming into play if I don't pass in the class name, which I will do in this instance.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably doesn't matter, then. I had just read the original code when making the suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrap_app
looks like a nice catch all for different application and similar docs with a hard failure in case of unexpected scenarios. Definitely good to use when dealing with more complex code.The class wrap seems safe here since we are passing a build explicitly.