Skip to content

Commit

Permalink
feat(workflow-engine): add EventAttributeConditionHandler (#82741)
Browse files Browse the repository at this point in the history
add `EventAttributeConditionHandler`
  • Loading branch information
ameliahsu authored Jan 2, 2025
1 parent 1668090 commit 30d47e5
Show file tree
Hide file tree
Showing 5 changed files with 970 additions and 0 deletions.
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

0 comments on commit 30d47e5

Please sign in to comment.