diff --git a/src/sentry/analytics/events/eventuser_endpoint_request.py b/src/sentry/analytics/events/eventuser_endpoint_request.py index 79c28fdc6868a5..df1dd2af56d5a5 100644 --- a/src/sentry/analytics/events/eventuser_endpoint_request.py +++ b/src/sentry/analytics/events/eventuser_endpoint_request.py @@ -1,13 +1,10 @@ from sentry import analytics +@analytics.eventclass("eventuser_endpoint.request") class EventUserEndpointRequest(analytics.Event): - type = "eventuser_endpoint.request" - - attributes = ( - analytics.Attribute("endpoint", required=True), - analytics.Attribute("project_id", required=False), - ) + endpoint: str + project_id: str | None = None analytics.register(EventUserEndpointRequest) diff --git a/src/sentry/analytics/events/groupowner_assignment.py b/src/sentry/analytics/events/groupowner_assignment.py index 81926fecc2bd98..944af06c444594 100644 --- a/src/sentry/analytics/events/groupowner_assignment.py +++ b/src/sentry/analytics/events/groupowner_assignment.py @@ -1,18 +1,15 @@ from sentry import analytics +@analytics.eventclass("groupowner.assignment") class GroupOwnerAssignment(analytics.Event): - type = "groupowner.assignment" - - attributes = ( - analytics.Attribute("organization_id"), - analytics.Attribute("project_id"), - analytics.Attribute("group_id"), - analytics.Attribute("new_assignment", type=bool), - analytics.Attribute("user_id", required=False), - analytics.Attribute("group_owner_type"), - analytics.Attribute("method", required=False), - ) + organization_id: str + project_id: str + group_id: str + new_assignment: bool + user_id: str | None = None + group_owner_type: str + method: str | None = None analytics.register(GroupOwnerAssignment) diff --git a/src/sentry/analytics/events/integration_commit_context_all_frames.py b/src/sentry/analytics/events/integration_commit_context_all_frames.py index 053472114c9f23..58545df56e0043 100644 --- a/src/sentry/analytics/events/integration_commit_context_all_frames.py +++ b/src/sentry/analytics/events/integration_commit_context_all_frames.py @@ -1,36 +1,30 @@ from sentry import analytics +@analytics.eventclass("integrations.failed_to_fetch_commit_context_all_frames") class IntegrationsFailedToFetchCommitContextAllFrames(analytics.Event): - type = "integrations.failed_to_fetch_commit_context_all_frames" - - attributes = ( - analytics.Attribute("organization_id"), - analytics.Attribute("project_id"), - analytics.Attribute("group_id"), - analytics.Attribute("event_id"), - analytics.Attribute("num_frames", type=int), - analytics.Attribute("num_successfully_mapped_frames", type=int), - analytics.Attribute("reason"), - ) + organization_id: str + project_id: str + group_id: str + event_id: str + num_frames: int + num_successfully_mapped_frames: int + reason: str +@analytics.eventclass("integrations.successfully_fetched_commit_context_all_frames") class IntegrationsSuccessfullyFetchedCommitContextAllFrames(analytics.Event): - type = "integrations.successfully_fetched_commit_context_all_frames" - - attributes = ( - analytics.Attribute("organization_id"), - analytics.Attribute("project_id"), - analytics.Attribute("group_id"), - analytics.Attribute("event_id"), - analytics.Attribute("num_frames", type=int), - analytics.Attribute("num_unique_commits", type=int), - analytics.Attribute("num_unique_commit_authors", type=int), - analytics.Attribute("num_successfully_mapped_frames", type=int), - analytics.Attribute("selected_frame_index", type=int), - analytics.Attribute("selected_provider", type=str), - analytics.Attribute("selected_code_mapping_id"), - ) + organization_id: str + project_id: str + group_id: str + event_id: str + num_frames: int + num_unique_commits: int + num_unique_commit_authors: int + num_successfully_mapped_frames: int + selected_frame_index: int + selected_provider: str + selected_code_mapping_id: str analytics.register(IntegrationsSuccessfullyFetchedCommitContextAllFrames) diff --git a/src/sentry/analytics/events/issue_resolved.py b/src/sentry/analytics/events/issue_resolved.py index 89ffb2de004704..c102e1349281d1 100644 --- a/src/sentry/analytics/events/issue_resolved.py +++ b/src/sentry/analytics/events/issue_resolved.py @@ -1,20 +1,17 @@ from sentry import analytics +@analytics.eventclass("issue.resolved") class IssueResolvedEvent(analytics.Event): - type = "issue.resolved" - - attributes = ( - analytics.Attribute("user_id", required=False), - analytics.Attribute("project_id", required=False), - analytics.Attribute("default_user_id"), - analytics.Attribute("organization_id"), - analytics.Attribute("group_id"), - analytics.Attribute("resolution_type"), - # TODO: make required once we validate that all events have this - analytics.Attribute("issue_category", required=False), - analytics.Attribute("issue_type", required=False), - ) + user_id: str | None = None + project_id: str | None = None + default_user_id: str + organization_id: str + group_id: str + resolution_type: str + # TODO: make required once we validate that all events have this + issue_category: str | None = None + issue_type: str | None = None analytics.register(IssueResolvedEvent) diff --git a/src/sentry/api/endpoints/group_tagkey_values.py b/src/sentry/api/endpoints/group_tagkey_values.py index f63c7ca3799334..beaefb3306319a 100644 --- a/src/sentry/api/endpoints/group_tagkey_values.py +++ b/src/sentry/api/endpoints/group_tagkey_values.py @@ -3,6 +3,7 @@ from rest_framework.response import Response from sentry import analytics, tagstore +from sentry.analytics.events.eventuser_endpoint_request import EventUserEndpointRequest from sentry.api.api_owners import ApiOwner from sentry.api.api_publish_status import ApiPublishStatus from sentry.api.base import region_silo_endpoint @@ -68,9 +69,10 @@ def get(self, request: Request, group, key) -> Response: List a Tag's Values """ analytics.record( - "eventuser_endpoint.request", - project_id=group.project_id, - endpoint="sentry.api.endpoints.group_tagkey_values.get", + EventUserEndpointRequest( + project_id=group.project_id, + endpoint="sentry.api.endpoints.group_tagkey_values.get", + ) ) lookup_key = tagstore.backend.prefix_reserved_key(key) diff --git a/src/sentry/api/endpoints/project_users.py b/src/sentry/api/endpoints/project_users.py index fffd5df8ac17b0..70714ef3c87d65 100644 --- a/src/sentry/api/endpoints/project_users.py +++ b/src/sentry/api/endpoints/project_users.py @@ -2,6 +2,7 @@ from rest_framework.response import Response from sentry import analytics +from sentry.analytics.events.eventuser_endpoint_request import EventUserEndpointRequest from sentry.api.api_publish_status import ApiPublishStatus from sentry.api.base import region_silo_endpoint from sentry.api.bases.project import ProjectAndStaffPermission, ProjectEndpoint @@ -41,9 +42,10 @@ def get(self, request: Request, project) -> Response: For example, ``query=email:foo@example.com`` """ analytics.record( - "eventuser_endpoint.request", - project_id=project.id, - endpoint="sentry.api.endpoints.project_users.get", + EventUserEndpointRequest( + project_id=project.id, + endpoint="sentry.api.endpoints.project_users.get", + ) ) field, identifier = None, None if request.GET.get("query"): diff --git a/src/sentry/integrations/analytics.py b/src/sentry/integrations/analytics.py index 2f155d92537095..8578dbe81d95af 100644 --- a/src/sentry/integrations/analytics.py +++ b/src/sentry/integrations/analytics.py @@ -1,127 +1,94 @@ from sentry import analytics +@analytics.eventclass("integration.added") class IntegrationAddedEvent(analytics.Event): - type = "integration.added" - - attributes = ( - analytics.Attribute("provider"), - analytics.Attribute("id"), - analytics.Attribute("organization_id"), - analytics.Attribute("user_id", required=False), - analytics.Attribute("default_user_id"), - ) + provider: str + id: str + organization_id: str + user_id: str | None = None + default_user_id: str +@analytics.eventclass("integration.disabled.notified") class IntegrationDisabledNotified(analytics.Event): - type = "integration.disabled.notified" - - attributes = ( - analytics.Attribute("organization_id"), - analytics.Attribute("provider"), - analytics.Attribute("integration_type"), - analytics.Attribute("integration_id"), - analytics.Attribute("user_id", required=False), - ) + organization_id: str + provider: str + integration_type: str + integration_id: str + user_id: str | None = None +@analytics.eventclass("integration.issue.created") class IntegrationIssueCreatedEvent(analytics.Event): - type = "integration.issue.created" - - attributes = ( - analytics.Attribute("provider"), - analytics.Attribute("id"), - analytics.Attribute("organization_id"), - analytics.Attribute("user_id", required=False), - analytics.Attribute("default_user_id"), - ) + provider: str + id: str + organization_id: str + user_id: str | None = None + default_user_id: str +@analytics.eventclass("integration.issue.linked") class IntegrationIssueLinkedEvent(analytics.Event): - type = "integration.issue.linked" - - attributes = ( - analytics.Attribute("provider"), - analytics.Attribute("id"), - analytics.Attribute("organization_id"), - analytics.Attribute("user_id", required=False), - analytics.Attribute("default_user_id"), - ) + provider: str + id: str + organization_id: str + user_id: str | None = None + default_user_id: str +@analytics.eventclass("integration.issue.status.synced") class IntegrationIssueStatusSyncedEvent(analytics.Event): - type = "integration.issue.status.synced" - - attributes = ( - analytics.Attribute("provider"), - analytics.Attribute("id"), - analytics.Attribute("organization_id"), - ) + provider: str + id: str + organization_id: str +@analytics.eventclass("integration.issue.assignee.synced") class IntegrationIssueAssigneeSyncedEvent(analytics.Event): - type = "integration.issue.assignee.synced" - - attributes = ( - analytics.Attribute("provider"), - analytics.Attribute("id"), - analytics.Attribute("organization_id"), - ) + provider: str + id: str + organization_id: str +@analytics.eventclass("integration.issue.comments.synced") class IntegrationIssueCommentsSyncedEvent(analytics.Event): - type = "integration.issue.comments.synced" - - attributes = ( - analytics.Attribute("provider"), - analytics.Attribute("id"), - analytics.Attribute("organization_id"), - ) + provider: str + id: str + organization_id: str +@analytics.eventclass("integration.repo.added") class IntegrationRepoAddedEvent(analytics.Event): - type = "integration.repo.added" - - attributes = ( - analytics.Attribute("provider"), - analytics.Attribute("id"), - analytics.Attribute("organization_id"), - ) + provider: str + id: str + organization_id: str +@analytics.eventclass("integration.resolve.commit") class IntegrationResolveCommitEvent(analytics.Event): - type = "integration.resolve.commit" - - attributes = ( - analytics.Attribute("provider"), - analytics.Attribute("id"), - analytics.Attribute("organization_id"), - ) + provider: str + id: str + organization_id: str +@analytics.eventclass("integration.resolve.pr") class IntegrationResolvePREvent(analytics.Event): - type = "integration.resolve.pr" - - attributes = ( - analytics.Attribute("provider"), - analytics.Attribute("id"), - analytics.Attribute("organization_id"), - ) + provider: str + id: str + organization_id: str +@analytics.eventclass("integration.stacktrace.linked") class IntegrationStacktraceLinkEvent(analytics.Event): - type = "integration.stacktrace.linked" - - attributes = ( - analytics.Attribute("provider"), - analytics.Attribute("config_id"), - analytics.Attribute("project_id"), - analytics.Attribute("organization_id"), - analytics.Attribute("filepath"), - analytics.Attribute("status"), - analytics.Attribute("link_fetch_iterations"), - analytics.Attribute("platform", required=False), - ) + provider: str + config_id: str + project_id: str + organization_id: str + filepath: str + status: str + link_fetch_iterations: str + platform: str | None = None def register_analytics() -> None: diff --git a/src/sentry/integrations/tasks/create_comment.py b/src/sentry/integrations/tasks/create_comment.py index 370bbc03533395..9b5b7a79bbe2c9 100644 --- a/src/sentry/integrations/tasks/create_comment.py +++ b/src/sentry/integrations/tasks/create_comment.py @@ -1,4 +1,5 @@ from sentry import analytics +from sentry.integrations.analytics import IntegrationIssueCommentsSyncedEvent from sentry.integrations.models.external_issue import ExternalIssue from sentry.integrations.models.integration import Integration from sentry.integrations.source_code_management.metrics import ( @@ -68,10 +69,10 @@ def create_comment(external_issue_id: int, user_id: int, group_note_id: int) -> note.data["external_id"] = installation.get_comment_id(comment) note.save() analytics.record( - # TODO(lb): this should be changed and/or specified? - "integration.issue.comments.synced", - provider=installation.model.provider, - id=installation.model.id, - organization_id=external_issue.organization_id, - user_id=user_id, + IntegrationIssueCommentsSyncedEvent( + provider=installation.model.provider, + id=installation.model.id, + organization_id=external_issue.organization_id, + user_id=user_id, + ) ) diff --git a/src/sentry/integrations/tasks/sync_assignee_outbound.py b/src/sentry/integrations/tasks/sync_assignee_outbound.py index c16d51080c7a59..c5c98c0b7edf45 100644 --- a/src/sentry/integrations/tasks/sync_assignee_outbound.py +++ b/src/sentry/integrations/tasks/sync_assignee_outbound.py @@ -3,6 +3,7 @@ from sentry import analytics, features from sentry.constants import ObjectStatus from sentry.exceptions import InvalidConfiguration +from sentry.integrations.analytics import IntegrationIssueAssigneeSyncedEvent from sentry.integrations.errors import OrganizationIntegrationNotFound from sentry.integrations.models.external_issue import ExternalIssue from sentry.integrations.models.integration import Integration @@ -93,10 +94,11 @@ def sync_assignee_outbound( external_issue, user, assign=assign, assignment_source=parsed_assignment_source ) analytics.record( - "integration.issue.assignee.synced", - provider=integration.provider, - id=integration.id, - organization_id=external_issue.organization_id, + IntegrationIssueAssigneeSyncedEvent( + provider=integration.provider, + id=integration.id, + organization_id=external_issue.organization_id, + ) ) except (OrganizationIntegrationNotFound, ApiUnauthorized, InvalidConfiguration) as e: lifecycle.record_halt(halt_reason=e) diff --git a/src/sentry/integrations/tasks/sync_status_inbound.py b/src/sentry/integrations/tasks/sync_status_inbound.py index c27967d4df99bb..41893edb498947 100644 --- a/src/sentry/integrations/tasks/sync_status_inbound.py +++ b/src/sentry/integrations/tasks/sync_status_inbound.py @@ -7,6 +7,7 @@ from django.utils import timezone as django_timezone from sentry import analytics +from sentry.analytics.events.issue_resolved import IssueResolvedEvent from sentry.api.helpers.group_index.update import get_current_release_version_of_group from sentry.constants import ObjectStatus from sentry.integrations.models.integration import Integration @@ -293,15 +294,16 @@ def sync_status_inbound( ) analytics.record( - "issue.resolved", - project_id=group.project.id, - default_user_id="Sentry Jira", - organization_id=organization_id, - group_id=group.id, - resolution_type="with_third_party_app", - provider=provider.key, - issue_type=group.issue_type.slug, - issue_category=group.issue_category.name.lower(), + IssueResolvedEvent( + project_id=group.project.id, + default_user_id="Sentry Jira", + organization_id=organization_id, + group_id=group.id, + resolution_type="with_third_party_app", + provider=provider.key, + issue_type=group.issue_type.slug, + issue_category=group.issue_category.name.lower(), + ) ) elif action == ResolveSyncAction.UNRESOLVE: diff --git a/src/sentry/integrations/tasks/sync_status_outbound.py b/src/sentry/integrations/tasks/sync_status_outbound.py index 1cea6900c38e04..5500f7abc42ac8 100644 --- a/src/sentry/integrations/tasks/sync_status_outbound.py +++ b/src/sentry/integrations/tasks/sync_status_outbound.py @@ -1,6 +1,7 @@ from sentry import analytics, features from sentry.constants import ObjectStatus from sentry.exceptions import InvalidIdentity +from sentry.integrations.analytics import IntegrationIssueStatusSyncedEvent from sentry.integrations.base import IntegrationInstallation from sentry.integrations.errors import OrganizationIntegrationNotFound from sentry.integrations.models.external_issue import ExternalIssue @@ -84,10 +85,11 @@ def sync_status_outbound(group_id: int, external_issue_id: int) -> bool | None: ) analytics.record( - "integration.issue.status.synced", - provider=integration.provider, - id=integration.id, - organization_id=external_issue.organization_id, + IntegrationIssueStatusSyncedEvent( + provider=integration.provider, + id=integration.id, + organization_id=external_issue.organization_id, + ) ) except ( IntegrationFormError, diff --git a/src/sentry/integrations/tasks/update_comment.py b/src/sentry/integrations/tasks/update_comment.py index 25a1ebc11c8ca5..3f79a1db86c29a 100644 --- a/src/sentry/integrations/tasks/update_comment.py +++ b/src/sentry/integrations/tasks/update_comment.py @@ -1,4 +1,5 @@ from sentry import analytics +from sentry.integrations.analytics import IntegrationIssueCommentsSyncedEvent from sentry.integrations.models.external_issue import ExternalIssue from sentry.integrations.models.integration import Integration from sentry.integrations.source_code_management.metrics import ( @@ -68,10 +69,10 @@ def update_comment(external_issue_id: int, user_id: int, group_note_id: int) -> ) installation.update_comment(external_issue.key, user_id, note) analytics.record( - # TODO(lb): this should be changed and/or specified? - "integration.issue.comments.synced", - provider=installation.model.provider, - id=installation.model.id, - organization_id=external_issue.organization_id, - user_id=user_id, + IntegrationIssueCommentsSyncedEvent( + provider=installation.model.provider, + id=installation.model.id, + organization_id=external_issue.organization_id, + user_id=user_id, + ) ) diff --git a/src/sentry/integrations/utils/commit_context.py b/src/sentry/integrations/utils/commit_context.py index 4a19e4fb13eb99..5cb34894304450 100644 --- a/src/sentry/integrations/utils/commit_context.py +++ b/src/sentry/integrations/utils/commit_context.py @@ -9,6 +9,10 @@ from django.utils.datastructures import OrderedSet from sentry import analytics +from sentry.analytics.events.integration_commit_context_all_frames import ( + IntegrationsFailedToFetchCommitContextAllFrames, + IntegrationsSuccessfullyFetchedCommitContextAllFrames, +) from sentry.constants import ObjectStatus from sentry.integrations.base import IntegrationInstallation from sentry.integrations.models.repository_project_path_config import RepositoryProjectPathConfig @@ -362,14 +366,15 @@ def _record_commit_context_all_frames_analytics( }, ) analytics.record( - "integrations.failed_to_fetch_commit_context_all_frames", - organization_id=organization_id, - project_id=project_id, - group_id=extra["group"], - event_id=extra["event"], - num_frames=len(frames), - num_successfully_mapped_frames=num_successfully_mapped_frames, - reason=reason, + IntegrationsFailedToFetchCommitContextAllFrames( + organization_id=organization_id, + project_id=project_id, + group_id=extra["group"], + event_id=extra["event"], + num_frames=len(frames), + num_successfully_mapped_frames=num_successfully_mapped_frames, + reason=reason, + ) ) return @@ -392,18 +397,19 @@ def _record_commit_context_all_frames_analytics( ) analytics.record( - "integrations.successfully_fetched_commit_context_all_frames", - organization_id=organization_id, - project_id=project_id, - group_id=extra["group"], - event_id=extra["event"], - num_frames=len(frames), - num_unique_commits=len(unique_commit_ids), - num_unique_commit_authors=len(unique_author_emails), - num_successfully_mapped_frames=num_successfully_mapped_frames, - selected_frame_index=selected_frame_index, - selected_provider=selected_provider, - selected_code_mapping_id=selected_blame.code_mapping.id, + IntegrationsSuccessfullyFetchedCommitContextAllFrames( + organization_id=organization_id, + project_id=project_id, + group_id=extra["group"], + event_id=extra["event"], + num_frames=len(frames), + num_unique_commits=len(unique_commit_ids), + num_unique_commit_authors=len(unique_author_emails), + num_successfully_mapped_frames=num_successfully_mapped_frames, + selected_frame_index=selected_frame_index, + selected_provider=selected_provider, + selected_code_mapping_id=selected_blame.code_mapping.id, + ) ) diff --git a/src/sentry/issues/endpoints/project_stacktrace_link.py b/src/sentry/issues/endpoints/project_stacktrace_link.py index 5fc9d9a082e7af..be194b8b1fd285 100644 --- a/src/sentry/issues/endpoints/project_stacktrace_link.py +++ b/src/sentry/issues/endpoints/project_stacktrace_link.py @@ -14,6 +14,7 @@ from sentry.api.base import region_silo_endpoint from sentry.api.bases.project import ProjectEndpoint from sentry.api.serializers import serialize +from sentry.integrations.analytics import IntegrationStacktraceLinkEvent from sentry.integrations.api.serializers.models.integration import IntegrationSerializer from sentry.integrations.base import IntegrationFeatures from sentry.integrations.services.integration import integration_service @@ -175,15 +176,16 @@ def get(self, request: Request, project: Project) -> Response: if result["current_config"] and serialized_config: analytics.record( - "integration.stacktrace.linked", - provider=serialized_config["provider"]["key"], - config_id=serialized_config["id"], - project_id=project.id, - organization_id=project.organization_id, - filepath=filepath, - status=error or "success", - link_fetch_iterations=result["iteration_count"], - platform=ctx["platform"], + IntegrationStacktraceLinkEvent( + provider=serialized_config["provider"]["key"], + config_id=serialized_config["id"], + project_id=project.id, + organization_id=project.organization_id, + filepath=filepath, + status=error or "success", + link_fetch_iterations=result["iteration_count"], + platform=ctx["platform"], + ) ) return Response( { diff --git a/src/sentry/plugins/providers/integration_repository.py b/src/sentry/plugins/providers/integration_repository.py index f55bb932e670ed..8359834dd97177 100644 --- a/src/sentry/plugins/providers/integration_repository.py +++ b/src/sentry/plugins/providers/integration_repository.py @@ -13,6 +13,7 @@ from sentry import analytics from sentry.api.exceptions import SentryAPIException from sentry.constants import ObjectStatus +from sentry.integrations.analytics import IntegrationRepoAddedEvent from sentry.integrations.base import IntegrationInstallation from sentry.integrations.models.integration import Integration from sentry.integrations.services.integration import integration_service @@ -198,10 +199,11 @@ def dispatch(self, request: Request, organization, **kwargs): repo_linked.send_robust(repo=repo, user=request.user, sender=self.__class__) analytics.record( - "integration.repo.added", - provider=self.id, - id=result.get("integration_id"), - organization_id=organization.id, + IntegrationRepoAddedEvent( + provider=self.id, + id=result.get("integration_id"), + organization_id=organization.id, + ) ) return Response( repository_service.serialize_repository( diff --git a/src/sentry/receivers/features.py b/src/sentry/receivers/features.py index 07b4af5d2528a7..cf1c48cf8fc995 100644 --- a/src/sentry/receivers/features.py +++ b/src/sentry/receivers/features.py @@ -4,6 +4,12 @@ from sentry import analytics from sentry.adoption import manager +from sentry.analytics.events.issue_resolved import IssueResolvedEvent +from sentry.integrations.analytics import ( + IntegrationAddedEvent, + IntegrationIssueCreatedEvent, + IntegrationIssueLinkedEvent, +) from sentry.integrations.services.integration import integration_service from sentry.models.featureadoption import FeatureAdoption from sentry.models.group import Group @@ -232,15 +238,16 @@ def record_issue_resolved(organization_id, project, group, user, resolution_type default_user_id = project.organization.default_owner_id or UNKNOWN_DEFAULT_USER_ID analytics.record( - "issue.resolved", - user_id=user_id, - project_id=project.id, - default_user_id=default_user_id, - organization_id=organization_id, - group_id=group.id, - resolution_type=resolution_type, - issue_type=group.issue_type.slug, - issue_category=group.issue_category.name.lower(), + IssueResolvedEvent( + user_id=user_id, + project_id=project.id, + default_user_id=default_user_id, + organization_id=organization_id, + group_id=group.id, + resolution_type=resolution_type, + issue_type=group.issue_type.slug, + issue_category=group.issue_category.name.lower(), + ) ) @@ -643,12 +650,13 @@ def record_integration_added( default_user_id = organization.get_default_owner().id analytics.record( - "integration.added", - user_id=user_id, - default_user_id=default_user_id, - organization_id=organization.id, - provider=integration.provider, - id=integration.id, + IntegrationAddedEvent( + user_id=user_id, + default_user_id=default_user_id, + organization_id=organization.id, + provider=integration.provider, + id=integration.id, + ) ) metrics.incr( "integration.added", @@ -665,12 +673,13 @@ def record_integration_issue_created(integration, organization, user, **kwargs): user_id = None default_user_id = organization.get_default_owner().id analytics.record( - "integration.issue.created", - user_id=user_id, - default_user_id=default_user_id, - organization_id=organization.id, - provider=integration.provider, - id=integration.id, + IntegrationIssueCreatedEvent( + user_id=user_id, + default_user_id=default_user_id, + organization_id=organization.id, + provider=integration.provider, + id=integration.id, + ) ) @@ -682,12 +691,13 @@ def record_integration_issue_linked(integration, organization, user, **kwargs): user_id = None default_user_id = organization.get_default_owner().id analytics.record( - "integration.issue.linked", - user_id=user_id, - default_user_id=default_user_id, - organization_id=organization.id, - provider=integration.provider, - id=integration.id, + IntegrationIssueLinkedEvent( + user_id=user_id, + default_user_id=default_user_id, + organization_id=organization.id, + provider=integration.provider, + id=integration.id, + ) ) diff --git a/src/sentry/receivers/releases.py b/src/sentry/receivers/releases.py index c676a4285acad9..7215fcd306a2a6 100644 --- a/src/sentry/receivers/releases.py +++ b/src/sentry/receivers/releases.py @@ -6,6 +6,7 @@ from sentry import analytics from sentry.db.postgres.transactions import in_test_hide_transaction_boundary +from sentry.integrations.analytics import IntegrationResolveCommitEvent, IntegrationResolvePREvent from sentry.models.activity import Activity from sentry.models.commit import Commit from sentry.models.group import Group, GroupStatus @@ -176,10 +177,11 @@ def resolved_in_commit(instance: Commit, created, **kwargs): if repo is not None: if repo.integration_id is not None: analytics.record( - "integration.resolve.commit", - provider=repo.provider, - id=repo.integration_id, - organization_id=repo.organization_id, + IntegrationResolveCommitEvent( + provider=repo.provider, + id=repo.integration_id, + organization_id=repo.organization_id, + ) ) issue_resolved.send_robust( @@ -251,10 +253,11 @@ def resolved_in_pull_request(instance: PullRequest, created, **kwargs): else: if repo is not None and repo.integration_id is not None: analytics.record( - "integration.resolve.pr", - provider=repo.provider, - id=repo.integration_id, - organization_id=repo.organization_id, + IntegrationResolvePREvent( + provider=repo.provider, + id=repo.integration_id, + organization_id=repo.organization_id, + ) ) diff --git a/src/sentry/tasks/commit_context.py b/src/sentry/tasks/commit_context.py index 8f8901943eb8a0..f4ccdb6ac0dec7 100644 --- a/src/sentry/tasks/commit_context.py +++ b/src/sentry/tasks/commit_context.py @@ -10,6 +10,10 @@ from sentry_sdk import set_tag from sentry import analytics +from sentry.analytics.events.groupowner_assignment import GroupOwnerAssignment +from sentry.analytics.events.integration_commit_context_all_frames import ( + IntegrationsFailedToFetchCommitContextAllFrames, +) from sentry.api.serializers.models.release import get_users_for_authors from sentry.integrations.source_code_management.commit_context import CommitContextIntegration from sentry.integrations.utils.commit_context import ( @@ -121,14 +125,15 @@ def process_commit_context( sdk_name=sdk_name, ) analytics.record( - "integrations.failed_to_fetch_commit_context_all_frames", - organization_id=project.organization_id, - project_id=project_id, - group_id=basic_logging_details["group"], - event_id=basic_logging_details["event"], - num_frames=0, - num_successfully_mapped_frames=0, - reason="could_not_find_in_app_stacktrace_frame", + IntegrationsFailedToFetchCommitContextAllFrames( + organization_id=project.organization_id, + project_id=project_id, + group_id=basic_logging_details["group"], + event_id=basic_logging_details["event"], + num_frames=0, + num_successfully_mapped_frames=0, + reason="could_not_find_in_app_stacktrace_frame", + ) ) return @@ -227,14 +232,15 @@ def process_commit_context( }, ) analytics.record( - "groupowner.assignment", - organization_id=project.organization_id, - project_id=project.id, - group_id=group_id, - new_assignment=created, - user_id=group_owner.user_id, - group_owner_type=group_owner.type, - method="scm_integration", + GroupOwnerAssignment( + organization_id=project.organization_id, + project_id=project.id, + group_id=group_id, + new_assignment=created, + user_id=group_owner.user_id, + group_owner_type=group_owner.type, + method="scm_integration", + ) ) except UnableToAcquireLock: pass diff --git a/src/sentry/tasks/groupowner.py b/src/sentry/tasks/groupowner.py index 330d0c9ae2a4ee..43c839f6e76ede 100644 --- a/src/sentry/tasks/groupowner.py +++ b/src/sentry/tasks/groupowner.py @@ -5,6 +5,7 @@ from django.utils import timezone from sentry import analytics +from sentry.analytics.events.groupowner_assignment import GroupOwnerAssignment from sentry.locks import locks from sentry.models.commit import Commit from sentry.models.groupowner import GroupOwner, GroupOwnerType @@ -108,14 +109,15 @@ def _process_suspect_commits( }, ) analytics.record( - "groupowner.assignment", - organization_id=project.organization_id, - project_id=project.id, - group_id=group_id, - new_assignment=created, - user_id=go.user_id, - group_owner_type=go.type, - method="release_commit", + GroupOwnerAssignment( + organization_id=project.organization_id, + project_id=project.id, + group_id=group_id, + new_assignment=created, + user_id=go.user_id, + group_owner_type=go.type, + method="release_commit", + ) ) except GroupOwner.MultipleObjectsReturned: diff --git a/src/sentry/tasks/unmerge.py b/src/sentry/tasks/unmerge.py index 3afb03d2aa4c3d..680913b781edbd 100644 --- a/src/sentry/tasks/unmerge.py +++ b/src/sentry/tasks/unmerge.py @@ -11,6 +11,7 @@ from django.db.models.base import Model from sentry import analytics, eventstore, features, similarity, tsdb +from sentry.analytics.events.eventuser_endpoint_request import EventUserEndpointRequest from sentry.constants import DEFAULT_LOGGER_NAME, LOG_LEVELS_MAP from sentry.culprit import generate_culprit from sentry.eventstore.models import BaseEvent @@ -380,9 +381,10 @@ def repair_group_release_data(caches, project, events): def get_event_user_from_interface(value, project): analytics.record( - "eventuser_endpoint.request", - project_id=project.id, - endpoint="sentry.tasks.unmerge.get_event_user_from_interface", + EventUserEndpointRequest( + project_id=project.id, + endpoint="sentry.tasks.unmerge.get_event_user_from_interface", + ) ) return EventUser( user_ident=value.get("id"),