Search in sources :

Example 11 with MergedAnomalyResultDTO

use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.

the class AnomalyReportGenerator method buildReport.

public void buildReport(List<MergedAnomalyResultDTO> anomalies, ThirdEyeAnomalyConfiguration configuration, AlertConfigDTO alertConfig) {
    String subject = "Thirdeye anomaly report : " + alertConfig.getName();
    long startTime = System.currentTimeMillis();
    long endTime = 0;
    for (MergedAnomalyResultDTO anomaly : anomalies) {
        if (anomaly.getStartTime() < startTime) {
            startTime = anomaly.getStartTime();
        }
        if (anomaly.getEndTime() > endTime) {
            endTime = anomaly.getEndTime();
        }
    }
    buildReport(startTime, endTime, anomalies, subject, configuration, false, alertConfig.getRecipients(), alertConfig.getFromAddress(), alertConfig.getName(), false);
}
Also used : MergedAnomalyResultDTO(com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO)

Example 12 with MergedAnomalyResultDTO

use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.

the class AnomalyReportGenerator method buildReport.

public void buildReport(long startTime, long endTime, List<MergedAnomalyResultDTO> anomalies, String subject, ThirdEyeAnomalyConfiguration configuration, boolean includeSentAnomaliesOnly, String emailRecipients, String fromEmail, String alertConfigName, boolean includeSummary) {
    if (anomalies == null || anomalies.size() == 0) {
        LOG.info("No anomalies found to send email, please check the parameters.. exiting");
    } else {
        Set<String> metrics = new HashSet<>();
        int alertedAnomalies = 0;
        int feedbackCollected = 0;
        int trueAlert = 0;
        int falseAlert = 0;
        int nonActionable = 0;
        List<AnomalyReportDTO> anomalyReportDTOList = new ArrayList<>();
        List<String> anomalyIds = new ArrayList<>();
        for (MergedAnomalyResultDTO anomaly : anomalies) {
            metrics.add(anomaly.getMetric());
            if (anomaly.getFeedback() != null) {
                feedbackCollected++;
                if (anomaly.getFeedback().getFeedbackType().equals(AnomalyFeedbackType.ANOMALY)) {
                    trueAlert++;
                } else if (anomaly.getFeedback().getFeedbackType().equals(AnomalyFeedbackType.NOT_ANOMALY)) {
                    falseAlert++;
                } else {
                    nonActionable++;
                }
            }
            String feedbackVal = getFeedback(anomaly.getFeedback() == null ? "Not Resolved" : "Resolved(" + anomaly.getFeedback().getFeedbackType().name() + ")");
            DateTimeZone dateTimeZone = Utils.getDataTimeZone(anomaly.getCollection());
            AnomalyReportDTO anomalyReportDTO = new AnomalyReportDTO(String.valueOf(anomaly.getId()), getAnomalyURL(anomaly, configuration.getDashboardHost()), String.format("%.2f", anomaly.getAvgBaselineVal()), String.format("%.2f", anomaly.getAvgCurrentVal()), getDimensionsString(anomaly.getDimensions()), String.format("%.2f hours (%s to %s) %s", getTimeDiffInHours(anomaly.getStartTime(), anomaly.getEndTime()), getDateString(anomaly.getStartTime(), dateTimeZone), getDateString(anomaly.getEndTime(), dateTimeZone), // duration
            getTimezoneString(dateTimeZone)), feedbackVal, anomaly.getFunction().getFunctionName(), // lift
            String.format("%+.2f%%", anomaly.getWeight() * 100), getLiftDirection(anomaly.getWeight()), anomaly.getMetric());
            if (anomaly.isNotified()) {
                alertedAnomalies++;
            }
            // include notified alerts only in the email
            if (includeSentAnomaliesOnly) {
                if (anomaly.isNotified()) {
                    anomalyReportDTOList.add(anomalyReportDTO);
                    anomalyIds.add(anomalyReportDTO.getAnomalyId());
                }
            } else {
                anomalyReportDTOList.add(anomalyReportDTO);
                anomalyIds.add(anomalyReportDTO.getAnomalyId());
            }
        }
        HtmlEmail email = new HtmlEmail();
        DateTimeZone timeZone = DateTimeZone.forTimeZone(AlertTaskRunnerV2.DEFAULT_TIME_ZONE);
        DataReportHelper.DateFormatMethod dateFormatMethod = new DataReportHelper.DateFormatMethod(timeZone);
        Map<String, Object> templateData = new HashMap<>();
        templateData.put("timeZone", timeZone);
        templateData.put("dateFormat", dateFormatMethod);
        templateData.put("startTime", startTime);
        templateData.put("endTime", endTime);
        templateData.put("anomalyCount", anomalies.size());
        templateData.put("metricsCount", metrics.size());
        templateData.put("notifiedCount", alertedAnomalies);
        templateData.put("feedbackCount", feedbackCollected);
        templateData.put("trueAlertCount", trueAlert);
        templateData.put("falseAlertCount", falseAlert);
        templateData.put("nonActionableCount", nonActionable);
        templateData.put("anomalyDetails", anomalyReportDTOList);
        templateData.put("alertConfigName", alertConfigName);
        templateData.put("includeSummary", includeSummary);
        templateData.put("reportGenerationTimeMillis", System.currentTimeMillis());
        templateData.put("dashboardHost", configuration.getDashboardHost());
        templateData.put("anomalyIds", Joiner.on(",").join(anomalyIds));
        boolean isSingleAnomalyEmail = false;
        String imgPath = null;
        if (anomalyReportDTOList.size() == 1) {
            isSingleAnomalyEmail = true;
            AnomalyReportDTO singleAnomaly = anomalyReportDTOList.get(0);
            subject = subject + " - " + singleAnomaly.getMetric();
            imgPath = EmailScreenshotHelper.takeGraphScreenShot(singleAnomaly.getAnomalyId(), configuration);
            String cid = "";
            try {
                cid = email.embed(new File(imgPath));
            } catch (Exception e) {
                LOG.error("Exception while embedding screenshot for anomaly {}", singleAnomaly.getAnomalyId(), e);
            }
            templateData.put("cid", cid);
        }
        buildEmailTemplateAndSendAlert(templateData, configuration.getSmtpConfiguration(), subject, emailRecipients, fromEmail, isSingleAnomalyEmail, email);
        if (StringUtils.isNotBlank(imgPath)) {
            try {
                Files.deleteIfExists(new File(imgPath).toPath());
            } catch (IOException e) {
                LOG.error("Exception in deleting screenshot {}", imgPath, e);
            }
        }
    }
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) HtmlEmail(org.apache.commons.mail.HtmlEmail) IOException(java.io.IOException) DateTimeZone(org.joda.time.DateTimeZone) IOException(java.io.IOException) MergedAnomalyResultDTO(com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO) File(java.io.File) HashSet(java.util.HashSet)

