Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add metric_agg_script to MetricAggregationRule #558

Merged
merged 4 commits into from
Nov 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
- None

## New features
- None
- Add metric_agg_script to MetricAggregationRule [#558](https://github.com/jertel/elastalert2/pull/558) - @dequis

## Other changes
- sphinx 4.2.0 to 4.3.0 and tzlocal==2.1 - [#561](https://github.com/jertel/elastalert2/pull/561) - @nsano-rururu
Expand Down
8 changes: 7 additions & 1 deletion docs/source/ruletypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1318,7 +1318,7 @@ default this is ``buffer_time``.
This rule requires:

``metric_agg_key``: This is the name of the field over which the metric value will be calculated. The underlying type of this field must be
supported by the specified aggregation type.
supported by the specified aggregation type. If using a scripted field via ``metric_agg_script``, this is the name for your scripted field

``metric_agg_type``: The type of metric aggregation to perform on the ``metric_agg_key`` field. This must be one of 'min', 'max', 'avg',
'sum', 'cardinality', 'value_count'.
Expand All @@ -1336,6 +1336,12 @@ Optional:
``query_key``: Group metric calculations by this field. For each unique value of the ``query_key`` field, the metric will be calculated and
evaluated separately against the threshold(s).

``metric_agg_script``: A `Painless` formatted script describing how to calculate your metric on-the-fly::

metric_agg_key: myScriptedMetric
metric_agg_script:
script: doc['field1'].value * doc['field2'].value

``min_doc_count``: The minimum number of events in the current window needed for an alert to trigger. Used in conjunction with ``query_key``,
this will only consider terms which in their last ``buffer_time`` had at least ``min_doc_count`` records. Default 1.

Expand Down
4 changes: 3 additions & 1 deletion elastalert/ruletypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,8 @@ def get_match_str(self, match):
return message

def generate_aggregation_query(self):
if self.rules.get('metric_agg_script'):
return {self.metric_key: {self.rules['metric_agg_type']: self.rules['metric_agg_script']}}
query = {self.metric_key: {self.rules['metric_agg_type']: {'field': self.rules['metric_agg_key']}}}
if self.rules['metric_agg_type'] in self.allowed_percent_aggregations:
query[self.metric_key][self.rules['metric_agg_type']]['percents'] = [self.rules['percentile_range']]
Expand Down Expand Up @@ -1175,7 +1177,7 @@ def __init__(self, *args):
self.rules['aggregation_query_element'] = self.generate_aggregation_query()

def generate_aggregation_query(self):
"""Lifted from MetricAggregationRule, added support for scripted fields"""
"""Lifted from MetricAggregationRule"""
if self.rules.get('metric_agg_script'):
return {self.metric_key: {self.rules['metric_agg_type']: self.rules['metric_agg_script']}}
query = {self.metric_key: {self.rules['metric_agg_type']: {'field': self.rules['metric_agg_key']}}}
Expand Down
16 changes: 16 additions & 0 deletions tests/rules_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,22 @@ def test_metric_aggregation_complex_query_key_bucket_interval():
assert rule.matches[1]['sub_qk'] == 'sub_qk_val1'


def test_metric_aggregation_scripted():
script_body = "doc['some_threshold'].value - doc['cpu_pct'].value"
rules = {'buffer_time': datetime.timedelta(minutes=5),
'timestamp_field': '@timestamp',
'metric_agg_type': 'avg',
'metric_agg_key': 'cpu_pct',
'metric_agg_script': {"script": script_body},
'min_threshold': 0.0}

rule = MetricAggregationRule(rules)
assert rule.rules['aggregation_query_element'] == {'metric_cpu_pct_avg': {'avg': {'script': script_body}}}

rule.check_matches(datetime.datetime.now(), None, {'metric_cpu_pct_avg': {'value': -0.5}})
assert rule.matches[0]['metric_cpu_pct_avg'] == -0.5


def test_percentage_match():
rules = {'match_bucket_filter': {'term': 'term_val'},
'buffer_time': datetime.timedelta(minutes=5),
Expand Down