use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.
the class AnomalyResource method viewMergedAnomaliesInRange.
// View merged anomalies for collection
@GET
@Path("/anomalies/view")
public List<MergedAnomalyResultDTO> viewMergedAnomaliesInRange(@NotNull @QueryParam("dataset") String dataset, @QueryParam("startTimeIso") String startTimeIso, @QueryParam("endTimeIso") String endTimeIso, @QueryParam("metric") String metric, @QueryParam("dimensions") String exploredDimensions, @DefaultValue("true") @QueryParam("applyAlertFilter") boolean applyAlertFiler) {
if (StringUtils.isBlank(dataset)) {
throw new IllegalArgumentException("dataset is a required query param");
}
DateTime endTime = DateTime.now();
if (StringUtils.isNotEmpty(endTimeIso)) {
endTime = ISODateTimeFormat.dateTimeParser().parseDateTime(endTimeIso);
}
DateTime startTime = endTime.minusDays(7);
if (StringUtils.isNotEmpty(startTimeIso)) {
startTime = ISODateTimeFormat.dateTimeParser().parseDateTime(startTimeIso);
}
List<MergedAnomalyResultDTO> anomalyResults = new ArrayList<>();
try {
if (StringUtils.isNotBlank(exploredDimensions)) {
// Decode dimensions map from request, which may contain encode symbols such as "%20D", etc.
exploredDimensions = URLDecoder.decode(exploredDimensions, UTF8);
try {
// Ensure the dimension names are sorted in order to match the string in backend database
DimensionMap sortedDimensions = OBJECT_MAPPER.readValue(exploredDimensions, DimensionMap.class);
exploredDimensions = OBJECT_MAPPER.writeValueAsString(sortedDimensions);
} catch (IOException e) {
LOG.warn("exploreDimensions may not be sorted because failed to read it as a json string: {}", e.toString());
}
}
boolean loadRawAnomalies = false;
if (StringUtils.isNotBlank(metric)) {
if (StringUtils.isNotBlank(exploredDimensions)) {
anomalyResults = anomalyMergedResultDAO.findByCollectionMetricDimensionsTime(dataset, metric, exploredDimensions, startTime.getMillis(), endTime.getMillis(), loadRawAnomalies);
} else {
anomalyResults = anomalyMergedResultDAO.findByCollectionMetricTime(dataset, metric, startTime.getMillis(), endTime.getMillis(), loadRawAnomalies);
}
} else {
anomalyResults = anomalyMergedResultDAO.findByCollectionTime(dataset, startTime.getMillis(), endTime.getMillis(), loadRawAnomalies);
}
} catch (Exception e) {
LOG.error("Exception in fetching anomalies", e);
}
if (applyAlertFiler) {
// TODO: why need try catch?
try {
anomalyResults = AlertFilterHelper.applyFiltrationRule(anomalyResults, alertFilterFactory);
} catch (Exception e) {
LOG.warn("Failed to apply alert filters on anomalies for dataset:{}, metric:{}, start:{}, end:{}, exception:{}", dataset, metric, startTimeIso, endTimeIso, e);
}
}
return anomalyResults;
}
use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.
the class OnboardResource method cloneAnomalyInstances.
/**
* Clone merged anomaly instances of one function to another
* 1. get all merged anomaly instances with AnomalyFunctionId = srcId
* 2. set the associated anomalyFunctionId = destId
* 3. save the modified anomaly instances
* @param srcId the source function Id with anomalies to be cloned.
* @param destId the destination function Id which source anomalies to be cloned to.
* @return boolean to indicate if the clone is success or not
*/
public Boolean cloneAnomalyInstances(Long srcId, Long destId) {
// make sure both function can be identified by IDs
AnomalyFunctionDTO srcAnomalyFunction = anomalyFunctionDAO.findById(srcId);
// if cannot find then return
if (srcAnomalyFunction == null) {
// LOG and exit
LOG.error("Source Anomaly Function With id [{}] does not found", srcId);
return false;
}
AnomalyFunctionDTO destAnomalyFunction = anomalyFunctionDAO.findById(destId);
// if cannot find then return
if (destAnomalyFunction == null) {
// LOG and exit
LOG.error("Destination Anomaly Function With id [{}] does not found", destId);
return false;
}
LOG.info("clone merged anomaly results from source anomaly function id {} to id {}", srcId, destId);
List<MergedAnomalyResultDTO> mergedAnomalyResultDTOs = mergedAnomalyResultDAO.findByFunctionId(srcId);
if (mergedAnomalyResultDTOs == null || mergedAnomalyResultDTOs.isEmpty()) {
LOG.error("No merged anomaly results found for anomaly function Id: {}", srcId);
return false;
}
for (MergedAnomalyResultDTO mergedAnomalyResultDTO : mergedAnomalyResultDTOs) {
long oldId = mergedAnomalyResultDTO.getId();
// clean the Id, then will create a new Id when save
mergedAnomalyResultDTO.setId(null);
mergedAnomalyResultDTO.setRawAnomalyIdList(null);
mergedAnomalyResultDTO.setFunctionId(destId);
mergedAnomalyResultDTO.setFunction(destAnomalyFunction);
long newId = mergedAnomalyResultDAO.save(mergedAnomalyResultDTO);
LOG.debug("clone merged anomaly {} to {}", oldId, newId);
}
return true;
}
use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.
the class AnomaliesResource method updateAnomalyMergedResultFeedback.
/**
* Update anomaly feedback
* @param mergedAnomalyId : mergedAnomalyId
* @param payload : Json payload containing feedback @see com.linkedin.thirdeye.constant.AnomalyFeedbackType
* eg. payload
* <p/>
* { "feedbackType": "NOT_ANOMALY", "comment": "this is not an anomaly" }
*/
@POST
@Path(value = "/updateFeedback/{mergedAnomalyId}")
public void updateAnomalyMergedResultFeedback(@PathParam("mergedAnomalyId") long mergedAnomalyId, String payload) {
try {
MergedAnomalyResultDTO result = mergedAnomalyResultDAO.findById(mergedAnomalyId);
if (result == null) {
throw new IllegalArgumentException("AnomalyResult not found with id " + mergedAnomalyId);
}
AnomalyFeedbackDTO feedback = result.getFeedback();
if (feedback == null) {
feedback = new AnomalyFeedbackDTO();
result.setFeedback(feedback);
}
AnomalyFeedbackDTO feedbackRequest = new ObjectMapper().readValue(payload, AnomalyFeedbackDTO.class);
if (feedbackRequest.getStatus() == null) {
feedback.setStatus(FeedbackStatus.NEW);
} else {
feedback.setStatus(feedbackRequest.getStatus());
}
feedback.setComment(feedbackRequest.getComment());
feedback.setFeedbackType(feedbackRequest.getFeedbackType());
mergedAnomalyResultDAO.updateAnomalyFeedback(result);
} catch (IOException e) {
throw new IllegalArgumentException("Invalid payload " + payload, e);
}
}
use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.
the class OnboardResource method getExistingMergedAnomalies.
/**
* Show the content of raw anomalies whose start time is located in the given time ranges
*
* @param monitoringWindowStartTime The start time of the monitoring window (in milli-second)
* @param monitoringWindowEndTime The start time of the monitoring window (in milli-second)
*/
@POST
@Path("function/{id}/getExistingMergedAnomalies")
public List<MergedAnomalyResultDTO> getExistingMergedAnomalies(@PathParam("id") String id, @QueryParam("start") long monitoringWindowStartTime, @QueryParam("end") long monitoringWindowEndTime) {
LOG.info("Retrieving merged anomaly results in the time range: {} -- {}", new DateTime(monitoringWindowStartTime), new DateTime(monitoringWindowEndTime));
List<MergedAnomalyResultDTO> mergedResults = null;
long functionId = Long.valueOf(id);
AnomalyFunctionDTO anomalyFunction = anomalyFunctionDAO.findById(functionId);
if (anomalyFunction == null) {
LOG.info("Anomaly functionId {} is not found", functionId);
return mergedResults;
}
mergedResults = mergedAnomalyResultDAO.findByStartTimeInRangeAndFunctionId(monitoringWindowStartTime, monitoringWindowEndTime, functionId);
return mergedResults;
}
use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.
the class EmailResource method generateAndSendAlertForMetrics.
@GET
@Path("generate/metrics/{startTime}/{endTime}")
public Response generateAndSendAlertForMetrics(@PathParam("startTime") Long startTime, @PathParam("endTime") Long endTime, @QueryParam("metrics") String metrics, @QueryParam("from") String fromAddr, @QueryParam("to") String toAddr, @QueryParam("subject") String subject, @QueryParam("includeSentAnomaliesOnly") boolean includeSentAnomaliesOnly, @QueryParam("teHost") String teHost, @QueryParam("smtpHost") String smtpHost, @QueryParam("smtpPort") int smtpPort, @QueryParam("phantomJsPath") String phantomJsPath) {
if (Strings.isNullOrEmpty(metrics)) {
throw new WebApplicationException("metrics null or empty: " + metrics);
}
String[] metricsArr = metrics.split(",");
if (metricsArr.length == 0) {
throw new WebApplicationException("metrics empty : " + metricsArr);
}
if (Strings.isNullOrEmpty(toAddr)) {
throw new WebApplicationException("Empty : list of recipients" + toAddr);
}
if (Strings.isNullOrEmpty(teHost)) {
throw new WebApplicationException("Invalid TE host" + teHost);
}
if (Strings.isNullOrEmpty(smtpHost)) {
throw new WebApplicationException("invalid smtp host" + smtpHost);
}
AnomalyReportGenerator anomalyReportGenerator = AnomalyReportGenerator.getInstance();
List<MergedAnomalyResultDTO> anomalies = anomalyReportGenerator.getAnomaliesForMetrics(Arrays.asList(metricsArr), startTime, endTime);
ThirdEyeAnomalyConfiguration configuration = new ThirdEyeAnomalyConfiguration();
SmtpConfiguration smtpConfiguration = new SmtpConfiguration();
smtpConfiguration.setSmtpHost(smtpHost);
smtpConfiguration.setSmtpPort(smtpPort);
configuration.setSmtpConfiguration(smtpConfiguration);
configuration.setDashboardHost(teHost);
configuration.setPhantomJsPath(phantomJsPath);
String emailSub = Strings.isNullOrEmpty(subject) ? "Thirdeye Anomaly Report" : subject;
anomalyReportGenerator.buildReport(startTime, endTime, anomalies, emailSub, configuration, includeSentAnomaliesOnly, toAddr, fromAddr, "Thirdeye Anomaly Report", true);
return Response.ok().build();
}
Aggregations