<commit_before>package com.pearson.statsagg.alerts;

import com.pearson.statsagg.database_objects.DatabaseObjectCommon;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import com.pearson.statsagg.database_objects.alerts.Alert;
import com.pearson.statsagg.database_objects.metric_group.MetricGroup;
import com.pearson.statsagg.database_objects.metric_group.MetricGroupsDao;
import com.pearson.statsagg.database_objects.notifications.NotificationGroup;
import com.pearson.statsagg.database_objects.notifications.NotificationGroupsDao;
import com.pearson.statsagg.globals.ApplicationConfiguration;
import com.pearson.statsagg.webui.StatsAggHtmlFramework;
import com.pearson.statsagg.utilities.EmailUtils;
import com.pearson.statsagg.utilities.StackTrace;
import com.pearson.statsagg.utilities.StringUtilities;
import java.util.Arrays;
import java.util.Collections;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.HtmlEmail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author <NAME>
 */
public class EmailThread implements Runnable  {
    
    private static final Logger logger = LoggerFactory.getLogger(EmailThread.class.getName());
    
    private final Alert alert_;
    private final int alertLevel_;
    private final List<String> metricKeys_;
    private final Map<String,BigDecimal> alertMetricValues_;  // k="{MetricKey}-{AlertId}"   example: "someMetric.example-55"
    private final Map<String,String> positiveAlertReasons_; // k=MetricMey, v=a reason why the alert was positive (ex "new data point detected")
    private final boolean isPositiveAlert_;
    private final boolean isResend_;
    private final String statsAggLocation_;
    
    private String subject_ = "";
    private String body_ = "";
    
    public EmailThread(Alert alert, int alertLevel, List<String> metricKeys, Map<String,BigDecimal> alertMetricValues, 
            Map<String,String> positiveAlertReasons, boolean isPositiveAlert, boolean isResend, String statsAggLocation) {
        this.alert_ = alert;
        this.alertLevel_ = alertLevel;
        this.metricKeys_ = metricKeys;
        this.alertMetricValues_ = alertMetricValues;
        this.positiveAlertReasons_ = positiveAlertReasons;
        this.isPositiveAlert_ = isPositiveAlert;
        this.isResend_ = isResend;
        this.statsAggLocation_ = statsAggLocation;
    }
    
    @Override
    public void run() {
        
        if (alert_ == null) {
            logger.warn("Alert cannot be null");
            return;
        }
        
        MetricGroupsDao metricGroupsDao = new MetricGroupsDao();
        MetricGroup metricGroup = metricGroupsDao.getMetricGroup(alert_.getMetricGroupId());
        
        buildAlertEmail(ApplicationConfiguration.getAlertMaxMetricsInEmail(), metricGroup);
        
        List<String> emailAddesses;
        if ((alertLevel_ == Alert.CAUTION) && !isPositiveAlert_) emailAddesses = getToEmailsAddressesForAlert(alert_.getCautionNotificationGroupId());
        else if ((alertLevel_ == Alert.CAUTION) && isPositiveAlert_) emailAddesses = getToEmailsAddressesForAlert(alert_.getCautionPositiveNotificationGroupId());
        else if ((alertLevel_ == Alert.DANGER) && !isPositiveAlert_) emailAddesses = getToEmailsAddressesForAlert(alert_.getDangerNotificationGroupId());
        else if ((alertLevel_ == Alert.DANGER) && isPositiveAlert_) emailAddesses = getToEmailsAddressesForAlert(alert_.getDangerPositiveNotificationGroupId());
        else emailAddesses = new ArrayList();
        
        if (ApplicationConfiguration.isAlertSendEmailEnabled() && !emailAddesses.isEmpty()) {
            sendEmail(emailAddesses, subject_, body_);
        }
    }
    
