package net.iponweb.disthene.reader.graphite.evaluation; import com.google.common.collect.ObjectArrays; import net.iponweb.disthene.reader.beans.TimeSeries; import net.iponweb.disthene.reader.config.Rollup; import net.iponweb.disthene.reader.exceptions.EvaluationException; import net.iponweb.disthene.reader.exceptions.InvalidNumberOfSeriesException; import net.iponweb.disthene.reader.exceptions.TimeSeriesNotAlignedException; import net.iponweb.disthene.reader.exceptions.TooMuchDataExpectedException; import net.iponweb.disthene.reader.graphite.PathTarget; import net.iponweb.disthene.reader.graphite.Target; import net.iponweb.disthene.reader.graphite.functions.DistheneFunction; import net.iponweb.disthene.reader.service.metric.MetricService; import net.iponweb.disthene.reader.utils.TimeSeriesUtils; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; /** * @author Andrei Ivanov */ public class TargetEvaluator { final static Logger logger = Logger.getLogger(TargetEvaluator.class); private MetricService metricService; public TargetEvaluator(MetricService metricService) { this.metricService = metricService; } public List<TimeSeries> eval(Target target) throws EvaluationException { return target.evaluate(this); } public List<TimeSeries> visit(PathTarget pathTarget) throws EvaluationException { try { return metricService.getMetricsAsList(pathTarget.getTenant(), Collections.singletonList(pathTarget.getPath()), pathTarget.getFrom(), pathTarget.getTo()); } catch (ExecutionException | InterruptedException | TooMuchDataExpectedException e) { logger.error(e.getMessage()); logger.debug(e); throw new EvaluationException(e); } } public List<TimeSeries> visit(DistheneFunction function) throws EvaluationException { return function.evaluate(this); } //todo: the logic below is duplicated several times - fix it! public TimeSeries getEmptyTimeSeries(long from, long to) { Long now = System.currentTimeMillis() * 1000; Long effectiveTo = Math.min(to, now); Rollup bestRollup = metricService.getRollup(from); Long effectiveFrom = (from % bestRollup.getRollup()) == 0 ? from : from + bestRollup.getRollup() - (from % bestRollup.getRollup()); effectiveTo = effectiveTo - (effectiveTo % bestRollup.getRollup()); int length = (int) ((effectiveTo - effectiveFrom) / bestRollup.getRollup() + 1); TimeSeries ts = new TimeSeries("", effectiveFrom, effectiveTo, bestRollup.getRollup()); ts.setValues(new Double[length]); return ts; } // todo: suboptimal public List<TimeSeries> bootstrap(Target target, List<TimeSeries> original, long period) throws EvaluationException { if (original.size() == 0) return new ArrayList<>(); List<TimeSeries> bootstrapped = new ArrayList<>(); bootstrapped.addAll(eval(target.previous(period))); if (bootstrapped.size() != original.size()) throw new InvalidNumberOfSeriesException(); if (!TimeSeriesUtils.checkAlignment(bootstrapped)) throw new TimeSeriesNotAlignedException(); int step = original.get(0).getStep(); // normalize (assuming bootstrapped step can only be bigger if (bootstrapped.get(0).getStep() != step) { int ratio = bootstrapped.get(0).getStep() / step; for(TimeSeries ts : bootstrapped) { List<Double> values = new ArrayList<>(); for (int i = 0; i < ts.getValues().length; i++) { values.addAll(Collections.nCopies(ratio, ts.getValues()[i])); } ts.setValues(values.toArray(new Double[values.size()])); } } for (int i = 0; i < bootstrapped.size(); i++) { bootstrapped.get(i).setValues(ObjectArrays.concat(bootstrapped.get(i).getValues(), original.get(i).getValues(), Double.class)); bootstrapped.get(i).setStep(step); } return bootstrapped; } }