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

feat(ddm): Add support for blocking metrics #63598

Merged
merged 11 commits into from
Jan 24, 2024

Conversation

iambriccardo
Copy link
Member

@iambriccardo iambriccardo commented Jan 22, 2024

This PR adds the ability to store blocked metrics in sentry options and allows to return of those blocked metrics in the metrics/meta endpoint.

A follow-up PR will be done in which the metrics configuration will be emitted for Relay. It was not done in this PR to not add additional complexity and surface for errors.

Copy link

sentry-io bot commented Jan 22, 2024

🔍 Existing Issues For Review

Your pull request is modifying functions with the following pre-existing issues:

📄 File: src/sentry/relay/config/init.py

Function Unhandled Issue
_get_project_config TypeError: 'Organization' object is not iterable ...
Event Count: 41
_get_project_config TypeError: 'int' object is not iterable sentry.ta...
Event Count: 1

Did you find this useful? React with a 👍 or 👎

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Jan 22, 2024
@iambriccardo iambriccardo changed the title riccardo/feat/blocked metrics feat(ddm): Add support for blocking metrics Jan 22, 2024
Copy link

codecov bot commented Jan 22, 2024

Codecov Report

Attention: 26 lines in your changes are missing coverage. Please review.

Comparison is base (6f3a2e4) 81.38% compared to head (a343e9d) 81.37%.
Report is 11 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #63598      +/-   ##
==========================================
- Coverage   81.38%   81.37%   -0.01%     
==========================================
  Files        5221     5224       +3     
  Lines      231753   231924     +171     
  Branches    40066    40111      +45     
==========================================
+ Hits       188603   188734     +131     
- Misses      37344    37369      +25     
- Partials     5806     5821      +15     
Files Coverage Δ
src/sentry/api/paginator.py 88.73% <100.00%> (ø)
src/sentry/api/urls.py 100.00% <ø> (ø)
src/sentry/features/__init__.py 100.00% <100.00%> (ø)
src/sentry/new_migrations/monkey/__init__.py 77.77% <100.00%> (ø)
src/sentry/sentry_metrics/visibility/__init__.py 100.00% <100.00%> (ø)
src/sentry/sentry_metrics/visibility/errors.py 100.00% <100.00%> (ø)
src/sentry/snuba/metrics/utils.py 96.80% <100.00%> (+0.10%) ⬆️
src/sentry/testutils/cases.py 85.67% <100.00%> (ø)
...app/components/modals/inviteMembersModal/index.tsx 92.42% <ø> (-0.23%) ⬇️
.../settings/organizationMembers/inviteRequestRow.tsx 100.00% <ø> (ø)
... and 4 more

... and 7 files with indirect coverage changes

@@ -123,3 +129,32 @@
)

return Response(response, status=200)


Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.
publish_status = {"GET": ApiPublishStatus.EXPERIMENTAL, "PATCH": ApiPublishStatus.EXPERIMENTAL}
owner = ApiOwner.TELEMETRY_EXPERIENCE

def get(self, request: Request, organization) -> Response:
Copy link
Member Author

Choose a reason for hiding this comment

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

Moved the metrics/meta endpoint also here, to prepare for a future refactor.