    public void buildAlertEmail(int numMetricKeysPerEmail, MetricGroup metricGroup) {
    
        if ((alert_ == null) || ((alertLevel_ != Alert.CAUTION) && (alertLevel_ != Alert.DANGER)) || (metricGroup == null)) {
            logger.error("Failed to create email alert message.");
            return;
        }
        
        String warningLevelString = null;
        if (alertLevel_ == Alert.CAUTION) warningLevelString = "Caution";
        else if (alertLevel_ == Alert.DANGER) warningLevelString = "Danger";    
                
        if (isPositiveAlert_) subject_ = "StatsAgg Positive Alert, " + warningLevelString + ", Name=\"" + alert_.getName() + "\"";
        else subject_ = "StatsAgg Alert, " + warningLevelString + ", Name=\"" + alert_.getName() + "\"";

        Calendar currentDateAndTime = Calendar.getInstance();
        SimpleDateFormat dateAndTimeFormat = new SimpleDateFormat("yyyy-MM-dd  h:mm:ss a  z");
        String formattedDateAndTime = dateAndTimeFormat.format(currentDateAndTime.getTime());
        
        String alertTriggeredAt = null;
        if (isResend_) alertTriggeredAt = alert_.getHumanReadable_AmountOfTimeAlertIsTriggered(alertLevel_, currentDateAndTime);
        
        StringBuilder body = new StringBuilder("<html>");
        
        if ((statsAggLocation_ != null) && !statsAggLocation_.isEmpty()) {
            body.append("<b>StatsAgg Server</b> = ").append("<a href=\"").append(statsAggLocation_).append("\">").append(statsAggLocation_).append("</a>").append("<br>");
        }
        
        if ((alertLevel_ == Alert.CAUTION) && (statsAggLocation_ != null) && !statsAggLocation_.isEmpty() && (alert_ != null) && (alert_.getName() != null)) {
            body.append("<b>Currently Triggered Metrics</b> = ").append("<a href=\"").append(statsAggLocation_).append("/AlertAssociations?Name=")
                    .append(StatsAggHtmlFramework.urlEncode(alert_.getName())).append("&Level=" + "Caution").append("\">");
            body.append("Triggered caution metrics").append("</a>").append("<br>");
        }
        
        if ((alertLevel_ == Alert.DANGER) && (statsAggLocation_ != null) && !statsAggLocation_.isEmpty() && (alert_ != null) && (alert_.getName() != null)) {
            body.append("<b>Currently Triggered Metrics</b> = ").append("<a href=\"").append(statsAggLocation_).append("/AlertAssociations?Name=")
                    .append(StatsAggHtmlFramework.urlEncode(alert_.getName())).append("&Level=" + "Danger").append("\">");
            body.append("Triggered danger metrics").append("</a>").append("<br>");
        }
        
        body.append("<b>Current Time</b> = ").append(formattedDateAndTime).append("<br>");
        if (alertTriggeredAt != null) body.append("<b>Alert Triggered Time</b> = ").append(alertTriggeredAt).append("<br>");
        body.append("<b>Alert Name</b> = ").append(StatsAggHtmlFramework.htmlEncode(alert_.getName())).append("<br>");
        
        body.append("<b>Alert Description</b> = ");
        if (alert_.getDescription() != null) body.append(StatsAggHtmlFramework.htmlEncode(alert_.getDescription()).replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;")).append("<br>");
        else body.append("<br>");
        
        body.append("<b>Metric Group Name</b> = ");
        if (metricGroup.getName() != null) body.append(StatsAggHtmlFramework.htmlEncode(metricGroup.getName())).append("<br>");
        else body.append("<br>");
        
        body.append("<b>Metric Group Description</b> = ");
        if (metricGroup.getDescription() != null) body.append(StatsAggHtmlFramework.htmlEncode(metricGroup.getDescription()).replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;")).append("<br><br>");
        else body.append("<br>");
        
        if (isPositiveAlert_) {
            body.append("<b>No metrics associated with the metric group \"").append(StatsAggHtmlFramework.htmlEncode(metricGroup.getName()))
                    .append("\" meet the following criteria:</b>").append("<br>");
        }<commit_msg>add metric group tags to email output<commit_after>package com.pearson.statsagg.alerts;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import com.pearson.statsagg.database_objects.alerts.Alert;
import com.pearson.statsagg.database_objects.metric_group.MetricGroup;
import com.pearson.statsagg.database_objects.metric_group.MetricGroupsDao;
import com.pearson.statsagg.database_objects.metric_group_tags.MetricGroupTag;
import com.pearson.statsagg.database_objects.metric_group_tags.MetricGroupTagsDao;
import com.pearson.statsagg.database_objects.notifications.NotificationGroup;
import com.pearson.statsagg.database_objects.notifications.NotificationGroupsDao;
import com.pearson.statsagg.globals.ApplicationConfiguration;
import com.pearson.statsagg.webui.StatsAggHtmlFramework;
import com.pearson.statsagg.utilities.EmailUtils;
import com.pearson.statsagg.utilities.StackTrace;
import com.pearson.statsagg.utilities.StringUtilities;
import java.util.Arrays;
import java.util.Collections;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.HtmlEmail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author <NAME>
 */
public class EmailThread implements Runnable  {
    
    private static final Logger logger = LoggerFactory.getLogger(EmailThread.class.getName());
    
    private final Alert alert_;
    private final int alertLevel_;
    private final List<String> metricKeys_;
    private final Map<String,BigDecimal> alertMetricValues_;  // k="{MetricKey}-{AlertId}"   example: "someMetric.example-55"
    private final Map<String,String> positiveAlertReasons_; // k=MetricMey, v=a reason why the alert was positive (ex "new data point detected")
    private final boolean isPositiveAlert_;
    private final boolean isResend_;
    private final String statsAggLocation_;
    
    private String subject_ = "";
    private String body_ = "";
    
    public EmailThread(Alert alert, int alertLevel, List<String> metricKeys, Map<String,BigDecimal> alertMetricValues, 
            Map<String,String> positiveAlertReasons, boolean isPositiveAlert, boolean isResend, String statsAggLocation) {
        this.alert_ = alert;
        this.alertLevel_ = alertLevel;
        this.metricKeys_ = metricKeys;
        this.alertMetricValues_ = alertMetricValues;
        this.positiveAlertReasons_ = positiveAlertReasons;
        this.isPositiveAlert_ = isPositiveAlert;
        this.isResend_ = isResend;
        this.statsAggLocation_ = statsAggLocation;
    }
    
    @Override
    public void run() {
        
        if (alert_ == null) {
            logger.warn("Alert cannot be null");
            return;
        }
        
        MetricGroupsDao metricGroupsDao = new MetricGroupsDao();
        MetricGroup metricGroup = metricGroupsDao.getMetricGroup(alert_.getMetricGroupId());
        
        MetricGroupTagsDao metricGroupTagsDao = new MetricGroupTagsDao();
        List<MetricGroupTag> metricGroupTags = metricGroupTagsDao.getMetricGroupTagsByMetricGroupId(alert_.getMetricGroupId());
        
        buildAlertEmail(ApplicationConfiguration.getAlertMaxMetricsInEmail(), metricGroup, metricGroupTags);
        
        List<String> emailAddesses;
        if ((alertLevel_ == Alert.CAUTION) && !isPositiveAlert_) emailAddesses = getToEmailsAddressesForAlert(alert_.getCautionNotificationGroupId());
        else if ((alertLevel_ == Alert.CAUTION) && isPositiveAlert_) emailAddesses = getToEmailsAddressesForAlert(alert_.getCautionPositiveNotificationGroupId());
        else if ((alertLevel_ == Alert.DANGER) && !isPositiveAlert_) emailAddesses = getToEmailsAddressesForAlert(alert_.getDangerNotificationGroupId());
        else if ((alertLevel_ == Alert.DANGER) && isPositiveAlert_) emailAddesses = getToEmailsAddressesForAlert(alert_.getDangerPositiveNotificationGroupId());
        else emailAddesses = new ArrayList();
        
        if (ApplicationConfiguration.isAlertSendEmailEnabled() && !emailAddesses.isEmpty()) {
            sendEmail(emailAddesses, subject_, body_);
        }
    }
    
    public void buildAlertEmail(int numMetricKeysPerEmail, MetricGroup metricGroup, List<MetricGroupTag> metricGroupTags) {
    
        if ((alert_ == null) || ((alertLevel_ != Alert.CAUTION) && (alertLevel_ != Alert.DANGER)) || (metricGroup == null)) {
            logger.error("Failed to create email alert message.");
            return;
        }
        
        String warningLevelString = null;
        if (alertLevel_ == Alert.CAUTION) warningLevelString = "Caution";
        else if (alertLevel_ == Alert.DANGER) warningLevelString = "Danger";    
                
        if (isPositiveAlert_) subject_ = "StatsAgg Positive Alert, " + warningLevelString + ", Name=\"" + alert_.getName() + "\"";
        else subject_ = "StatsAgg Alert, " + warningLevelString + ", Name=\"" + alert_.getName() + "\"";

        Calendar currentDateAndTime = Calendar.getInstance();
        SimpleDateFormat dateAndTimeFormat = new SimpleDateFormat("yyyy-MM-dd  h:mm:ss a  z");
        String formattedDateAndTime = dateAndTimeFormat.format(currentDateAndTime.getTime());
        
        String alertTriggeredAt = null;
        if (isResend_) alertTriggeredAt = alert_.getHumanReadable_AmountOfTimeAlertIsTriggered(alertLevel_, currentDateAndTime);
        
        StringBuilder body = new StringBuilder("<html>");
        
        if ((statsAggLocation_ != null) && !statsAggLocation_.isEmpty()) {
            body.append("<b>StatsAgg Server</b> = ").append("<a href=\"").append(statsAggLocation_).append("\">").append(statsAggLocation_).append("</a>").append("<br>");
        }
        
        if ((alertLevel_ == Alert.CAUTION) && (statsAggLocation_ != null) && !statsAggLocation_.isEmpty() && (alert_ != null) && (alert_.getName() != null)) {
            body.append("<b>Currently Triggered Metrics</b> = ").append("<a href=\"").append(statsAggLocation_).append("/AlertAssociations?Name=")
                    .append(StatsAggHtmlFramework.urlEncode(alert_.getName())).append("&Level=" + "Caution").append("\">");
            body.append("Triggered caution metrics").append("</a>").append("<br>");
        }
        
        if ((alertLevel_ == Alert.DANGER) && (statsAggLocation_ != null) && !statsAggLocation_.isEmpty() && (alert_ != null) && (alert_.getName() != null)) {
            body.append("<b>Currently Triggered Metrics</b> = ").append("<a href=\"").append(statsAggLocation_).append("/AlertAssociations?Name=")
                    .append(StatsAggHtmlFramework.urlEncode(alert_.getName())).append("&Level=" + "Danger").append("\">");
            body.append("Triggered danger metrics").append("</a>").append("<br>");
        }
        
        body.append("<b>Current Time</b> = ").append(formattedDateAndTime).append("<br>");
        if (alertTriggeredAt != null) body.append("<b>Alert Triggered Time</b> = ").append(alertTriggeredAt).append("<br>");
        body.append("<b>Alert Name</b> = ").append(StatsAggHtmlFramework.htmlEncode(alert_.getName())).append("<br>");
        
        body.append("<b>Alert Description</b> = ");
        if (alert_.getDescription() != null) body.append(StatsAggHtmlFramework.htmlEncode(alert_.getDescription()).replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;")).append("<br>");
        else body.append("<br>");
        
        body.append("<b>Metric Group Name</b> = ");
        if (metricGroup.getName() != null) body.append(StatsAggHtmlFramework.htmlEncode(metricGroup.getName())).append("<br>");
        else body.append("<br>");
        
        body.append("<b>Metric Group Description</b> = ");
        if (metricGroup.getDescription() != null) body.append(StatsAggHtmlFramework.htmlEncode(metricGroup.getDescription()).replaceAll("\n", "<br>&nbsp;&nbsp;&nbsp;"));
        
        if ((metricGroupTags == null) || metricGroupTags.isEmpty()) body.append("<br><br>");
        else body.append("<br>");
        
        if ((metricGroupTags != null) && !metricGroupTags.isEmpty()) {
            body.append("<b>Tags</b> = ");
            
            for (MetricGroupTag metricGroupTag : metricGroupTags) {
                if ((metricGroupTag != null) && (metricGroupTag.getTag() != null) && !metricGroupTag.getTag().trim().isEmpty()) {
                    body.append("<u>").append(StatsAggHtmlFramework.htmlEncode(metricGroupTag.getTag().trim())).append("</u>&nbsp;");
                }
            }
            
            body.append("<br><br>");
        }
        
        if (isPositiveAlert_) {
            body.append("<b>No metrics associated with the metric group \"").append(StatsAggHtmlFramework.htmlEncode(metricGroup.getName()))
                    .append("\" meet the following criteria:</b>").append("<br>");
        }
{'fraction_non_alphanumeric': 0.1368402239961873, 'fraction_numerical': 0.0004765876325509353, 'mean_word_length': 3.6411390655239146, 'pattern_counts': {'":': 0, '<': 113, '<?xml version=': 0, '>': 113, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5393555', 'n_tokens_mistral': 4783, 'n_tokens_neox': 4612, 'n_words': 824}