From 1d050d090bc8e983400a79563596640130964ba6 Mon Sep 17 00:00:00 2001 From: nsano-rururu Date: Mon, 24 May 2021 01:46:49 +0900 Subject: [PATCH 1/2] Add support for RocketChat --- docs/source/elastalert.rst | 1 + docs/source/ruletypes.rst | 40 +++ elastalert/alerters/rocketchat.py | 98 +++++ elastalert/loaders.py | 5 +- elastalert/schema.yaml | 9 + tests/alerters/rocketchat_test.py | 577 ++++++++++++++++++++++++++++++ 6 files changed, 729 insertions(+), 1 deletion(-) create mode 100644 elastalert/alerters/rocketchat.py create mode 100644 tests/alerters/rocketchat_test.py diff --git a/docs/source/elastalert.rst b/docs/source/elastalert.rst index ba260b33..b315f321 100755 --- a/docs/source/elastalert.rst +++ b/docs/source/elastalert.rst @@ -48,6 +48,7 @@ Currently, we have support built in for these alert types: - OpsGenie - PagerDuty - PagerTree +- RocketChat - Squadcast - ServiceNow - Slack diff --git a/docs/source/ruletypes.rst b/docs/source/ruletypes.rst index 35a4247b..c96ae776 100644 --- a/docs/source/ruletypes.rst +++ b/docs/source/ruletypes.rst @@ -2371,6 +2371,46 @@ Example usage:: - "pagertree" pagertree_integration_url: "PagerTree Integration URL" +RocketChat +~~~~~~~~~~ + +RocketChat alerter will send a notification to a predefined channel. The body of the notification is formatted the same as with other alerters. +https://developer.rocket.chat/api/rest-api/methods/chat/postmessage + +The alerter requires the following option: + +``rocket_chat_webhook_url``: The webhook URL that includes your auth data and the ID of the channel (room) you want to post to. You can use a list of URLs to send to multiple channels. + +Optional: + +``rocket_chat_username_override``: By default RocketChat will use username defined in Integration when posting to the channel. Use this option to change it (free text). + +``rocket_chat_channel_override``: Incoming webhooks have a default channel, but it can be overridden. A public channel can be specified “#other-channel”, and a Direct Message with “@username”. + +``rocket_chat_emoji_override``: By default ElastAlert will use the :ghost: emoji when posting to the channel. You can use a different emoji per +ElastAlert rule. Any Apple emoji can be used, see http://emojipedia.org/apple/ . If rocket_chat_icon_url_override parameter is provided, emoji is ignored. + +``rocket_chat_msg_color``: By default the alert will be posted with the ‘danger’ color. You can also use ‘good’ or ‘warning’ colors. + +``rocket_chat_text_string``: Notification message you want to add. + +``rocket_chat_proxy``: By default ElastAlert will not use a network proxy to send notifications to RocketChat. Set this option using ``hostname:port`` if you need to use a proxy. + +``slack_alert_fields``: You can add additional fields to your RocketChat alerts using this field. Specify the title using `title` and a value for the field using `value`. Additionally you can specify whether or not this field should be a `short` field using `short: true`. + +Example rocket_chat_alert_fields:: + + rocket_chat_alert_fields: + - title: Host + value: monitor.host + short: true + - title: Status + value: monitor.status + short: true + - title: Zone + value: beat.name + short: true + Squadcast ~~~~~~~~~ diff --git a/elastalert/alerters/rocketchat.py b/elastalert/alerters/rocketchat.py new file mode 100644 index 00000000..5b86ce5f --- /dev/null +++ b/elastalert/alerters/rocketchat.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +import copy +import json +import requests +from requests.exceptions import RequestException +import warnings + +from ..alerts import Alerter, DateTimeEncoder +from ..util import EAException +from ..util import elastalert_logger +from ..util import lookup_es_key + + +class RocketChatAlerter(Alerter): + """ Creates a RocketChat notification for each alert """ + required_options = set(['rocket_chat_webhook_url']) + + def __init__(self, rule): + super(RocketChatAlerter, self).__init__(rule) + self.rocket_chat_webhook_url = self.rule['rocket_chat_webhook_url'] + if isinstance(self.rocket_chat_webhook_url, str): + self.rocket_chat_webhook_url = [self.rocket_chat_webhook_url] + self.rocket_chat_proxy = self.rule.get('rocket_chat_proxy', None) + + self.rocket_chat_username_override = self.rule.get('rocket_chat_username_override', 'elastalert2') + self.rocket_chat_channel_override = self.rule.get('rocket_chat_channel_override', '') + if isinstance(self.rocket_chat_channel_override, str): + self.rocket_chat_channel_override = [self.rocket_chat_channel_override] + self.rocket_chat_emoji_override = self.rule.get('rocket_chat_emoji_override', ':ghost:') + self.rocket_chat_msg_color = self.rule.get('rocket_chat_msg_color', 'danger') + self.rocket_chat_text_string = self.rule.get('rocket_chat_text_string', '') + self.rocket_chat_alert_fields = self.rule.get('rocket_chat_alert_fields', '') + + def format_body(self, body): + return body + + def get_aggregation_summary_text__maximum_width(self): + width = super(RocketChatAlerter, self).get_aggregation_summary_text__maximum_width() + + # Reduced maximum width for prettier Slack display. + return min(width, 75) + + def get_aggregation_summary_text(self, matches): + text = super(RocketChatAlerter, self).get_aggregation_summary_text(matches) + if text: + text = '```\n{0}```\n'.format(text) + return text + + def populate_fields(self, matches): + alert_fields = [] + for arg in self.rocket_chat_alert_fields: + arg = copy.copy(arg) + arg['value'] = lookup_es_key(matches[0], arg['value']) + alert_fields.append(arg) + return alert_fields + + def alert(self, matches): + body = self.create_alert_body(matches) + body = self.format_body(body) + headers = {'content-type': 'application/json'} + proxies = {'https': self.rocket_chat_proxy} if self.rocket_chat_proxy else None + payload = { + 'username': self.rocket_chat_username_override, + 'text': self.rocket_chat_text_string, + 'attachments': [ + { + 'color': self.rocket_chat_msg_color, + 'title': self.create_title(matches), + 'text': body, + 'fields': [] + } + ] + } + + # if we have defined fields, populate noteable fields for the alert + if self.rocket_chat_alert_fields != '': + payload['attachments'][0]['fields'] = self.populate_fields(matches) + + if self.rocket_chat_emoji_override != '': + payload['emoji'] = self.rocket_chat_emoji_override + + for url in self.rocket_chat_webhook_url: + for channel_override in self.rocket_chat_channel_override: + try: + payload['channel'] = channel_override + response = requests.post( + url, data=json.dumps(payload, cls=DateTimeEncoder), + headers=headers, + proxies=proxies) + warnings.resetwarnings() + response.raise_for_status() + except RequestException as e: + raise EAException("Error posting to Rocket.Chat: %s" % e) + elastalert_logger.info("Alert sent to Rocket.Chat") + + def get_info(self): + return {'type': 'rocketchat', + 'rocket_chat_username_override': self.rocket_chat_username_override} diff --git a/elastalert/loaders.py b/elastalert/loaders.py index 60824ba6..ef074b3c 100644 --- a/elastalert/loaders.py +++ b/elastalert/loaders.py @@ -32,6 +32,8 @@ import elastalert.alerters.victorops import elastalert.dingtalk import elastalert.thehive +import elastalert.alerters.rocketchat + from . import alerts from . import enhancements from . import ruletypes @@ -114,7 +116,8 @@ class RulesLoader(object): 'dingtalk': elastalert.dingtalk.DingTalkAlerter, 'chatwork': elastalert.alerters.chatwork.ChatworkAlerter, 'datadog': elastalert.alerters.datadog.DatadogAlerter, - 'ses': elastalert.alerters.ses.SesAlerter + 'ses': elastalert.alerters.ses.SesAlerter, + 'rocketchat': elastalert.alerters.rocketchat.RocketChatAlerter } # A partial ordering of alert types. Relative order will be preserved in the resulting alerts list diff --git a/elastalert/schema.yaml b/elastalert/schema.yaml index 0d911f70..33aee274 100644 --- a/elastalert/schema.yaml +++ b/elastalert/schema.yaml @@ -457,6 +457,15 @@ properties: pagertree_integration_url: {type: string} pagertree_proxy: {type: string} + ### RocketChat + rocket_chat_webhook_url: *arrayOfString + rocket_chat_username_override: {type: string} + rocket_chat_channel_override: {type: string} + rocket_chat_emoji_override: {type: string} + rocket_chat_msg_color: {enum: [good, warning, danger]} + rocket_chat_text_string: {type: string} + rocket_chat_proxy: {type: string} + ### ServiceNow servicenow_rest_url: {type: string} username: {type: string} diff --git a/tests/alerters/rocketchat_test.py b/tests/alerters/rocketchat_test.py new file mode 100644 index 00000000..81335090 --- /dev/null +++ b/tests/alerters/rocketchat_test.py @@ -0,0 +1,577 @@ +import json + +import mock +import pytest +from requests import RequestException + +from elastalert.alerters.rocketchat import RocketChatAlerter +from elastalert.alerts import BasicMatchString +from elastalert.loaders import FileRulesLoader +from elastalert.util import EAException + + +def test_rocketchat_uses_custom_title(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': 'http://please.dontgohere.rocketchat', + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'elastalert2', + 'channel': '', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['alert_subject'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': '' + } + mock_post_request.assert_called_once_with( + rule['rocket_chat_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + +def test_rocketchat_uses_rule_name_when_custom_title_is_not_provided(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': ['http://please.dontgohere.rocketchat'], + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'elastalert2', + 'channel': '', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['name'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': '' + } + mock_post_request.assert_called_once_with( + rule['rocket_chat_webhook_url'][0], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + +def test_rocketchat_username_override(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': 'http://please.dontgohere.rocketchat', + 'rocket_chat_username_override': 'test elastalert', + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'test elastalert', + 'channel': '', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['alert_subject'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': '' + } + mock_post_request.assert_called_once_with( + rule['rocket_chat_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + +def test_rocketchat_chat_channel(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': ['http://please.dontgohere.rocketchat'], + 'rocket_chat_channel_override': '#test-alert', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'elastalert2', + 'channel': '#test-alert', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['name'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': '' + } + mock_post_request.assert_called_once_with( + rule['rocket_chat_webhook_url'][0], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + +def test_rocketchat_uses_list_of_custom_rocket_chat_channel(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': ['http://please.dontgohere.rocketchat'], + 'rocket_chat_channel_override': ['#test-alert', '#test-alert2'], + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data1 = { + 'username': 'elastalert2', + 'channel': '#test-alert', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['name'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': '' + } + expected_data2 = { + 'username': 'elastalert2', + 'channel': '#test-alert2', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['name'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': '' + } + mock_post_request.assert_called_with( + rule['rocket_chat_webhook_url'][0], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None + ) + assert expected_data1 == json.loads(mock_post_request.call_args_list[0][1]['data']) + assert expected_data2 == json.loads(mock_post_request.call_args_list[1][1]['data']) + + +def test_rocketchat_emoji_override(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': ['http://please.dontgohere.rocketchat'], + 'rocket_chat_emoji_override': ':shushing_face:', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'elastalert2', + 'channel': '', + 'emoji': ':shushing_face:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['name'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': '' + } + mock_post_request.assert_called_once_with( + rule['rocket_chat_webhook_url'][0], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + +def test_rocketchat_msg_color_good(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': 'http://please.dontgohere.rocketchat', + 'rocket_chat_username_override': 'elastalert2', + 'rocket_chat_msg_color': 'good', + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'elastalert2', + 'channel': '', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'good', + 'title': rule['alert_subject'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': '' + } + mock_post_request.assert_called_once_with( + rule['rocket_chat_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + +def test_rocketchat_msg_color_warning(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': 'http://please.dontgohere.rocketchat', + 'rocket_chat_username_override': 'elastalert2', + 'rocket_chat_msg_color': 'warning', + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'elastalert2', + 'channel': '', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'warning', + 'title': rule['alert_subject'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': '' + } + mock_post_request.assert_called_once_with( + rule['rocket_chat_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + +def test_rocketchat_text_string(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': 'http://please.dontgohere.rocketchat', + 'rocket_chat_username_override': 'elastalert2', + 'rocket_chat_text_string': 'text str', + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'elastalert2', + 'channel': '', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['alert_subject'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': 'text str' + } + mock_post_request.assert_called_once_with( + rule['rocket_chat_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + +def test_rocketchat_proxy(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': 'http://please.dontgohere.rocketchat', + 'rocket_chat_proxy': 'http://proxy.url', + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'elastalert2', + 'channel': '', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['alert_subject'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': [] + } + ], + 'text': '' + } + mock_post_request.assert_called_once_with( + rule['rocket_chat_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies={'https': rule['rocket_chat_proxy']} + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + +def test_rocketchat_alert_fields(): + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': 'http://please.dontgohere.rocketchat', + 'rocket_chat_username_override': 'elastalert2', + 'rocket_chat_alert_fields': [ + { + 'title': 'Host', + 'value': 'somefield', + 'short': 'true' + }, + { + 'title': 'Sensors', + 'value': '@timestamp', + 'short': 'true' + } + ], + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + + expected_data = { + 'username': 'elastalert2', + 'channel': '', + 'emoji': ':ghost:', + 'attachments': [ + { + 'color': 'danger', + 'title': rule['alert_subject'], + 'text': BasicMatchString(rule, match).__str__(), + 'fields': + [ + { + 'short': 'true', + 'title': 'Host', + 'value': 'foobarbaz' + }, + { + 'short': 'true', + 'title': 'Sensors', + 'value': '2021-01-01T00:00:00' + } + ], + } + ], + 'text': '' + } + mock_post_request.assert_called_once_with( + rule['rocket_chat_webhook_url'], + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None + ) + assert expected_data == json.loads(mock_post_request.call_args_list[0][1]['data']) + + +def test_rocketchat_required_options_key_error(): + try: + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post'): + alert.alert([match]) + except KeyError: + assert True + + +def test_rocketchat_msg_color_key_error(): + try: + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': 'http://please.dontgohere.rocketchat', + 'rocket_chat_msg_color': 'abc', + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post'): + alert.alert([match]) + except KeyError: + assert True + + +def test_rocketchat_ea_exception(): + try: + rule = { + 'name': 'Test Rule', + 'type': 'any', + 'rocket_chat_webhook_url': 'http://please.dontgohere.rocketchat', + 'rocket_chat_username_override': 'elastalert2', + 'rocket_chat_msg_pretext': 'pretext value', + 'alert_subject': 'Cool subject', + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = RocketChatAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + mock_run = mock.MagicMock(side_effect=RequestException) + with mock.patch('requests.post', mock_run), pytest.raises(RequestException): + alert.alert([match]) + except EAException: + assert True From 2a7af8f6a453e57f046efabda1f312b06274c5ed Mon Sep 17 00:00:00 2001 From: Naoyuki Sano Date: Mon, 24 May 2021 01:57:08 +0900 Subject: [PATCH 2/2] Update ruletypes.rst --- docs/source/ruletypes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/ruletypes.rst b/docs/source/ruletypes.rst index c96ae776..79d7f005 100644 --- a/docs/source/ruletypes.rst +++ b/docs/source/ruletypes.rst @@ -2396,7 +2396,7 @@ ElastAlert rule. Any Apple emoji can be used, see http://emojipedia.org/apple/ . ``rocket_chat_proxy``: By default ElastAlert will not use a network proxy to send notifications to RocketChat. Set this option using ``hostname:port`` if you need to use a proxy. -``slack_alert_fields``: You can add additional fields to your RocketChat alerts using this field. Specify the title using `title` and a value for the field using `value`. Additionally you can specify whether or not this field should be a `short` field using `short: true`. +```rocket_chat_alert_fields``: You can add additional fields to your RocketChat alerts using this field. Specify the title using `title` and a value for the field using `value`. Additionally you can specify whether or not this field should be a `short` field using `short: true`. Example rocket_chat_alert_fields::