package com.linkedin.thirdeye.anomaly.alert.util; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.quartz.JobExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.linkedin.thirdeye.anomaly.ThirdEyeAnomalyConfiguration; public class EmailScreenshotHelper { private static final String TEMP_PATH = "/tmp/graph"; private static final String SCREENSHOT_FILE_SUFFIX = ".png"; private static final String GRAPH_SCREENSHOT_GENERATOR_SCRIPT = "/getGraphPnj.js"; private static final Logger LOG = LoggerFactory.getLogger(EmailScreenshotHelper.class); private static final ExecutorService executorService = Executors.newCachedThreadPool(); public static String takeGraphScreenShot(final String anomalyId, final ThirdEyeAnomalyConfiguration configuration) throws JobExecutionException { Callable<String> callable = new Callable<String>() { public String call() throws Exception { return takeScreenshot(anomalyId, configuration); } }; Future<String> task = executorService.submit(callable); String result = null; try { result = task.get(3, TimeUnit.MINUTES); LOG.info("Finished with result: {}", result); } catch (Exception e) { LOG.error("Exception in fetching screenshot for anomaly id {}", anomalyId, e); EmailHelper.sendFailureEmailForScreenshot(anomalyId, e.fillInStackTrace(), configuration); } return result; } private static String takeScreenshot(String anomalyId, ThirdEyeAnomalyConfiguration configuration) throws Exception { String imgRoute = configuration.getDashboardHost() + "/thirdeye#investigate?anomalyId=" + anomalyId; LOG.info("imgRoute {}", imgRoute); String phantomScript = configuration.getRootDir() + GRAPH_SCREENSHOT_GENERATOR_SCRIPT; LOG.info("Phantom JS script {}", phantomScript); String imgPath = TEMP_PATH + anomalyId + SCREENSHOT_FILE_SUFFIX; LOG.info("imgPath {}", imgPath); Process proc = Runtime.getRuntime().exec(new String[]{configuration.getPhantomJsPath(), "phantomjs", "--ssl-protocol=any", "--ignore-ssl-errors=true", phantomScript, imgRoute, imgPath}); InputStream stderr = proc.getErrorStream(); InputStreamReader isr = new InputStreamReader(stderr); BufferedReader br = new BufferedReader(isr); // exhaust the error stream before waiting for the process to exit String line = br.readLine(); if (line != null) { do { line = br.readLine(); } while (line != null); } int exitVal = proc.waitFor(); if (exitVal != 0) { throw new Exception("PhantomJS process failed with error code: " + exitVal); } return imgPath; } }