diff --git a/docs/source/ruletypes.rst b/docs/source/ruletypes.rst index bb446206..afd9203a 100644 --- a/docs/source/ruletypes.rst +++ b/docs/source/ruletypes.rst @@ -2453,6 +2453,10 @@ Example slack_alert_fields:: ``slack_ca_certs``: Set this option to ``True`` if you want to validate the SSL certificate. +``slack_footer``: Add a static footer text for alert. Defaults to "". + +``slack_footer_icon``: A Public Url for a footer icon. Defaults to "". + Splunk On-Call (Formerly VictorOps) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/elastalert/alerts.py b/elastalert/alerts.py index 646323d8..8cbf9915 100644 --- a/elastalert/alerts.py +++ b/elastalert/alerts.py @@ -1060,6 +1060,8 @@ def __init__(self, rule): self.slack_attach_kibana_discover_url = self.rule.get('slack_attach_kibana_discover_url', False) self.slack_kibana_discover_color = self.rule.get('slack_kibana_discover_color', '#ec4b98') self.slack_kibana_discover_title = self.rule.get('slack_kibana_discover_title', 'Discover in Kibana') + self.footer = self.rule.get('slack_footer', '') + self.footer_icon = self.rule.get('slack_footer_icon', '') def format_body(self, body): # https://api.slack.com/docs/formatting @@ -1122,6 +1124,10 @@ def alert(self, matches): if self.slack_title_link != '': payload['attachments'][0]['title_link'] = self.slack_title_link + if self.footer != '' and self.footer_icon != '': + payload['attachments'][0]['footer'] = self.footer + payload['attachments'][0]['footer_icon'] = self.footer_icon + if self.slack_attach_kibana_discover_url: kibana_discover_url = lookup_es_key(matches[0], 'kibana_discover_url') if kibana_discover_url: diff --git a/elastalert/schema.yaml b/elastalert/schema.yaml index ca402d19..b4a51365 100644 --- a/elastalert/schema.yaml +++ b/elastalert/schema.yaml @@ -282,6 +282,8 @@ properties: slack_attach_kibana_discover_url: {type: boolean} slack_kibana_discover_color: {type: string} slack_kibana_discover_title: {type: string} + slack_footer: {type: string} + slack_footer_icon: {type: string} ### Mattermost mattermost_webhook_url: *arrayOfString diff --git a/tests/alerts_test.py b/tests/alerts_test.py index 3af230a1..3e1febf7 100644 --- a/tests/alerts_test.py +++ b/tests/alerts_test.py @@ -2749,6 +2749,56 @@ def test_slack_ca_certs(): assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) +def test_slack_footer(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'slack_webhook_url': 'http://please.dontgohere.slack', + 'slack_username_override': 'elastalert', + 'slack_footer': 'Elastic Alerts', + 'slack_footer_icon': 'http://footer.icon.url', + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = SlackAlerter(rule) + match = { + '@timestamp': '2016-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'elastalert', + 'channel': '', + 'icon_emoji': ':ghost:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['alert_subject'], + 'text': BasicMatchString(rule, match).__str__(), + 'mrkdwn_in': ['text', 'pretext'], + 'fields': [], + 'footer': 'Elastic Alerts', + 'footer_icon': 'http://footer.icon.url' + } + ], + 'text': '', + 'parse': 'none' + } + mock_post_request.assert_called_once_with( + rule['slack_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None, + verify=True, + timeout=10 + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + def test_http_alerter_with_payload(): rule = { 'name': 'Test HTTP Post Alerter With Payload',