OrganizationMetricsEndpoint.as_view(),
name="sentry-api-0-organization-metrics-index",
),
re_path(
r"^(?P<organization_slug>[^/]+)/metrics/meta/$",
Copy link
Member Author

Choose a reason for hiding this comment

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

This is the previous endpoint, which is kept for backwards compatibility.

try:
blocked_metrics_payload = json.loads(json_payload)
except ValueError:
if repair:
Copy link
Member Author

Choose a reason for hiding this comment

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

Repairing on write allows us to make sure we don't end up in a broken state of the system which requires a separate PR to unbreak.

Copy link
Member

Choose a reason for hiding this comment

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

I do understand that this is a real possibility since anyone else could theoretically write to this field, but I do not see a value in trying to "repair" it by deleting the key completely. Raising an exception and opening an issue on Sentry would be enough IMO.

Copy link
Member Author

Choose a reason for hiding this comment

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

I can remove this behavior, but if something is corrupted, we either delete it or figure out its content and make a PR to untangle it programmatically.

My main idea for doing so is that if a config of a user gets corrupted, they will now ingest all their blocked metrics and they don't have a way to block them again (they have to wait for our PR). With my system, they can immediately fix the problem with the downside being losing their previous settings. Still, it's a negligible problem since if the JSON is corrupted there likely won't be valuable data in the stored settings.


return BlockedMetrics(metrics=blocked_metrics)._merge_blocked_metrics()

def _merge_blocked_metrics(self) -> "BlockedMetrics":
Copy link
Member Author

Choose a reason for hiding this comment

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

We run merging on both writing and reading, this assumes that options data can be overridden by someone else, so as long as the data is in the right format, we will merge.

Copy link
Member

Choose a reason for hiding this comment

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

We need merging because of the tags?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nope, we need merging in general, since we don't want to return to the frontend duplicated data.

type=parsed_mri.entity,
project_ids=project_ids,
blocked_for_projects = []
if (blocked := blocked_metrics.get(metric_mri)) is not None:
Copy link
Member Author

Choose a reason for hiding this comment

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

Too much manipulation going on here but if we have to merge blocked and non-blocked metrics we have no other ways.

@iambriccardo iambriccardo marked this pull request as ready for review January 23, 2024 15:59
@iambriccardo iambriccardo requested review from a team as code owners January 23, 2024 15:59
@@ -2904,7 +2904,7 @@ def build_and_store_session(
self.store_session(self.build_session(**kwargs))


class OrganizationMetricMetaIntegrationTestCase(MetricsAPIBaseTestCase):
class OrganizationMetricsIntegrationTestCase(MetricsAPIBaseTestCase):
Copy link
Member Author

Choose a reason for hiding this comment

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

driveby: Renamed for consistency.


for metric_mri, project_ids in stored_mris.items():
stored_metrics = get_stored_metrics_of_projects(projects, use_case_id)
Copy link
Member Author

Choose a reason for hiding this comment

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

driveby: Removed for consistency.

Copy link
Member

@obostjancic obostjancic left a comment

Choose a reason for hiding this comment

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

Looks fine overall, left a couple of comments. Also, as mentioned before, I think we should try to keep refactors to a minimum during feature impl.


@dataclass(frozen=True)
class BlockedMetric:
metric_mri: str
Copy link
Member

Choose a reason for hiding this comment

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

nit:

Suggested change
metric_mri: str
mri: str

try:
blocked_metrics_payload = json.loads(json_payload)
except ValueError:
if repair:
Copy link
Member

Choose a reason for hiding this comment

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

I do understand that this is a real possibility since anyone else could theoretically write to this field, but I do not see a value in trying to "repair" it by deleting the key completely. Raising an exception and opening an issue on Sentry would be enough IMO.


return BlockedMetrics(metrics=blocked_metrics)._merge_blocked_metrics()

def _merge_blocked_metrics(self) -> "BlockedMetrics":
Copy link
Member

Choose a reason for hiding this comment

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

We need merging because of the tags?

@@ -1,5 +1,7 @@
from __future__ import annotations

from sentry.sentry_metrics.visibility import get_blocked_metrics
Copy link
Member

Choose a reason for hiding this comment

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

nit: do we plan on putting anything else in this module? If not, then i would call it blocking or metrics_blocking or would flatten it out by butting exports and errors in metrics_blocking.py

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes we are, all the deletion logic will go there. It's called visibility exactly because it's a generic term that both have in common.

@iambriccardo iambriccardo merged commit f201c69 into master Jan 24, 2024
50 of 51 checks passed
@iambriccardo iambriccardo deleted the riccardo/feat/blocked-metrics branch January 24, 2024 08:49
@github-actions github-actions bot locked and limited conversation to collaborators Feb 8, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Scope: Backend Automatically applied to PRs that change backend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants