Exemple #1
0
def build_incident_attachment(incident, integration_key, metric_value=None):
    data = incident_attachment_info(incident, metric_value)
    if incident.status == IncidentStatus.CRITICAL.value:
        severity = "critical"
    elif incident.status == IncidentStatus.WARNING.value:
        severity = "warning"
    elif incident.status == IncidentStatus.CLOSED.value:
        severity = "info"

    event_action = "resolve"
    if incident.status in [IncidentStatus.WARNING.value, IncidentStatus.CRITICAL.value]:
        event_action = "trigger"

    return {
        "routing_key": integration_key,
        "event_action": event_action,
        "dedup_key": f"incident_{incident.organization_id}_{incident.identifier}",
        "payload": {
            "summary": incident.alert_rule.name,
            "severity": severity,
            "source": str(incident.identifier),
            "custom_details": {"details": data["text"]},
        },
        "links": [{"href": data["title_link"], "text": data["title"]}],
    }
Exemple #2
0
def build_incident_attachment(incident, metric_value=None):
    """
    Builds an incident attachment for slack unfurling
    :param incident: The `Incident` to build the attachment for
    :param metric_value: The value of the metric that triggered this alert to fire. If
    not provided we'll attempt to calculate this ourselves.
    :return:
    """

    data = incident_attachment_info(incident, metric_value)

    colors = {
        "Resolved": RESOLVED_COLOR,
        "Warning": LEVEL_TO_COLOR["warning"],
        "Critical": LEVEL_TO_COLOR["fatal"],
    }

    return {
        "fallback": data["title"],
        "title": data["title"],
        "title_link": data["title_link"],
        "text": data["text"],
        "fields": [],
        "mrkdwn_in": ["text"],
        "footer_icon": data["logo_url"],
        "footer": "Sentry Incident",
        "ts": to_timestamp(data["ts"]),
        "color": colors[data["status"]],
        "actions": [],
    }
Exemple #3
0
    def test_with_incident_where_no_sessions_exist(self):
        alert_rule = self.create_alert_rule(
            query="",
            aggregate=
            "percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate",
            dataset=QueryDatasets.SESSIONS,
            time_window=60,
        )
        trigger = self.create_alert_rule_trigger(alert_rule,
                                                 CRITICAL_TRIGGER_LABEL, 95)
        incident = self.create_incident(
            self.organization,
            title="Incident #2",
            projects=[self.project],
            alert_rule=alert_rule,
            status=IncidentStatus.CLOSED.value,
            date_started=self.now,
        )
        action = self.create_alert_rule_trigger_action(
            alert_rule_trigger=trigger, triggered_for_incident=incident)
        data = incident_attachment_info(incident, None, action, method="fire")

        assert data["title"] == f"Critical: {alert_rule.name}"
        assert data["status"] == "Critical"
        assert data[
            "text"] == "No sessions crash free rate in the last 60 minutes"
Exemple #4
0
    def test_returns_correct_info(self):
        alert_rule = self.create_alert_rule()
        date_started = self.now
        incident = self.create_incident(
            self.organization,
            title="Incident #1",
            projects=[self.project],
            alert_rule=alert_rule,
            status=IncidentStatus.CLOSED.value,
            date_started=date_started,
        )
        trigger = self.create_alert_rule_trigger(alert_rule,
                                                 CRITICAL_TRIGGER_LABEL, 100)
        action = self.create_alert_rule_trigger_action(
            alert_rule_trigger=trigger, triggered_for_incident=incident)
        metric_value = 123
        data = incident_attachment_info(incident, metric_value, action)

        assert data["title"] == f"Resolved: {alert_rule.name}"
        assert data["status"] == "Resolved"
        assert data[
            "text"] == "123 events in the last 10 minutes\nFilter: level:error"
        assert data["ts"] == date_started
        assert data[
            "title_link"] == "http://testserver/organizations/baz/alerts/1/"
        assert (
            data["logo_url"] ==
            "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
        )
