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(workflow-engine): add EventAttributeConditionHandler #82741

Merged
merged 4 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/sentry/workflow_engine/handlers/condition/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
"ReappearedEventConditionHandler",
"RegressionEventConditionHandler",
"ExistingHighPriorityIssueConditionHandler",
"EventAttributeConditionHandler",
]

from .group_event_handlers import (
EventAttributeConditionHandler,
EventCreatedByDetectorConditionHandler,
EventSeenCountConditionHandler,
EveryEventConditionHandler,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
from typing import Any

import sentry_sdk

from sentry.eventstore.models import GroupEvent
from sentry.rules import MatchType, match_values
from sentry.rules.conditions.event_attribute import attribute_registry
from sentry.utils import json
from sentry.utils.registry import NoRegistrationExistsError
from sentry.workflow_engine.models.data_condition import Condition
from sentry.workflow_engine.registry import condition_handler_registry
from sentry.workflow_engine.types import DataConditionHandler, WorkflowJob
Expand Down Expand Up @@ -29,3 +36,53 @@ class EventSeenCountConditionHandler(DataConditionHandler[WorkflowJob]):
def evaluate_value(job: WorkflowJob, comparison: Any) -> bool:
event = job["event"]
return event.group.times_seen == comparison


@condition_handler_registry.register(Condition.EVENT_ATTRIBUTE)
class EventAttributeConditionHandler(DataConditionHandler[WorkflowJob]):
@staticmethod
def get_attribute_values(event: GroupEvent, attribute: str) -> list[str]:
path = attribute.split(".")
first_attribute = path[0]
try:
attribute_handler = attribute_registry.get(first_attribute)
except NoRegistrationExistsError:
attribute_handler = None

if not attribute_handler:
attribute_values = []
else:
try:
attribute_values = attribute_handler.handle(path, event)
except KeyError as e:
attribute_values = []
sentry_sdk.capture_exception(e)

attribute_values = [str(value).lower() for value in attribute_values if value is not None]

return attribute_values

@staticmethod
def evaluate_value(job: WorkflowJob, comparison: Any) -> bool:
comparison_dict = json.loads(comparison)

event = job["event"]
attribute = comparison_dict.get("attribute", "")
attribute_values = EventAttributeConditionHandler.get_attribute_values(event, attribute)

match = comparison_dict.get("match")
desired_value = comparison_dict.get("value")
if not (match and desired_value) and not (match in (MatchType.IS_SET, MatchType.NOT_SET)):
return False

desired_value = str(desired_value).lower()

# NOTE: IS_SET condition differs btw tagged_event and event_attribute so not handled by match_values
if match == MatchType.IS_SET:
return bool(attribute_values)
elif match == MatchType.NOT_SET:
return not attribute_values

return match_values(
group_values=attribute_values, match_value=desired_value, match_type=match
)
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from collections.abc import Callable
from typing import Any

from sentry.rules.conditions.event_attribute import EventAttributeCondition
from sentry.rules.conditions.every_event import EveryEventCondition
from sentry.rules.conditions.existing_high_priority_issue import ExistingHighPriorityIssueCondition
from sentry.rules.conditions.reappeared_event import ReappearedEventCondition
from sentry.rules.conditions.regression_event import RegressionEventCondition
from sentry.utils import json
from sentry.utils.registry import Registry
from sentry.workflow_engine.models.data_condition import Condition, DataCondition
from sentry.workflow_engine.models.data_condition_group import DataConditionGroup
Expand Down Expand Up @@ -65,3 +67,16 @@ def create_existing_high_priority_issue_data_condition(
condition_result=True,
condition_group=dcg,
)


@data_condition_translator_registry.register(EventAttributeCondition.id)
def create_event_attribute_data_condition(
data: dict[str, Any], dcg: DataConditionGroup
) -> DataCondition:
comparison = {"match": data["match"], "value": data["value"], "attribute": data["attribute"]}
return DataCondition.objects.create(
type=Condition.EVENT_ATTRIBUTE,
comparison=json.dumps(comparison),
condition_result=True,
condition_group=dcg,
)
1 change: 1 addition & 0 deletions src/sentry/workflow_engine/models/data_condition.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Condition(models.TextChoices):
LESS_OR_EQUAL = "lte"
LESS = "lt"
NOT_EQUAL = "ne"
EVENT_ATTRIBUTE = "event_attribute"
EVENT_CREATED_BY_DETECTOR = "event_created_by_detector"
EVENT_SEEN_COUNT = "event_seen_count"
EVERY_EVENT = "every_event"
Expand Down
Loading
Loading