Example 13 with MergedAnomalyResultDTO

use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.

the class AnomalyReportGenerator method getAnomaliesForMetrics.

public List<MergedAnomalyResultDTO> getAnomaliesForMetrics(List<String> metrics, long startTime, long endTime) {
    List<MergedAnomalyResultDTO> anomalies = new ArrayList<>();
    LOG.info("fetching anomalies for metrics : " + metrics);
    for (String metric : metrics) {
        List<MetricConfigDTO> metricConfigDTOList = metricConfigManager.findByMetricName(metric);
        for (MetricConfigDTO metricConfigDTO : metricConfigDTOList) {
            List<MergedAnomalyResultDTO> results = anomalyResultManager.findByCollectionMetricTime(metricConfigDTO.getDataset(), metric, startTime, endTime, false);
            LOG.info("Found {} result for metric {}", results.size(), metric);
            anomalies.addAll(results);
        }
    }
    return anomalies;
}
Also used : MetricConfigDTO(com.linkedin.thirdeye.datalayer.dto.MetricConfigDTO) MergedAnomalyResultDTO(com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO) ArrayList(java.util.ArrayList)

Example 14 with MergedAnomalyResultDTO

use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.

the class AlertTaskRunnerV2 method sendAnomalyReport.

private void sendAnomalyReport() throws Exception {
    AlertConfigBean.EmailConfig emailConfig = alertConfig.getEmailConfig();
    if (emailConfig != null && emailConfig.getFunctionIds() != null) {
        List<Long> functionIds = alertConfig.getEmailConfig().getFunctionIds();
        List<MergedAnomalyResultDTO> mergedAnomaliesAllResults = new ArrayList<>();
        long lastNotifiedAnomaly = emailConfig.getAnomalyWatermark();
        for (Long functionId : functionIds) {
            List<MergedAnomalyResultDTO> resultsForFunction = anomalyMergedResultDAO.findByFunctionIdAndIdGreaterThan(functionId, lastNotifiedAnomaly);
            if (resultsForFunction != null && resultsForFunction.size() > 0) {
                mergedAnomaliesAllResults.addAll(resultsForFunction);
            }
            // fetch anomalies having id lesser than the watermark for the same function with notified = false & endTime > last one day
            // these anomalies are the ones that did not qualify filtration rule and got modified.
            // We should add these again so that these could be included in email if qualified through filtration rule
            List<MergedAnomalyResultDTO> filteredAnomalies = anomalyMergedResultDAO.findUnNotifiedByFunctionIdAndIdLesserThanAndEndTimeGreaterThanLastOneDay(functionId, lastNotifiedAnomaly);
            if (filteredAnomalies != null && filteredAnomalies.size() > 0) {
                mergedAnomaliesAllResults.addAll(filteredAnomalies);
            }
        }
        // apply filtration rule
        List<MergedAnomalyResultDTO> results = AlertFilterHelper.applyFiltrationRule(mergedAnomaliesAllResults, alertFilterFactory);
        if (results.isEmpty()) {
            LOG.info("Zero anomalies found, skipping sending email");
        } else {
            AnomalyReportGenerator.getInstance().buildReport(results, thirdeyeConfig, alertConfig);
            updateNotifiedStatus(results);
            // update anomaly watermark in alertConfig
            long lastNotifiedAlertId = emailConfig.getAnomalyWatermark();
            for (MergedAnomalyResultDTO anomalyResult : results) {
                if (anomalyResult.getId() > lastNotifiedAlertId) {
                    lastNotifiedAlertId = anomalyResult.getId();
                }
            }
            if (lastNotifiedAlertId != emailConfig.getAnomalyWatermark()) {
                alertConfig.getEmailConfig().setAnomalyWatermark(lastNotifiedAlertId);
                alertConfigDAO.update(alertConfig);
            }
        }
    }
}
Also used : AlertConfigBean(com.linkedin.thirdeye.datalayer.pojo.AlertConfigBean) MergedAnomalyResultDTO(com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO) ArrayList(java.util.ArrayList)

