Yelp/elastalert

Not able to sent dynamic values as alertmanager_fields from custom ruletype

vicvinodvic opened this issue · 1 comments

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:

  • "debug"
  • "alertmanager"
    alertmanager_alertname: "Test Custom rule"
    alertmanager_annotations:
    description: "Test Custom rule"
    summary: "Test Custom rule"
    alertmanager_hosts:
  • "https://"
    alertmanager_fields:
    categoryid: "{{ match[categoryid] }}"

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}

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']