diff --git a/CHANGELOG.md b/CHANGELOG.md index b8bda7ab..2fbce3e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - TBD ## New features -- TBD +- 'summary_table_type' property now supports 'html' format for aggregation tables - [#1260](https://github.com/jertel/elastalert2/pull/1260) - @jertel ## Other changes - [Helm] Expose minReadySeconds parameter to assist in detecting failed deployments - [#1243](https://github.com/jertel/elastalert2/pull/1243) - @alexku7 diff --git a/docs/source/ruletypes.rst b/docs/source/ruletypes.rst index 0bd6379c..4a28e8b0 100644 --- a/docs/source/ruletypes.rst +++ b/docs/source/ruletypes.rst @@ -464,7 +464,7 @@ This should result in 2 alerts: One containing alice's two events, sent at ``201 For aggregations, there can sometimes be a large number of documents present in the viewing medium (email, Jira ticket, etc..). If you set the ``summary_table_fields`` field, ElastAlert 2 will provide a summary of the specified fields from all the results. -The formatting style of the summary table can be switched between ``ascii`` (default) and ``markdown`` with parameter ``summary_table_type``. ``markdown`` might be the more suitable formatting for alerters supporting it like TheHive. +The formatting style of the summary table can be switched between ``ascii`` (default), ``markdown``, or ``html`` with parameter ``summary_table_type``. The maximum number of rows in the summary table can be limited with the parameter ``summary_table_max_rows``. @@ -823,7 +823,7 @@ summary_table_fields summary_table_type ^^^^^^^^^^^^^^^^^^^^ -``summary_table_type``: Either ``ascii`` or ``markdown``. Select the table type to use for the aggregation summary. Defaults to ``ascii`` for the classical text based table. +``summary_table_type``: One of: ``ascii`` or ``markdown`` or ``html``. Select the table type to use for the aggregation summary. Defaults to ``ascii`` for the classical text based table. summary_table_max_rows ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/elastalert/alerts.py b/elastalert/alerts.py index 1d0dd60d..793715df 100644 --- a/elastalert/alerts.py +++ b/elastalert/alerts.py @@ -4,6 +4,11 @@ import os from jinja2 import Template + +from prettytable import PrettyTable +from prettytable import MSWORD_FRIENDLY +from prettytable import ALL + from texttable import Texttable from elastalert.util import EAException, lookup_es_key @@ -297,6 +302,22 @@ def get_aggregation_summary_text(self, matches): markdown_row += '| ' + str(key) + ' ' text += markdown_row + '| ' + str(count) + ' |\n' text += '\n' + + elif summary_table_type == 'html': + # Portions of the following block of HTML formatting code was taken from + # an abandoned PR (https://github.com/jertel/elastalert2/pull/1227). + text_table = PrettyTable() + text_table.field_names = summary_table_fields_with_count + text_table.set_style(MSWORD_FRIENDLY) + text_table.border = True + text_table.header = True + text_table.hrules = ALL + text_table.vrules = ALL + text_table.header = True + text_table.format = True + for keys, count in match_aggregation.items(): + text_table.add_row([key for key in keys] + [count]) + text = text_table.get_html_string() # max_rows message if 'summary_table_max_rows' in self.rule: diff --git a/elastalert/schema.yaml b/elastalert/schema.yaml index 7651acbe..003e5157 100644 --- a/elastalert/schema.yaml +++ b/elastalert/schema.yaml @@ -272,7 +272,7 @@ properties: ### summary table summary_table_fields: {type: array, items: {type: string}} - summary_table_type: {type: string, enum: ['ascii', 'markdown']} + summary_table_type: {type: string, enum: ['ascii', 'html', 'markdown']} summary_table_max_rows: {type: integer, minimum: 0} summary_prefix: {type: string} summary_suffix: {type: string} diff --git a/requirements.txt b/requirements.txt index 26a894e1..3139a12f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,7 @@ Jinja2>=3.1.2 jira>=3.4.1 jsonpointer>=2.3 jsonschema>=4.17.3 +prettytable>=3.8.0 prison>=0.2.1 prometheus_client>=0.15.0 python-dateutil>=2.8.2 diff --git a/tests/alerts_test.py b/tests/alerts_test.py index 3cb27f4d..6e814a8f 100644 --- a/tests/alerts_test.py +++ b/tests/alerts_test.py @@ -245,6 +245,36 @@ def test_alert_aggregation_summary_markdown_table(): assert "| field_value | cde from match | 2 |" in summary_table +def test_alert_aggregation_summary_html_table(): + rule = { + 'name': 'test_rule', + 'type': mock_rule(), + 'owner': 'the_owner', + 'priority': 2, + 'alert_subject': 'A very long subject', + 'aggregation': 1, + 'summary_table_fields': ['field', 'abc'], + 'summary_table_type': 'html' + } + matches = [ + {'@timestamp': '2016-01-01', 'field': 'field_value', 'abc': 'abc from match', }, + {'@timestamp': '2016-01-01', 'field': 'field_value', 'abc': 'abc from match', }, + {'@timestamp': '2016-01-01', 'field': 'field_value', 'abc': 'abc from match', }, + {'@timestamp': '2016-01-01', 'field': 'field_value', 'abc': 'cde from match', }, + {'@timestamp': '2016-01-01', 'field': 'field_value', 'abc': 'cde from match', }, + ] + alert = Alerter(rule) + summary_table = str(alert.get_aggregation_summary_text(matches)) + assert '' in summary_table + assert 'field' in summary_table + assert 'abc' in summary_table + assert 'abc from match' in summary_table + assert '3' in summary_table + assert 'cde from match' in summary_table + assert '2' in summary_table + + def test_alert_aggregation_summary_default_table(): rule = { 'name': 'test_rule',