private static void addMissingMetricSets(List<MetricSet> knownMetricSetList, List<MetricSet> missingMetricSetList) { knownMetricSetList.addAll( missingMetricSetList .stream() .map(metricSet -> MetricSet .builder() .name(metricSet.getName()) .tags(metricSet.getTags()) .build()) .collect(Collectors.toList())); } }
@Bean @ConditionalOnMissingBean MetricSetMixerService metricSetMixerService() { return new MetricSetMixerService(); }
@Bean @ConditionalOnMissingBean(MetricsServiceRepository.class) MetricsServiceRepository metricsServiceRepository() { return new MapBackedMetricsServiceRepository(); }
private List<MetricSet> buildMetricSets(String metricSetName, List<InfluxDbResult> influxDbResults) { List<MetricSet> metricSets = new ArrayList<MetricSet>(); if (influxDbResults != null) { for (InfluxDbResult influxDbResult : influxDbResults) { Instant endtime = Instant.ofEpochMilli(influxDbResult.getStartTimeMillis() + influxDbResult.getStepMillis() * influxDbResult.getValues().size()); MetricSetBuilder metricSetBuilder = MetricSet.builder() .name(metricSetName) .startTimeMillis(influxDbResult.getStartTimeMillis()) .startTimeIso(Instant.ofEpochMilli(influxDbResult.getStartTimeMillis()).toString()) .endTimeMillis(endtime.toEpochMilli()) .endTimeIso(endtime.toString()) .stepMillis(influxDbResult.getStepMillis()) .values(influxDbResult.getValues()) .tag("field", influxDbResult.getId()); Map<String, String> tags = influxDbResult.getTags(); if (tags != null) { metricSetBuilder.tags(tags); } metricSets.add(metricSetBuilder.build()); } } return metricSets; } }
public MetricSetPair mixOne(MetricSet controlMetricSet, MetricSet experimentMetricSet) { String controlName = controlMetricSet.getName(); String experimentName = experimentMetricSet.getName(); Map<String, String> controlTags = controlMetricSet.getTags(); Map<String, String> experimentTags = experimentMetricSet.getTags(); List<Double> controlValues = controlMetricSet.getValues(); List<Double> experimentValues = experimentMetricSet.getValues(); MetricSetPair.MetricSetScope controlScope = MetricSetPair.MetricSetScope.builder() .startTimeIso(controlMetricSet.getStartTimeIso()) .startTimeMillis(controlMetricSet.getStartTimeMillis()) .stepMillis(controlMetricSet.getStepMillis()) .build(); MetricSetPair.MetricSetScope experimentScope = MetricSetPair.MetricSetScope.builder() .startTimeIso(experimentMetricSet.getStartTimeIso()) .startTimeMillis(experimentMetricSet.getStartTimeMillis()) .stepMillis(experimentMetricSet.getStepMillis()) .build(); if (controlMetricSet.expectedDataPoints() > controlValues.size()) { controlValues = new ArrayList<>(controlValues); while (controlMetricSet.expectedDataPoints() > controlValues.size()) { controlValues.add(Double.NaN); if (experimentMetricSet.expectedDataPoints() > experimentValues.size()) { experimentValues = new ArrayList<>(experimentValues); while (experimentMetricSet.expectedDataPoints() > experimentValues.size()) { experimentValues.add(Double.NaN);
accountCredentialsRepository); return synchronousQueryProcessor.executeQueryAndProduceTaskResult(resolvedMetricsAccountName, resolvedStorageAccountName, canaryConfig,
public TaskResult executeQueryAndProduceTaskResult(String metricsAccountName, String storageAccountName, CanaryConfig canaryConfig, int metricIndex, CanaryScope canaryScope) { try { Map outputs = processQueryAndReturnMap(metricsAccountName, storageAccountName, canaryConfig, null /* canaryMetricConfig */, metricIndex, canaryScope, false /* dryRun */); return new TaskResult(ExecutionStatus.SUCCEEDED, Collections.emptyMap(), outputs); } catch (IOException e) { throw new RuntimeException(e); } } }
public Map processQueryAndReturnMap(String metricsAccountName, String storageAccountName, CanaryConfig canaryConfig, CanaryMetricConfig canaryMetricConfig, int metricIndex, CanaryScope canaryScope, boolean dryRun) throws IOException { if (canaryConfig == null) { canaryConfig = CanaryConfig.builder().metric(canaryMetricConfig).build(); } if (dryRun) { MetricsService metricsService = metricsServiceRepository .getOne(metricsAccountName) .orElseThrow(() -> new IllegalArgumentException("No metrics service was configured; unable to read from metrics store.")); String query = metricsService.buildQuery(metricsAccountName, canaryConfig, canaryMetricConfig, canaryScope); return Collections.singletonMap("query", query); } else { String metricSetListId = executeQuery(metricsAccountName, storageAccountName, canaryConfig, metricIndex, canaryScope); return Collections.singletonMap("metricSetListId", metricSetListId); } }
public List<MetricSetPair> mixAll(List<MetricSet> controlMetricSetList, List<MetricSet> experimentMetricSetList) { if (controlMetricSetList == null) { controlMetricSetList = new ArrayList<>(); } if (experimentMetricSetList == null) { experimentMetricSetList = new ArrayList<>(); } // Build 'metric set key' -> 'metric set' maps of control and experiment so we can efficiently identify missing metric sets. Map<String, MetricSet> controlMetricSetMap = buildMetricSetMap(controlMetricSetList); Map<String, MetricSet> experimentMetricSetMap = buildMetricSetMap(experimentMetricSetList); // Identify metric sets missing from each map. List<MetricSet> missingFromExperiment = findMissingMetricSets(controlMetricSetList, experimentMetricSetMap); List<MetricSet> missingFromControl = findMissingMetricSets(experimentMetricSetList, controlMetricSetMap); // Add placeholder metric sets for each one that is missing. addMissingMetricSets(controlMetricSetList, missingFromControl); addMissingMetricSets(experimentMetricSetList, missingFromExperiment); // Sort each metric set list so that we can pair them. controlMetricSetList.sort(Comparator.comparing(metricSet -> metricSet.getMetricSetKey())); experimentMetricSetList.sort(Comparator.comparing(metricSet -> metricSet.getMetricSetKey())); // Produce the list of metric set pairs from the pair of metric set lists. List<MetricSetPair> ret = new ArrayList<>(); for (int i = 0; i < controlMetricSetList.size(); i++) { ret.add(mixOne(controlMetricSetList.get(i), experimentMetricSetList.get(i))); } return ret; }
MetricsService metricsService = metricsServiceRepository .getOne(metricsAccountName) .orElseThrow(() -> new IllegalArgumentException("No metrics service was configured; unable to read from metrics store.")); .orElseThrow(() -> new IllegalArgumentException("No storage service was configured; unable to write metric set list.")); Id queryId = registry.createId("canary.telemetry.query").withTag("metricsStore", metricsService.getType()); try { registry.counter(queryId.withTag("retries", retries + "")).increment(); metricSetList = metricsService.queryMetrics(metricsAccountName, canaryConfig, canaryMetricConfig, canaryScope); success = true; } catch (IOException | UncheckedIOException | RetrofitError | RetryableQueryException e) {
@ApiOperation(value = "Retrieve a list of descriptors for use in populating the canary config ui") @RequestMapping(method = RequestMethod.GET) public List<Map> listMetadata(@RequestParam(required = false) final String metricsAccountName, @RequestParam(required = false) final String filter) throws IOException { String resolvedMetricsAccountName = CredentialsHelper.resolveAccountByNameOrType(metricsAccountName, AccountCredentials.Type.METRICS_STORE, accountCredentialsRepository); MetricsService metricsService = metricsServiceRepository .getOne(resolvedMetricsAccountName) .orElseThrow(() -> new IllegalArgumentException("No metrics service was configured; unable to read from metrics store.")); List<Map> matchingDescriptors = metricsService.getMetadata(resolvedMetricsAccountName, filter); if (StringUtils.isEmpty(filter)) { log.debug("Returned all {} descriptors via account {}.", matchingDescriptors.size(), resolvedMetricsAccountName, filter); } else { log.debug("Matched {} descriptors via account {} using filter '{}'.", matchingDescriptors.size(), resolvedMetricsAccountName, filter); } return metricsService.getMetadata(resolvedMetricsAccountName, filter); } }
protected AtlasResults convertTokenizedLineToAtlasResults(String[] tokenizedLine) { try { AtlasResults atlasResults = kayentaObjectMapper.readValue(tokenizedLine[1], AtlasResults.class); String atlasResultsType = atlasResults.getType(); if (StringUtils.isEmpty(atlasResultsType) || !EXPECTED_RESULTS_TYPE_LIST.contains(atlasResultsType)) { if (atlasResultsType.equals("error")) { if (atlasResults.getMessage().contains("IllegalStateException")) { throw new FatalQueryException("Atlas query failed: " + atlasResults.getMessage()); } else { throw new RetryableQueryException("Atlas query failed: " + atlasResults.getMessage()); } } log.info("Received results of type other than 'timeseries' or 'close' from Atlas: {}", atlasResults); return null; } return atlasResults; } catch (IOException e) { log.error("Cannot process Atlas results", e); return null; } }
@Override public Optional<MetricsService> getOne(String accountName) { return metricsServices .stream() .filter(m -> m.servicesAccount(accountName)) .findFirst(); } }
private static List<MetricSet> findMissingMetricSets(List<MetricSet> requiredMetricSetList, Map<String, MetricSet> knownMetricSetMap) { return requiredMetricSetList .stream() .filter(requiredMetricSet -> !knownMetricSetMap.containsKey(requiredMetricSet.getMetricSetKey())) .collect(Collectors.toList()); }
protected List<AtlasResults> processInput(BufferedReader reader) { List<String[]> tokenizedLines = reader .lines() .filter(line -> !StringUtils.isEmpty(line)) .map(line -> line.split(": ", 2)) .collect(Collectors.toList()); tokenizedLines .stream() .map(tokenizedLine -> tokenizedLine[0]) .filter(openingToken -> !openingToken.equals("data")) .forEach(nonDataOpeningToken -> log.info("Received opening token other than 'data' from Atlas: {}", nonDataOpeningToken)); List<AtlasResults> atlasResultsList = tokenizedLines .stream() .map(this::convertTokenizedLineToAtlasResults) .filter(Objects::nonNull) .collect(Collectors.toList()); if (!atlasResultsList.get(atlasResultsList.size() - 1).getType().equals("close")) { log.error("Received data from Atlas that did not terminate with a 'close'."); throw new RetryableQueryException("Atlas response did not end in a 'close', we cannot guarantee all data was received."); } return atlasResultsList; }
@Nonnull @Override public TaskResult execute(@Nonnull Stage stage) { Map<String, Object> context = stage.getContext(); String metricsAccountName = (String)context.get("metricsAccountName"); String storageAccountName = (String)context.get("storageAccountName"); Map<String, Object> canaryConfigMap = (Map<String, Object>)context.get("canaryConfig"); CanaryConfig canaryConfig = kayentaObjectMapper.convertValue(canaryConfigMap, CanaryConfig.class); int metricIndex = (Integer)stage.getContext().get("metricIndex"); CanaryScope canaryScope; try { canaryScope = kayentaObjectMapper.readValue((String)stage.getContext().get("canaryScope"), PrometheusCanaryScope.class); } catch (IOException e) { log.warn("Unable to parse JSON scope", e); throw new RuntimeException(e); } String resolvedMetricsAccountName = CredentialsHelper.resolveAccountByNameOrType(metricsAccountName, AccountCredentials.Type.METRICS_STORE, accountCredentialsRepository); String resolvedStorageAccountName = CredentialsHelper.resolveAccountByNameOrType(storageAccountName, AccountCredentials.Type.OBJECT_STORE, accountCredentialsRepository); return synchronousQueryProcessor.executeQueryAndProduceTaskResult(resolvedMetricsAccountName, resolvedStorageAccountName, canaryConfig, metricIndex, canaryScope); } }
@Bean @ConditionalOnMissingBean MetricSetMixerService metricSetMixerService() { return new MetricSetMixerService(); }
@Bean @ConditionalOnMissingBean(MetricsServiceRepository.class) MetricsServiceRepository metricsServiceRepository() { return new MapBackedMetricsServiceRepository(); }
); return synchronousQueryProcessor.executeQueryAndProduceTaskResult( resolvedMetricsAccountName, resolvedStorageAccountName,
); return synchronousQueryProcessor.executeQueryAndProduceTaskResult( resolvedMetricsAccountName, resolvedStorageAccountName,