Example 15 with MergedAnomalyResultDTO

use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.

the class AlertTaskRunnerV2 method updateNotifiedStatus.

private void updateNotifiedStatus(List<MergedAnomalyResultDTO> mergedResults) {
    for (MergedAnomalyResultDTO mergedResult : mergedResults) {
        mergedResult.setNotified(true);
        anomalyMergedResultDAO.update(mergedResult);
    }
}
Also used : MergedAnomalyResultDTO(com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO)

Aggregations

MergedAnomalyResultDTO (com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO)61 ArrayList (java.util.ArrayList)24 AnomalyFunctionDTO (com.linkedin.thirdeye.datalayer.dto.AnomalyFunctionDTO)17 RawAnomalyResultDTO (com.linkedin.thirdeye.datalayer.dto.RawAnomalyResultDTO)17 Path (javax.ws.rs.Path)16 DimensionMap (com.linkedin.thirdeye.api.DimensionMap)11 GET (javax.ws.rs.GET)10 AnomalyFeedbackDTO (com.linkedin.thirdeye.datalayer.dto.AnomalyFeedbackDTO)9 HashMap (java.util.HashMap)9 DateTime (org.joda.time.DateTime)9 MetricTimeSeries (com.linkedin.thirdeye.api.MetricTimeSeries)8 IOException (java.io.IOException)8 ScalingFactor (com.linkedin.thirdeye.detector.metric.transfer.ScalingFactor)7 ExecutionException (java.util.concurrent.ExecutionException)7 TimeoutException (java.util.concurrent.TimeoutException)6 TimeGranularity (com.linkedin.thirdeye.api.TimeGranularity)5 POST (javax.ws.rs.POST)5 Pair (com.linkedin.pinot.pql.parsers.utils.Pair)4 AnomalyDetectionInputContext (com.linkedin.thirdeye.anomaly.detection.AnomalyDetectionInputContext)4 AnomaliesWrapper (com.linkedin.thirdeye.dashboard.resources.v2.pojo.AnomaliesWrapper)4