use of com.amazonaws.services.cloudwatch.model.MetricDataQuery in project aws-athena-query-federation by awslabs.
the class MetricsRecordHandlerTest method mockMetricData.
private GetMetricDataResult mockMetricData(InvocationOnMock invocation, int numMetrics, int numSamples) {
GetMetricDataRequest request = invocation.getArgumentAt(0, GetMetricDataRequest.class);
/**
* Confirm that all available criteria were pushed down into Cloudwatch Metrics
*/
List<MetricDataQuery> queries = request.getMetricDataQueries();
assertEquals(1, queries.size());
MetricDataQuery query = queries.get(0);
MetricStat stat = query.getMetricStat();
assertEquals("m1", query.getId());
assertNotNull(stat.getPeriod());
assertNotNull(stat.getMetric());
assertNotNull(stat.getStat());
assertNotNull(stat.getMetric().getMetricName());
assertNotNull(stat.getMetric().getNamespace());
assertNotNull(stat.getMetric().getDimensions());
assertEquals(1, stat.getMetric().getDimensions().size());
String nextToken = (request.getNextToken() == null) ? "valid" : null;
List<MetricDataResult> samples = new ArrayList<>();
for (int i = 0; i < numMetrics; i++) {
List<Double> values = new ArrayList<>();
List<Date> timestamps = new ArrayList<>();
for (double j = 0; j < numSamples; j++) {
values.add(j);
timestamps.add(new Date(System.currentTimeMillis() + (int) j));
}
samples.add(new MetricDataResult().withValues(values).withTimestamps(timestamps).withId("m1"));
}
return new GetMetricDataResult().withNextToken(nextToken).withMetricDataResults(samples);
}
use of com.amazonaws.services.cloudwatch.model.MetricDataQuery in project aws-athena-query-federation by awslabs.
the class MetricsRecordHandler method readMetricSamplesWithConstraint.
/**
* Handles retrieving the samples for a specific metric from Cloudwatch Metrics.
*/
private void readMetricSamplesWithConstraint(BlockSpiller blockSpiller, ReadRecordsRequest request, QueryStatusChecker queryStatusChecker) throws TimeoutException {
GetMetricDataRequest dataRequest = MetricUtils.makeGetMetricDataRequest(request);
Map<String, MetricDataQuery> queries = new HashMap<>();
for (MetricDataQuery query : dataRequest.getMetricDataQueries()) {
queries.put(query.getId(), query);
}
String prevToken;
ValueSet dimensionNameConstraint = request.getConstraints().getSummary().get(DIMENSION_NAME_FIELD);
ValueSet dimensionValueConstraint = request.getConstraints().getSummary().get(DIMENSION_VALUE_FIELD);
do {
prevToken = dataRequest.getNextToken();
GetMetricDataResult result = invoker.invoke(() -> metrics.getMetricData(dataRequest));
for (MetricDataResult nextMetric : result.getMetricDataResults()) {
MetricStat metricStat = queries.get(nextMetric.getId()).getMetricStat();
List<Date> timestamps = nextMetric.getTimestamps();
List<Double> values = nextMetric.getValues();
for (int i = 0; i < nextMetric.getValues().size(); i++) {
int sampleNum = i;
blockSpiller.writeRows((Block block, int row) -> {
/**
* Most constraints were already applied at split generation so we only need to apply
* a subset.
*/
block.offerValue(METRIC_NAME_FIELD, row, metricStat.getMetric().getMetricName());
block.offerValue(NAMESPACE_FIELD, row, metricStat.getMetric().getNamespace());
block.offerValue(STATISTIC_FIELD, row, metricStat.getStat());
block.offerComplexValue(DIMENSIONS_FIELD, row, (Field field, Object val) -> {
if (field.getName().equals(DIMENSION_NAME_FIELD)) {
return ((Dimension) val).getName();
} else if (field.getName().equals(DIMENSION_VALUE_FIELD)) {
return ((Dimension) val).getValue();
}
throw new RuntimeException("Unexpected field " + field.getName());
}, metricStat.getMetric().getDimensions());
// This field is 'faked' in that we just use it as a convenient way to filter single dimensions. As such
// we always populate it with the value of the filter if the constraint passed and the filter was singleValue
String dimName = (dimensionNameConstraint == null || !dimensionNameConstraint.isSingleValue()) ? null : dimensionNameConstraint.getSingleValue().toString();
block.offerValue(DIMENSION_NAME_FIELD, row, dimName);
// This field is 'faked' in that we just use it as a convenient way to filter single dimensions. As such
// we always populate it with the value of the filter if the constraint passed and the filter was singleValue
String dimVal = (dimensionValueConstraint == null || !dimensionValueConstraint.isSingleValue()) ? null : dimensionValueConstraint.getSingleValue().toString();
block.offerValue(DIMENSION_VALUE_FIELD, row, dimVal);
block.offerValue(PERIOD_FIELD, row, metricStat.getPeriod());
boolean matches = true;
block.offerValue(VALUE_FIELD, row, values.get(sampleNum));
long timestamp = timestamps.get(sampleNum).getTime() / 1000;
block.offerValue(TIMESTAMP_FIELD, row, timestamp);
return matches ? 1 : 0;
});
}
}
dataRequest.setNextToken(result.getNextToken());
} while (dataRequest.getNextToken() != null && !dataRequest.getNextToken().equalsIgnoreCase(prevToken) && queryStatusChecker.isQueryRunning());
}
use of com.amazonaws.services.cloudwatch.model.MetricDataQuery in project aws-athena-query-federation by awslabs.
the class MetricUtils method makeGetMetricDataRequest.
/**
* Creates a Cloudwatch Metrics sample data request from the provided inputs
*
* @param readRecordsRequest The RecordReadRequest to make into a Cloudwatch Metrics Data request.
* @return The Cloudwatch Metrics Data request that matches the requested read operation.
*/
protected static GetMetricDataRequest makeGetMetricDataRequest(ReadRecordsRequest readRecordsRequest) {
Split split = readRecordsRequest.getSplit();
String serializedMetricStats = split.getProperty(MetricStatSerDe.SERIALIZED_METRIC_STATS_FIELD_NAME);
List<MetricStat> metricStats = MetricStatSerDe.deserialize(serializedMetricStats);
GetMetricDataRequest dataRequest = new GetMetricDataRequest();
com.amazonaws.services.cloudwatch.model.Metric metric = new com.amazonaws.services.cloudwatch.model.Metric();
metric.setNamespace(split.getProperty(NAMESPACE_FIELD));
metric.setMetricName(split.getProperty(METRIC_NAME_FIELD));
List<MetricDataQuery> metricDataQueries = new ArrayList<>();
int metricId = 1;
for (MetricStat nextMetricStat : metricStats) {
metricDataQueries.add(new MetricDataQuery().withMetricStat(nextMetricStat).withId("m" + metricId++));
}
dataRequest.withMetricDataQueries(metricDataQueries);
ValueSet timeConstraint = readRecordsRequest.getConstraints().getSummary().get(TIMESTAMP_FIELD);
if (timeConstraint instanceof SortedRangeSet && !timeConstraint.isNullAllowed()) {
// SortedRangeSet is how >, <, between is represented which are easiest and most common when
// searching logs so we attempt to push that down here as an optimization. SQL can represent complex
// overlapping ranges which Cloudwatch can not support so this is not a replacement for applying
// constraints using the ConstraintEvaluator.
Range basicPredicate = ((SortedRangeSet) timeConstraint).getSpan();
if (!basicPredicate.getLow().isNullValue()) {
Long lowerBound = (Long) basicPredicate.getLow().getValue();
// TODO: confirm timezone handling
logger.info("makeGetMetricsRequest: with startTime " + (lowerBound * 1000) + " " + new Date(lowerBound * 1000));
dataRequest.withStartTime(new Date(lowerBound * 1000));
} else {
// TODO: confirm timezone handling
dataRequest.withStartTime(new Date(0));
}
if (!basicPredicate.getHigh().isNullValue()) {
Long upperBound = (Long) basicPredicate.getHigh().getValue();
// TODO: confirm timezone handling
logger.info("makeGetMetricsRequest: with endTime " + (upperBound * 1000) + " " + new Date(upperBound * 1000));
dataRequest.withEndTime(new Date(upperBound * 1000));
} else {
// TODO: confirm timezone handling
dataRequest.withEndTime(new Date(System.currentTimeMillis()));
}
} else {
// TODO: confirm timezone handling
dataRequest.withStartTime(new Date(0));
dataRequest.withEndTime(new Date(System.currentTimeMillis()));
}
return dataRequest;
}
Aggregations