def build_incident_attachment(action,
                              incident,
                              metric_value=None,
                              method=None):
    from sentry.api.serializers.rest_framework.base import (
        camel_to_snake_case,
        convert_dict_key_case,
    )

    data = incident_attachment_info(incident,
                                    metric_value,
                                    action=action,
                                    method=method)
    return {
        "metric_alert":
        convert_dict_key_case(
            serialize(incident, serializer=IncidentSerializer()),
            camel_to_snake_case),
        "description_text":
        data["text"],
        "description_title":
        data["title"],
        "web_url":
        data["title_link"],
    }
Exemple #6
0
def build_incident_attachment(incident, integration_key, metric_value=None):
    data = incident_attachment_info(incident, metric_value)
    if incident.status == IncidentStatus.CRITICAL.value:
        severity = "critical"
    elif incident.status == IncidentStatus.WARNING.value:
        severity = "warning"
    elif incident.status == IncidentStatus.CLOSED.value:
        severity = "info"

    event_action = "resolve"
    if incident.status in [
            IncidentStatus.WARNING.value, IncidentStatus.CRITICAL.value
    ]:
        event_action = "trigger"

    footer_text = "Sentry Incident | {}".format(data["ts"].strftime("%b %d"))

    return {
        "routing_key":
        integration_key,
        "event_action":
        event_action,
        "dedup_key":
        "incident_{}_{}".format(incident.organization_id, incident.identifier),
        "payload": {
            "summary": data["text"],
            "severity": severity,
            "source": incident.identifier,
            "custom_details": footer_text,
        },
        "links": [{
            "href": data["title_link"],
            "text": data["title"]
        }],
    }
Exemple #7
0
 def test_with_incident_trigger_users_resolve(self):
     self.create_incident_and_related_objects(field="users")
     data = incident_attachment_info(self.incident, IncidentStatus.CLOSED)
     assert data["title"] == f"Resolved: {self.alert_rule.name}"
     assert data["status"] == "Resolved"
     assert data["text"] == "100.0% users crash free rate in the last 60 minutes"
     assert data["ts"] == self.date_started
     assert (
         data["logo_url"]
         == "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
     )
Exemple #8
0
    def test_with_incident_trigger_sessions(self):
        self.create_incident_and_related_objects()
        data = incident_attachment_info(self.incident, IncidentStatus.CRITICAL, 92)

        assert data["title"] == f"Critical: {self.alert_rule.name}"
        assert data["status"] == "Critical"
        assert data["text"] == "92% sessions crash free rate in the last 60 minutes"
        assert data["ts"] == self.date_started
        assert (
            data["logo_url"]
            == "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
        )
Exemple #9
0
    def build(self) -> SlackBody:
        data = incident_attachment_info(self.incident, self.new_status, self.metric_value)

        return self._build(
            actions=[],
            color=INCIDENT_COLOR_MAPPING.get(data["status"]),
            fallback=data["title"],
            fields=[],
            footer=get_footer(data["ts"]),
            text=data["text"],
            title=data["title"],
            title_link=data["title_link"],
        )
Exemple #10
0
 def test_with_incident_trigger_users(self):
     self.create_incident_and_related_objects(field="users")
     data = incident_attachment_info(self.incident,
                                     92,
                                     self.action,
                                     method="fire")
     assert data["title"] == f"Critical: {self.alert_rule.name}"
     assert data["status"] == "Critical"
     assert data[
         "text"] == "92% users crash free rate in the last 60 minutes"
     assert data["ts"] == self.date_started
     assert (
         data["logo_url"] ==
         "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
     )
Exemple #11
0
def build_incident_attachment(
    incident: Incident,
    new_status: IncidentStatus,
    metric_value: str | None = None,
) -> Mapping[str, str]:
    from sentry.api.serializers.rest_framework.base import (
        camel_to_snake_case,
        convert_dict_key_case,
    )

    data = incident_attachment_info(incident, new_status, metric_value)
    return {
        "metric_alert": convert_dict_key_case(
            serialize(incident, serializer=IncidentSerializer()), camel_to_snake_case
        ),
        "description_text": data["text"],
        "description_title": data["title"],
        "web_url": data["title_link"],
    }
