-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
feat(workflow_engine): Add evaluation logs to detectors #121908
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ | |
| from sentry.issues.producer import PayloadType, produce_occurrence_to_kafka | ||
| from sentry.models.activity import Activity | ||
| from sentry.models.group import Group | ||
| from sentry.models.organization import Organization | ||
| from sentry.services.eventstore.models import GroupEvent | ||
| from sentry.utils import metrics | ||
| from sentry.utils.cache import cache | ||
|
|
@@ -21,7 +22,8 @@ | |
| ) | ||
| from sentry.workflow_engine.models import DataPacket, Detector | ||
| from sentry.workflow_engine.models.detector_group import DetectorGroup | ||
| from sentry.workflow_engine.processors import DetectorEvaluation | ||
| from sentry.workflow_engine.processors import DetectorEvaluation, ProcessDetectorsResult | ||
| from sentry.workflow_engine.processors.evaluation_logging import emit_detector_evaluation_logs | ||
|
Check failure on line 26 in src/sentry/workflow_engine/processors/detector.py
|
||
| from sentry.workflow_engine.types import ( | ||
| DetectorGroupKey, | ||
| DetectorId, | ||
|
|
@@ -271,6 +273,16 @@ | |
| ) | ||
|
|
||
|
|
||
| def _get_detector_organization(detector: Detector) -> Organization: | ||
| if detector.project_id is not None: | ||
| return detector.linked_project.organization | ||
|
|
||
| organization_id = detector.config.get("organization_id") | ||
| if not isinstance(organization_id, int): | ||
| raise ValueError("Organization-scoped detector is missing organization_id") | ||
|
Check failure on line 282 in src/sentry/workflow_engine/processors/detector.py
|
||
|
Contributor
Author
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. We should raise a DetectorProcessing exception here instead of a value error, then catch it in |
||
| return Organization.objects.get_from_cache(id=organization_id) | ||
|
|
||
|
|
||
| @trace | ||
| def process_detectors[T]( | ||
| data_packet: DataPacket[T], detectors: list[Detector] | ||
|
|
@@ -293,6 +305,17 @@ | |
| ): | ||
| detector_results = handler.evaluate(data_packet) | ||
|
|
||
| emit_detector_evaluation_logs( | ||
| logger, | ||
| organization=_get_detector_organization(detector), | ||
| result=ProcessDetectorsResult( | ||
| detector_id=detector.id, | ||
| detector_type=detector.type, | ||
| project_id=detector.project_id, | ||
| evaluations=detector_results, | ||
| ), | ||
| ) | ||
|
|
||
| for result in detector_results.values(): | ||
| logger_extra = { | ||
| "detector": detector.id, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| from dataclasses import dataclass | ||
| from enum import StrEnum | ||
| from typing import Any, TypedDict | ||
|
|
||
| from sentry.workflow_engine.types import DetectorGroupKey, DetectorPriorityLevel, DetectorResult | ||
|
|
@@ -13,6 +14,11 @@ class DetectorEvaluationData(TypedDict): | |
| event_data: dict[str, Any] | None # TODO - improve this typing, for now migrating | ||
|
|
||
|
|
||
| class DetectorEvaluationOutcome(StrEnum): | ||
|
Contributor
Author
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.
|
||
| COMPLETED = "completed" | ||
| NO_RESULTS = "no_results" | ||
|
|
||
|
|
||
| @dataclass(frozen=True, kw_only=True) | ||
| class DetectorEvaluation( | ||
| BaseWorkflowEngineEvaluation[ | ||
|
|
@@ -49,3 +55,35 @@ def artifact_fields(self) -> dict[str, Any]: | |
| "priority": self.priority.value, | ||
| "trigger_group_evaluation": self.data["trigger_group_evaluation"].to_artifact(), | ||
| } | ||
|
|
||
|
|
||
| @dataclass(frozen=True, kw_only=True) | ||
| class ProcessDetectorsResult: | ||
| detector_id: int | ||
| detector_type: str | ||
| project_id: int | None | ||
| evaluations: dict[DetectorGroupKey, DetectorEvaluation] | ||
|
|
||
| @property | ||
| def outcome(self) -> DetectorEvaluationOutcome: | ||
| if self.evaluations: | ||
|
Contributor
Author
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. if the evaluation has an error in it, we should proxy that error up to this status as well. |
||
| return DetectorEvaluationOutcome.COMPLETED | ||
| return DetectorEvaluationOutcome.NO_RESULTS | ||
|
|
||
| def to_artifact(self) -> dict[str, object]: | ||
| return { | ||
| "detector_id": self.detector_id, | ||
| "detector_type": self.detector_type, | ||
| "project_id": self.project_id, | ||
| "outcome": self.outcome, | ||
| } | ||
|
Comment on lines
+73
to
+79
Contributor
Author
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. this should use |
||
|
|
||
| def evaluation_artifacts(self) -> list[dict[str, object]]: | ||
| detector_artifact = self.to_artifact() | ||
| if not self.evaluations: | ||
| return [detector_artifact] | ||
|
|
||
| return [ | ||
| {**detector_artifact, **evaluation.to_artifact()} | ||
| for evaluation in self.evaluations.values() | ||
| ] | ||
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.
Detector batch processing aborts on stale organization reference
The new emit_detector_evaluation_logs call in process_detectors uses _get_detector_organization without exception handling, causing the detector loop to abort on stale references or invalid config.
Evidence
Also found at 1 additional location
src/sentry/workflow_engine/processors/detector.py:282Identified by Warden · sentry-backend-bugs · DQ2-XJ4