package com.linkedin.thirdeye.tools; import com.linkedin.thirdeye.anomaly.utils.DetectionResourceHttpUtils; import com.linkedin.thirdeye.datalayer.bao.AnomalyFunctionManager; import com.linkedin.thirdeye.datalayer.bao.AutotuneConfigManager; import com.linkedin.thirdeye.datalayer.dto.AnomalyFunctionDTO; import com.linkedin.thirdeye.datalayer.dto.AutotuneConfigDTO; import com.linkedin.thirdeye.datalayer.util.DaoProviderUtil; import com.linkedin.thirdeye.detector.email.filter.PrecisionRecallEvaluator; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.lang.StringUtils; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility class to support fetching results from autotune endpoint, fetching evaluation results from evaluation endpoint * Also provide ways to write map to csv, read from csv to Map of Strings */ public class AutoTuneAlertFilterTool { private static final Logger LOG = LoggerFactory.getLogger(AutoTuneAlertFilterTool.class); public static AnomalyFunctionManager anomalyFunctionDAO; public static AutotuneConfigManager autotuneConfigDAO; private static final int APPLICATION_PORT = 1867; private static final String LOCALHOST = "localhost"; public static String CSVSEPERATOR = ","; public static String CSVESCAPE = ";"; public AutoTuneAlertFilterTool(File persistenceFile){ DaoProviderUtil.init(persistenceFile); anomalyFunctionDAO = DaoProviderUtil .getInstance(com.linkedin.thirdeye.datalayer.bao.jdbc.AnomalyFunctionManagerImpl.class); autotuneConfigDAO = DaoProviderUtil .getInstance(com.linkedin.thirdeye.datalayer.bao.jdbc.AutotuneConfigManagerImpl.class); } public static class EvaluationNode{ private Properties alertFilterEval; private static final String ID = "Id"; private static final String METRICNAME = "metricName"; private static final String ALERTFILTERSTR = "alertFilterStr"; private static final String COLLECTION = "collection"; private static List<String> getHeaders(){ List<String> headers = new ArrayList<>(); headers.addAll(Arrays.asList(COLLECTION, METRICNAME, ID, ALERTFILTERSTR)); headers.addAll(PrecisionRecallEvaluator.getPropertyNames()); return headers; } public EvaluationNode(Long Id, String metricName, String collection, String alertFilterStr, Properties alertFilterEvaluations){ alertFilterEvaluations.put(ID, Id); alertFilterEvaluations.put(METRICNAME, metricName); alertFilterEvaluations.put(COLLECTION, collection); alertFilterEvaluations.put(ALERTFILTERSTR, alertFilterStr); this.alertFilterEval = alertFilterEvaluations; } public String toCSVString(){ StringBuilder res = new StringBuilder(); for(String header : getHeaders()){ res.append(alertFilterEval.get(header)) .append(CSVSEPERATOR); } return res.toString(); } public static String getCSVSchema(){ return StringUtils.join(getHeaders(), CSVSEPERATOR); } } public String getTunedAlertFilterByFunctionId(Long functionId, String startTimeISO, String endTimeISO, String AUTOTUNE_TYPE, String holidayStarts, String holidayEnds) throws Exception{ DetectionResourceHttpUtils httpUtils = new DetectionResourceHttpUtils(LOCALHOST, APPLICATION_PORT); try { return httpUtils.runAutoTune(functionId, startTimeISO, endTimeISO, AUTOTUNE_TYPE, holidayStarts, holidayEnds); } catch (Exception e) { LOG.warn(e.getMessage()); } return null; } public String evaluateAlertFilterByFunctionId(Long functionId, String startTimeISO, String endTimeISO, String holidayStarts, String holidayEnds){ DetectionResourceHttpUtils httpUtils = new DetectionResourceHttpUtils(LOCALHOST, APPLICATION_PORT); try{ return httpUtils.getEvalStatsAlertFilter(functionId, startTimeISO, endTimeISO, holidayStarts, holidayEnds); } catch (Exception e) { LOG.warn(e.getMessage()); } return null; } public String evaluateAlertFilterByAutoTuneId(Long autotuneId, String startTimeISO, String endTimeISO, String holidayStarts, String holidayEnds){ DetectionResourceHttpUtils httpUtils = new DetectionResourceHttpUtils(LOCALHOST, APPLICATION_PORT); try{ return httpUtils.evalAutoTune(autotuneId, startTimeISO, endTimeISO, holidayStarts, holidayEnds); } catch (Exception e){ LOG.warn(e.getMessage()); } return null; } public void writeMapToCSV(Map<String, String> map, String fileName, String headers) throws IOException { BufferedWriter bw = new BufferedWriter(new FileWriter(fileName)); if (headers != null){ bw.write(headers); bw.newLine(); } for (Map.Entry<String, String> pair : map.entrySet()) { bw.write(pair.getKey() + "," + pair.getValue()); bw.newLine(); } bw.close(); } public EvaluationNode evalAnomalyFunctionAlertFilterToEvalNode(Long functionID, String startTimeISO, String endTimeISO, String holidayStarts, String holidayEnds) throws IOException, JSONException { AnomalyFunctionDTO anomalyFunctionSpec = anomalyFunctionDAO.findById(functionID); String metricName = anomalyFunctionSpec.getFunctionName(); String collection = anomalyFunctionSpec.getCollection(); String metricAlertFilter = (anomalyFunctionSpec.getAlertFilter() == null)? "null": anomalyFunctionSpec.getAlertFilter().toString().replaceAll(CSVSEPERATOR, CSVESCAPE); String evals = evaluateAlertFilterByFunctionId(functionID, startTimeISO, endTimeISO, holidayStarts, holidayEnds); Properties alertFilterEvaluations = jsonStringToProperties(evals); return new EvaluationNode(functionID, metricName, collection, metricAlertFilter, alertFilterEvaluations); } public EvaluationNode evalAutoTunedAlertFilterToEvalNode(Long autotuneId, String startTimeISO, String endTimeISO, String holidayStarts, String holidayEnds) throws IOException, JSONException{ AutotuneConfigDTO autotuneConfigDTO = autotuneConfigDAO.findById(autotuneId); long functionId = autotuneConfigDTO.getFunctionId(); AnomalyFunctionDTO anomalyFunctionSpec = anomalyFunctionDAO.findById(functionId); String metricName = anomalyFunctionSpec.getFunctionName(); String collection = anomalyFunctionSpec.getCollection(); String metricAlertFilter = autotuneConfigDTO.getConfiguration().toString().replaceAll(CSVSEPERATOR, CSVESCAPE); String evals = evaluateAlertFilterByAutoTuneId(autotuneId, startTimeISO, endTimeISO, holidayStarts, holidayEnds); Properties alertFilterEvaluations = jsonStringToProperties(evals); return new EvaluationNode(autotuneId, metricName, collection, metricAlertFilter, alertFilterEvaluations); } private Properties jsonStringToProperties(String jsonStr) throws JSONException { Properties res = new Properties(); if (jsonStr != null) { JSONObject jsonVal = new JSONObject(jsonStr); Iterator<String> nameltr = jsonVal.keys(); while (nameltr.hasNext()) { String key = nameltr.next(); String eval = jsonVal.getString(key); res.put(key, eval); } } return res; } public List<Long> getAllFunctionIdsByCollection(String Collection){ List<AnomalyFunctionDTO> anomalyFunctionSpecs = anomalyFunctionDAO.findAllByCollection(Collection); List<Long> functionIds = new ArrayList<>(); for(AnomalyFunctionDTO anomalyFunctionSpec: anomalyFunctionSpecs){ functionIds.add(anomalyFunctionSpec.getId()); } return functionIds; } public Boolean checkAnomaliesHasLabels(Long functionId, String startTimeISO, String endTimeISO, String holidayStarts, String holidayEnds){ DetectionResourceHttpUtils httpUtils = new DetectionResourceHttpUtils(LOCALHOST, APPLICATION_PORT); try{ return Boolean.valueOf(httpUtils.checkHasLabels(functionId, startTimeISO, endTimeISO, holidayStarts, holidayEnds)); } catch (Exception e) { LOG.warn(e.getMessage()); } return null; } public String getInitAutoTuneByFunctionId(Long functionId, String startTimeISO, String endTimeISO, String AUTOTUNE_TYPE, int nExpected,String holidayStarts, String holidayEnds) throws Exception{ DetectionResourceHttpUtils httpUtils = new DetectionResourceHttpUtils(LOCALHOST, APPLICATION_PORT); try { return httpUtils.initAutoTune(functionId, startTimeISO, endTimeISO, AUTOTUNE_TYPE, nExpected, holidayStarts, holidayEnds); } catch (Exception e) { LOG.warn(e.getMessage()); } return null; } }