Exemple #12
0
def build_incident_attachment(action,
                              incident,
                              metric_value=None,
                              method=None):
    """
    Builds an incident attachment for slack unfurling
    :param incident: The `Incident` to build the attachment for
    :param metric_value: The value of the metric that triggered this alert to fire. If
    not provided we'll attempt to calculate this ourselves.
    :return:
    """

    data = incident_attachment_info(incident,
                                    metric_value,
                                    action=action,
                                    method=method)

    colors = {
        "Resolved": RESOLVED_COLOR,
        "Warning": LEVEL_TO_COLOR["warning"],
        "Critical": LEVEL_TO_COLOR["fatal"],
    }

    incident_footer_ts = (
        "<!date^{:.0f}^Sentry Incident - Started {} at {} | Sentry Incident>".
        format(to_timestamp(data["ts"]), "{date_pretty}", "{time}"))

    return {
        "fallback": data["title"],
        "title": data["title"],
        "title_link": data["title_link"],
        "text": data["text"],
        "fields": [],
        "mrkdwn_in": ["text"],
        "footer_icon": data["logo_url"],
        "footer": incident_footer_ts,
        "color": colors[data["status"]],
        "actions": [],
    }
Exemple #13
0
    def test_with_incident_trigger(self):
        alert_rule = self.create_alert_rule()
        now = self.now
        date_started = now - timedelta(minutes=5)
        event_date = now - timedelta(minutes=5)

        self.create_event(event_date)
        self.create_event(event_date)
        self.create_event(event_date)
        self.create_event(event_date)

        incident = self.create_incident(
            self.organization,
            title="Incident #2",
            projects=[self.project],
            alert_rule=alert_rule,
            status=IncidentStatus.CLOSED.value,
            date_started=date_started,
            query="",
        )

        self.create_alert_rule_trigger_action(triggered_for_incident=incident)

        incident_trigger = (
            IncidentTrigger.objects.filter(incident=incident).order_by("-date_modified").first()
        )
        incident_trigger.update(date_modified=now)

        data = incident_attachment_info(incident)

        assert data["title"] == f"Resolved: {alert_rule.name}"
        assert data["status"] == "Resolved"
        assert data["text"] == "4 events in the last 10 minutes\nFilter: level:error"
        assert data["ts"] == date_started
        assert data["title_link"] == "http://testserver/organizations/baz/alerts/1/"
        assert (
            data["logo_url"]
            == "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
        )
Exemple #14
0
    def test_with_incident_trigger_crash_rate_alerts(self):
        for idx, field in enumerate(["sessions", "users"]):
            alert_rule = self.create_alert_rule(
                query="",
                aggregate=
                f"percentage({field}_crashed, {field}) AS _crash_rate_alert_aggregate",
            )
            date_started = self.now
            incident = self.create_incident(
                self.organization,
                title="Incident #1",
                projects=[self.project],
                alert_rule=alert_rule,
                status=IncidentStatus.CLOSED.value,
                date_started=date_started,
            )
            trigger = self.create_alert_rule_trigger(alert_rule,
                                                     CRITICAL_TRIGGER_LABEL,
                                                     95)
            action = self.create_alert_rule_trigger_action(
                alert_rule_trigger=trigger, triggered_for_incident=incident)
            metric_value = 92
            data = incident_attachment_info(incident,
                                            metric_value,
                                            action,
                                            method="fire")

            assert data["title"] == f"Critical: {alert_rule.name}"
            assert data["status"] == "Critical"
            assert data[
                "text"] == f"92% {field} crash free rate in the last 10 minutes"
            assert data["ts"] == date_started
            assert data[
                "title_link"] == f"http://testserver/organizations/baz/alerts/{idx + 1}/"
            assert (
                data["logo_url"] ==
                "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
            )
