Yelp / elastalert

Easy & Flexible Alerting With ElasticSearch
https://elastalert.readthedocs.org
Apache License 2.0
8k stars 1.73k forks source link

Not able to sent dynamic values as alertmanager_fields from custom ruletype #3283

Closed vicvinodvic closed 1 year ago

vicvinodvic commented 1 year ago

I have created a custom rule which alerts when particular category ids' API status has more than 90% failure. Below is the code, I want to send categoryid as alertmanager_fields , but its going null, please help me in fixing the issue Rule configuration alert:

I have tried below combination categoryid: "{{ match.categoryid }}" categoryid: "match.categoryid" categoryid: "match[categoryid]"

Custom Rule code from elastalert.ruletypes import RuleType from datetime import datetime, timedelta from jinja2 import Template

template_string = """

For Category {{ match['categoryid'] }}, more than {{ match['threshold'] }}% Rreq Failures

Total Txns : {{ match['total_transactions'] }} Failed Txns : {{ match['failed_transactions'] }}

"""

class RreqRule(RuleType):

def __init__(self, rule_config, *args, **kwargs):
    super(RreqRule, self).__init__(rule_config, *args, **kwargs)
    self.alerted_category = []
    self.rule_template = Template(template_string)
    self.start_time = datetime.utcnow() - timedelta(minutes=10)
    self.end_time = datetime.utcnow()

    # Get the failure rate threshold from the rule configuration file
    self.threshold = float(self.rules['threshold'])

# add_data will be called each time Elasticsearch is queried.
# data is a list of documents from Elasticsearch, sorted by timestamp,
# including all the fields that the config specifies with "include"
def add_data(self, data):
    # Extract the categoryid and transaction result from the data
    for document in data:
        categoryid = document['categoryid']
        api_status = document['business_context']['apistatus']

        self.rules.setdefault(categoryid, {'total_transactions': 0, 'failed_transactions': 0 })
        self.rules[categoryid]['total_transactions'] += 1
        if api_status != 'Y':
            self.rules[categoryid]['failed_transactions'] += 1

        # Calculate the failure rate for this categoryid
        total_transactions = self.rules[categoryid]['total_transactions']
        failed_transactions = self.rules[categoryid]['failed_transactions']
        failure_rate = float(failed_transactions) / float(total_transactions)
        # If the failure rate exceeds the threshold, trigger an alert
        if failure_rate >= self.threshold:

            if categoryid not in self.alerted_category:
                self.alerted_category.append(categoryid)
            self.add_match({
                'categoryid': categoryid,
                'threshold': self.threshold,
                'total_transactions': total_transactions,
                'failed_transactions': failed_transactions
            })
        else:
            print("------------Ignoring alert for categoryid :  ", categoryid)

def get_match_str(self, match):
    # Format the match string with the failure rate
    alert_body = self.rule_template.render(match=match)
    [match.pop(k) for k in list(match.keys()) if k != 'categoryid']
    self.rules['alertmanager_fields'] = {
        'categoryid': match['categoryid']
    }
    return alert_body

# garbage_collect is called indicating that ElastAlert 2 has already been run up to timestamp
# It is useful for knowing that there were no query results from Elasticsearch because
# add_data will not be called with an empty list
def garbage_collect(self, timestamp):
   for categoryid in self.alerted_category:
       self.alerted_category.remove(categoryid)
       self.rules[categoryid] = {'total_transactions': 0, 'failed_transactions': 0}
vicvinodvic commented 1 year ago

Using below Code resolved the Issue from elastalert.enhancements import BaseEnhancement

class PsdEnhancement(BaseEnhancement):

# The enhancement is run against every match
# The match is passed to the process function where it can be modified in any way
# ElastAlert 2 will do this for each enhancement linked to a rule
def process(self, match):
    self.rule['alertmanager_labels']['categoryid'] = match['categoryid']