diff --git a/CHANGELOG.md b/CHANGELOG.md index f75a6837..e2ecb9e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - TBD ## New features -- TBD +- [Telegram] Added new telegram_thread_id setting for sending alerts to different threads of supergroup/forum. - [#1319](https://github.com/jertel/elastalert2/pull/1319) - @polshe-v ## Other changes - Update setup.py & requirements.txt & requirements-dev.txt - [#1316](https://github.com/jertel/elastalert2/pull/1316) - @nsano-rururu diff --git a/docs/source/ruletypes.rst b/docs/source/ruletypes.rst index 26709a44..64309e70 100644 --- a/docs/source/ruletypes.rst +++ b/docs/source/ruletypes.rst @@ -3688,6 +3688,8 @@ Optional: ``telegram_parse_mode``: The Telegram parsing mode, which determines the format of the alert text body. Possible values are ``markdown``, ``markdownV2``, ``html``. Defaults to ``markdown``. +``telegram_thread_id``: Unique identifier for the target thread of supergroup/forum using telegram message_thread_id (Optional, positive integer value, no default). + Example usage:: alert: diff --git a/elastalert/alerters/telegram.py b/elastalert/alerters/telegram.py index 48632537..18c543c3 100644 --- a/elastalert/alerters/telegram.py +++ b/elastalert/alerters/telegram.py @@ -23,6 +23,7 @@ def __init__(self, rule): self.telegram_proxy_login = self.rule.get('telegram_proxy_login', None) self.telegram_proxy_password = self.rule.get('telegram_proxy_pass', None) self.telegram_parse_mode = self.rule.get('telegram_parse_mode', 'markdown') + self.telegram_thread_id = self.rule.get('telegram_thread_id', None) def alert(self, matches): if self.telegram_parse_mode != 'html': @@ -49,7 +50,8 @@ def alert(self, matches): 'chat_id': self.telegram_room_id, 'text': body, 'parse_mode': self.telegram_parse_mode, - 'disable_web_page_preview': True + 'disable_web_page_preview': True, + 'message_thread_id': self.telegram_thread_id } try: diff --git a/elastalert/schema.yaml b/elastalert/schema.yaml index a41c775d..666d06b0 100644 --- a/elastalert/schema.yaml +++ b/elastalert/schema.yaml @@ -773,6 +773,7 @@ properties: telegram_proxy_login: {type: string} telegram_proxy_pass: {type: string} telegram_parse_mode: {type: string, enum: ['markdown', 'markdownV2', 'html']} + telegram_thread_id: {type: number} ### Tencent SMS tencent_sms_secret_id: {type: string} diff --git a/tests/alerters/telegram_test.py b/tests/alerters/telegram_test.py index 66d0a1a4..748c72bb 100644 --- a/tests/alerters/telegram_test.py +++ b/tests/alerters/telegram_test.py @@ -12,6 +12,46 @@ from elastalert.util import EAException +def test_telegram_thread_id(caplog): + caplog.set_level(logging.INFO) + rule = { + 'name': 'Test Telegram Rule', + 'type': 'any', + 'telegram_bot_token': 'xxxxx1', + 'telegram_room_id': 'xxxxx2', + 'telegram_thread_id': 2, + 'alert': [] + } + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = TelegramAlerter(rule) + match = { + '@timestamp': '2021-01-01T00:00:00', + 'somefield': 'foobarbaz' + } + with mock.patch('requests.post') as mock_post_request: + alert.alert([match]) + expected_data = { + 'chat_id': rule['telegram_room_id'], + 'text': '⚠ *Test Telegram Rule* ⚠ ```\nTest Telegram Rule\n\n@timestamp: 2021-01-01T00:00:00\nsomefield: foobarbaz\n ```', + 'parse_mode': 'markdown', + 'disable_web_page_preview': True, + 'message_thread_id': 2 + } + + mock_post_request.assert_called_once_with( + 'https://api.telegram.org/botxxxxx1/sendMessage', + data=mock.ANY, + headers={'content-type': 'application/json'}, + proxies=None, + auth=None + ) + + actual_data = json.loads(mock_post_request.call_args_list[0][1]['data']) + assert expected_data == actual_data + assert ('elastalert', logging.INFO, 'Alert sent to Telegram room xxxxx2') == caplog.record_tuples[0] + + def test_telegram_markdown(caplog): caplog.set_level(logging.INFO) rule = { @@ -34,7 +74,8 @@ def test_telegram_markdown(caplog): 'chat_id': rule['telegram_room_id'], 'text': '⚠ *Test Telegram Rule* ⚠ ```\nTest Telegram Rule\n\n@timestamp: 2021-01-01T00:00:00\nsomefield: foobarbaz\n ```', 'parse_mode': 'markdown', - 'disable_web_page_preview': True + 'disable_web_page_preview': True, + 'message_thread_id': None } mock_post_request.assert_called_once_with( @@ -73,7 +114,8 @@ def test_telegram_html(caplog): 'chat_id': rule['telegram_room_id'], 'text': '⚠ Test Telegram Rule ⚠ \nTest Telegram Rule\n\n@timestamp: 2021-01-01T00:00:00\nsomefield: foobarbaz\n', 'parse_mode': 'html', - 'disable_web_page_preview': True + 'disable_web_page_preview': True, + 'message_thread_id': None } mock_post_request.assert_called_once_with( @@ -113,7 +155,8 @@ def test_telegram_proxy(): 'chat_id': rule['telegram_room_id'], 'text': '⚠ *Test Telegram Rule* ⚠ ```\nTest Telegram Rule\n\n@timestamp: 2021-01-01T00:00:00\nsomefield: foobarbaz\n ```', 'parse_mode': 'markdown', - 'disable_web_page_preview': True + 'disable_web_page_preview': True, + 'message_thread_id': None } mock_post_request.assert_called_once_with( @@ -150,7 +193,8 @@ def test_telegram_text_maxlength(): 'text': '⚠ *Test Telegram Rule' + ('a' * 3979) + '\n⚠ *message was cropped according to telegram limits!* ⚠ ```', 'parse_mode': 'markdown', - 'disable_web_page_preview': True + 'disable_web_page_preview': True, + 'message_thread_id': None } mock_post_request.assert_called_once_with( @@ -275,7 +319,8 @@ def test_telegram_matchs(): '----------------------------------------\n' + ' ```', 'parse_mode': 'markdown', - 'disable_web_page_preview': True + 'disable_web_page_preview': True, + 'message_thread_id': None } mock_post_request.assert_called_once_with(