Exemple #15
0
    def test_with_incident_trigger(self):
        alert_rule = self.create_alert_rule()
        now = self.now
        date_started = now - timedelta(minutes=5)
        event_date = now - timedelta(minutes=5)

        self.create_event(event_date)
        self.create_event(event_date)
        self.create_event(event_date)
        self.create_event(event_date)

        incident = self.create_incident(
            self.organization,
            title="Incident #2",
            projects=[self.project],
            alert_rule=alert_rule,
            status=IncidentStatus.CLOSED.value,
            date_started=date_started,
            query="",
        )
        trigger = self.create_alert_rule_trigger(alert_rule,
                                                 CRITICAL_TRIGGER_LABEL, 100)
        action = self.create_alert_rule_trigger_action(
            alert_rule_trigger=trigger, triggered_for_incident=incident)

        incident_trigger = (IncidentTrigger.objects.filter(
            incident=incident).order_by("-date_modified").first())
        incident_trigger.update(date_modified=now)

        # Test the trigger "firing"
        data = incident_attachment_info(incident, action=action, method="fire")
        assert data["title"] == "Critical: {}".format(
            alert_rule.name)  # Pulls from trigger, not incident
        assert data[
            "status"] == "Critical"  # Should pull from the action/trigger.
        assert data[
            "text"] == "4 events in the last 10 minutes\nFilter: level:error"
        assert data["ts"] == date_started
        assert data[
            "title_link"] == "http://testserver/organizations/baz/alerts/1/"
        assert (
            data["logo_url"] ==
            "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
        )

        # Test the trigger "resolving"
        data = incident_attachment_info(incident,
                                        action=action,
                                        method="resolve")
        assert data["title"] == f"Resolved: {alert_rule.name}"
        assert data["status"] == "Resolved"
        assert data[
            "text"] == "4 events in the last 10 minutes\nFilter: level:error"
        assert data["ts"] == date_started
        assert data[
            "title_link"] == "http://testserver/organizations/baz/alerts/1/"
        assert (
            data["logo_url"] ==
            "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
        )

        # No trigger passed, uses incident as fallback
        data = incident_attachment_info(incident, action=action)
        assert data["title"] == f"Resolved: {alert_rule.name}"
        assert data["status"] == "Resolved"
        assert data[
            "text"] == "4 events in the last 10 minutes\nFilter: level:error"
        assert data["ts"] == date_started
        assert data[
            "title_link"] == "http://testserver/organizations/baz/alerts/1/"
        assert (
            data["logo_url"] ==
            "http://testserver/_static/{version}/sentry/images/sentry-email-avatar.png"
        )
Exemple #16
0
def build_incident_attachment(incident, metric_value=None):
    data = incident_attachment_info(incident, metric_value)

    colors = {
        "Resolved": "good",
        "Warning": "warning",
        "Critical": "attention"
    }

    footer_text = "Sentry Incident | {}".format(data["ts"].strftime("%b %d"))

    return {
        "type":
        "AdaptiveCard",
        "$schema":
        "http://adaptivecards.io/schemas/adaptive-card.json",
        "version":
        "1.2",
        "body": [{
            "type":
            "ColumnSet",
            "columns": [
                {
                    "type": "Column",
                    "style": colors[data["status"]],
                    "items": [],
                    "width": "20px",
                },
                {
                    "type":
                    "Column",
                    "items": [{
                        "type":
                        "Container",
                        "items": [
                            {
                                "type":
                                "TextBlock",
                                "text":
                                "[{}]({})".format(data["title"],
                                                  data["title_link"]),
                                "fontType":
                                "Default",
                                "weight":
                                "Bolder",
                            },
                            {
                                "type": "TextBlock",
                                "text": data["text"],
                                "isSubtle": True
                            },
                            {
                                "type":
                                "ColumnSet",
                                "columns": [
                                    {
                                        "type":
                                        "Column",
                                        "items": [{
                                            "type": "Image",
                                            "url": data["logo_url"],
                                            "size": "Small",
                                            "width": "20px",
                                        }],
                                        "width":
                                        "auto",
                                    },
                                    {
                                        "type":
                                        "Column",
                                        "items": [{
                                            "type": "TextBlock",
                                            "spacing": "None",
                                            "text": footer_text,
                                            "isSubtle": True,
                                            "wrap": True,
                                            "height": "stretch",
                                        }],
                                        "width":
                                        "stretch",
                                    },
                                ],
                            },
                        ],
                    }],
                    "width":
                    "stretch",
                },
            ],
        }],
    }