Skip to content

Commit

Permalink
Merge pull request #399 from iamxeph/feature_add_metric_format_string…
Browse files Browse the repository at this point in the history
…_to_metricaggregation

Adds metric_format_string config to Metric Aggregation rule
  • Loading branch information
jertel committed Aug 15, 2021
2 parents 46d1061 + 84eb7ab commit c5bd069
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
## New features
- [Kubernetes] Adding Image Pull Secret to Helm Chart - [#370](https://github.com/jertel/elastalert2/pull/370) - @robrankin
- Apply percentage_format_string to match_body percentage value; will appear in new percentage_formatted key - [#387](https://github.com/jertel/elastalert2/pull/387) - @iamxeph
- Add metric_format_string optional configuration for Metric Aggregation to format aggregated value - [#](https://github.com/jertel/elastalert2/pull/) - @iamxeph
- Add support for Kibana 7.14 for Kibana Discover - [#392](https://github.com/jertel/elastalert2/pull/392) - @nsano-rururu

## Other changes
Expand Down
4 changes: 4 additions & 0 deletions docs/source/ruletypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,10 @@ allign with the time elastalert runs, (This both avoid calculations on partial d
See: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html#_offset for a
more comprehensive explaination.

``metric_format_string``: An optional format string applies to the aggregated metric value in the alert match text and match_body. This adds 'metric_{metric_agg_key}_formatted' value to the match_body in addition to raw, unformatted 'metric_{metric_agg_key}' value so that you can use the values for ``alert_subject_args`` and ``alert_text_args``. Must be a valid python format string. Both format() and %-formatted syntax works. For example, "{:.2%}" will format '0.966666667' to '96.67%', and "%.2f" will format '0.966666667' to '0.97'.
See: https://docs.python.org/3.4/library/string.html#format-specification-mini-language


Spike Aggregation
~~~~~~~~~~~~~~~~~~

Expand Down
12 changes: 11 additions & 1 deletion elastalert/ruletypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1068,10 +1068,11 @@ def __init__(self, *args):
self.rules['aggregation_query_element'] = self.generate_aggregation_query()

def get_match_str(self, match):
metric_format_string = self.rules.get('metric_format_string', None)
message = 'Threshold violation, %s:%s %s (min: %s max : %s) \n\n' % (
self.rules['metric_agg_type'],
self.rules['metric_agg_key'],
match[self.metric_key],
self.format_string(metric_format_string, match[self.metric_key]) if metric_format_string else match[self.metric_key],
self.rules.get('min_threshold'),
self.rules.get('max_threshold')
)
Expand All @@ -1095,6 +1096,9 @@ def check_matches(self, timestamp, query_key, aggregation_data):
if self.crossed_thresholds(metric_val):
match = {self.rules['timestamp_field']: timestamp,
self.metric_key: metric_val}
metric_format_string = self.rules.get('metric_format_string', None)
if metric_format_string is not None:
match[self.metric_key +'_formatted'] = self.format_string(metric_format_string, metric_val)
if query_key is not None:
match = expand_string_into_dict(match, self.rules['query_key'], query_key)
self.add_match(match)
Expand Down Expand Up @@ -1136,6 +1140,12 @@ def crossed_thresholds(self, metric_value):
return True
return False

def format_string(self, format_config, target_value):
if (format_config.startswith('{')):
return format_config.format(target_value)
else:
return format_config % (target_value)


class SpikeMetricAggregationRule(BaseAggregationRule, SpikeRule):
""" A rule that matches when there is a spike in an aggregated event compared to its reference point """
Expand Down
18 changes: 18 additions & 0 deletions tests/rules_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,24 @@ def test_metric_aggregation():
rule.check_matches(datetime.datetime.now(), None, {'metric_cpu_pct_avg': {'value': 0.95}})
assert len(rule.matches) == 2

rule = MetricAggregationRule(rules)
rule.check_matches(datetime.datetime.now(), None, {'metric_cpu_pct_avg': {'value': 0.966666667}})
assert '0.966666667' in rule.get_match_str(rule.matches[0])
assert rule.matches[0]['metric_cpu_pct_avg'] == 0.966666667
assert 'metric_cpu_pct_avg_formatted' not in rule.matches[0]
rules['metric_format_string'] = '{:.2%}'
rule = MetricAggregationRule(rules)
rule.check_matches(datetime.datetime.now(), None, {'metric_cpu_pct_avg': {'value': 0.966666667}})
assert '96.67%' in rule.get_match_str(rule.matches[0])
assert rule.matches[0]['metric_cpu_pct_avg'] == 0.966666667
assert rule.matches[0]['metric_cpu_pct_avg_formatted'] == '96.67%'
rules['metric_format_string'] = '%.2f'
rule = MetricAggregationRule(rules)
rule.check_matches(datetime.datetime.now(), None, {'metric_cpu_pct_avg': {'value': 0.966666667}})
assert '0.97' in rule.get_match_str(rule.matches[0])
assert rule.matches[0]['metric_cpu_pct_avg'] == 0.966666667
assert rule.matches[0]['metric_cpu_pct_avg_formatted'] == '0.97'

rules['query_key'] = 'subdict'
rule = MetricAggregationRule(rules)
rule.check_matches(datetime.datetime.now(), 'qk_val', {'metric_cpu_pct_avg': {'value': 0.95}})
Expand Down

0 comments on commit c5bd069

Please sign in to comment.