com.amazonaws.metrics.internal.cloudwatch.PredefinedMetricTransformer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aws-java-sdk Show documentation
Show all versions of aws-java-sdk Show documentation
The Amazon Web Services SDK for Java provides Java APIs for building software on AWS' cost-effective, scalable, and reliable infrastructure products. The AWS Java SDK allows developers to code against APIs for all of Amazon's infrastructure web services (Amazon S3, Amazon EC2, Amazon SQS, Amazon Relational Database Service, Amazon AutoScaling, etc).
The newest version!
/*
* Copyright 2010-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazonaws.metrics.internal.cloudwatch;
import static com.amazonaws.metrics.internal.cloudwatch.spi.MetricData.newMetricDatum;
import static com.amazonaws.metrics.internal.cloudwatch.spi.RequestMetricTransformer.Utils.endTimestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.annotation.ThreadSafe;
import com.amazonaws.AmazonWebServiceRequest;
import com.amazonaws.Request;
import com.amazonaws.Response;
import com.amazonaws.metrics.MetricType;
import com.amazonaws.metrics.RequestMetricCollector;
import com.amazonaws.metrics.internal.cloudwatch.spi.AWSMetricTransformerFactory;
import com.amazonaws.metrics.internal.cloudwatch.spi.Dimensions;
import com.amazonaws.services.cloudwatch.model.Dimension;
import com.amazonaws.services.cloudwatch.model.MetricDatum;
import com.amazonaws.services.cloudwatch.model.StandardUnit;
import com.amazonaws.util.AWSRequestMetrics;
import com.amazonaws.util.AWSRequestMetrics.Field;
import com.amazonaws.util.TimingInfo;
/**
* Used to transform the predefined metrics of the AWS SDK into instances of
* {@link MetricDatum}.
*
* See http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/
* publishingMetrics.html
*
* @see AWSRequestMetrics
* @see RequestMetricCollector
*/
@ThreadSafe
public class PredefinedMetricTransformer {
private static final Log log = LogFactory.getLog(PredefinedMetricTransformer.class);
static final boolean INCLUDE_REQUEST_TYPE = true;
static final boolean EXCLUDE_REQUEST_TYPE = !INCLUDE_REQUEST_TYPE;
/**
* Returns a non-null list of metric datum for the metrics collected for the
* given request/response.
*
* @param metricType the request metric type
*/
public List toMetricData(MetricType metricType, Request> request, Response> response) {
if (metricType instanceof Field) {
// Predefined metrics across all aws http clients
Field predefined = (Field) metricType;
switch(predefined) {
case HttpClientRetryCount:
case HttpClientPoolAvailableCount:
case HttpClientPoolLeasedCount:
case HttpClientPoolPendingCount:
return metricOfCount(predefined, request, response);
case RequestCount: // intentionally fall thru to reuse the same routine as RetryCount
case RetryCount:
return metricOfRequestOrRetryCount(predefined, request, response);
case ResponseProcessingTime: // drop thru
case RequestSigningTime: // drop thru
return latencyMetricOf(predefined, request, response, EXCLUDE_REQUEST_TYPE);
case ClientExecuteTime:
return latencyOfClientExecuteTime(request, response);
case HttpClientSendRequestTime:
case HttpClientReceiveResponseTime:
case HttpRequestTime:
return latencyMetricOf(predefined, request, response, INCLUDE_REQUEST_TYPE);
case Exception:
return counterMetricOf(predefined, request, response, INCLUDE_REQUEST_TYPE);
default:
break;
}
}
// Predefined metrics for specific service clients
for (AWSMetricTransformerFactory aws: AWSMetricTransformerFactory.values()) {
if (metricType.name().startsWith(aws.name())) {
List metricData = aws.getRequestMetricTransformer()
.toMetricData(metricType, request, response);
if (metricData != null)
return metricData;
break;
}
}
if (log.isDebugEnabled()) {
AmazonWebServiceRequest origReq = request == null ? null : request
.getOriginalRequest();
String reqClassName = origReq == null ? null : origReq.getClass().getName();
log.debug("No request metric transformer can be found for metric type "
+ metricType.name() + " for " + reqClassName);
}
return Collections.emptyList();
}
/**
* Returns a list with a single metric datum for the specified retry or
* request count predefined metric; or an empty list if there is none.
*
* @param metricType
* must be either {@link Field#RequestCount} or
* {@link Field#RetryCount}; or else GIGO.
*/
protected List metricOfRequestOrRetryCount(
Field metricType, Request> req, Object resp) {
AWSRequestMetrics m = req.getAWSRequestMetrics();
TimingInfo ti = m.getTimingInfo();
// Always retrieve the request count even for retry which is equivalent
// to the number of requests minus one.
Number counter = ti.getCounter(Field.RequestCount.name());
if (counter == null) {
// this is possible if one of the request handlers screwed up
return Collections.emptyList();
}
int requestCount = counter.intValue();
if (requestCount < 1) {
LogFactory.getLog(getClass()).warn(
"request count must be at least one");
return Collections.emptyList();
}
final double count = metricType == Field.RequestCount
? requestCount
: requestCount-1 // retryCount = requestCount - 1
;
if (count < 1) {
return Collections.emptyList();
} else {
return Collections.singletonList(new MetricDatum()
.withMetricName(req.getServiceName())
.withDimensions(new Dimension()
.withName(Dimensions.MetricType.name())
.withValue(metricType.name()))
.withUnit(StandardUnit.Count)
.withValue(Double.valueOf(count))
.withTimestamp(endTimestamp(ti)))
;
}
}
protected List metricOfCount(
Field metricType, Request> req, Object resp) {
AWSRequestMetrics m = req.getAWSRequestMetrics();
TimingInfo ti = m.getTimingInfo();
Number counter = ti.getCounter(metricType.name());
if (counter == null) {
return Collections.emptyList();
}
final double count = counter.doubleValue();
if (count < 1) {
return Collections.emptyList();
} else {
return Collections.singletonList(new MetricDatum()
.withMetricName(req.getServiceName())
.withDimensions(new Dimension()
.withName(Dimensions.MetricType.name())
.withValue(metricType.name()))
.withUnit(StandardUnit.Count)
.withValue(Double.valueOf(count))
.withTimestamp(endTimestamp(ti)))
;
}
}
/**
* Returns all the latency metric data recorded for the specified metric
* event type; or an empty list if there is none. The number of metric datum
* in the returned list should be exactly one when there is no retries, or
* more than one when there are retries.
*
* @param includesRequestType
* true iff the "request" dimension is to be included;
*/
protected List latencyMetricOf(MetricType metricType,
Request> req, Object response, boolean includesRequestType) {
AWSRequestMetrics m = req.getAWSRequestMetrics();
TimingInfo root = m.getTimingInfo();
final String metricName = metricType.name();
List subMeasures =
root.getAllSubMeasurements(metricName);
if (subMeasures != null) {
List result =
new ArrayList(subMeasures.size());
for (TimingInfo sub : subMeasures) {
if (sub.isEndTimeKnown()) { // being defensive
List dims = new ArrayList();
dims.add(new Dimension()
.withName(Dimensions.MetricType.name())
.withValue(metricName));
// Either a non request type specific datum is created per
// sub-measurement, or a request type specific one is
// created but not both
if (includesRequestType) {
dims.add(new Dimension()
.withName(Dimensions.RequestType.name())
.withValue(requestType(req)));
}
MetricDatum datum = new MetricDatum()
.withMetricName(req.getServiceName())
.withDimensions(dims)
.withUnit(StandardUnit.Milliseconds)
.withValue(sub.getTimeTakenMillisIfKnown());
result.add(datum);
}
}
return result;
}
return Collections.emptyList();
}
/**
* Returns a request type specific metrics for
* {@link Field#ClientExecuteTime} which is special in the sense that it
* makes a more accurate measurement by taking the {@link TimingInfo} at the
* root into account.
*/
protected List latencyOfClientExecuteTime(Request> req, Object response) {
AWSRequestMetrics m = req.getAWSRequestMetrics();
TimingInfo root = m.getTimingInfo();
final String metricName = Field.ClientExecuteTime.name();
if (root.isEndTimeKnown()) { // being defensive
List dims = new ArrayList();
dims.add(new Dimension()
.withName(Dimensions.MetricType.name())
.withValue(metricName));
// request type specific
dims.add(new Dimension()
.withName(Dimensions.RequestType.name())
.withValue(requestType(req)));
MetricDatum datum = new MetricDatum()
.withMetricName(req.getServiceName())
.withDimensions(dims)
.withUnit(StandardUnit.Milliseconds)
.withValue(root.getTimeTakenMillisIfKnown());
return Collections.singletonList(datum);
}
return Collections.emptyList();
}
/**
* Returns the name of the type of request.
*/
private String requestType(Request> req) {
return req.getOriginalRequest().getClass().getSimpleName();
}
/**
* Returns a list of metric datum recorded for the specified counter metric
* type; or an empty list if there is none.
*
* @param includesRequestType
* true iff an additional metric datum is to be created that
* includes the "request" dimension
*/
protected List counterMetricOf(MetricType type,
Request> req, Object resp, boolean includesRequestType) {
AWSRequestMetrics m = req.getAWSRequestMetrics();
TimingInfo ti = m.getTimingInfo();
final String metricName = type.name();
Number counter = ti.getCounter(metricName);
if (counter == null) {
return Collections.emptyList();
}
int count = counter.intValue();
if (count < 1) {
LogFactory.getLog(getClass()).warn("Count must be at least one");
return Collections.emptyList();
}
final List result = new ArrayList();
final Dimension metricDimension = new Dimension()
.withName(Dimensions.MetricType.name())
.withValue(metricName);
// non-request type specific metric datum
final MetricDatum first = new MetricDatum()
.withMetricName(req.getServiceName())
.withDimensions(metricDimension)
.withUnit(StandardUnit.Count)
.withValue(Double.valueOf(count))
.withTimestamp(endTimestamp(ti));
result.add(first);
if (includesRequestType) {
// additional request type specific metric datum
Dimension requestDimension = new Dimension()
.withName(Dimensions.RequestType.name())
.withValue(requestType(req));
final MetricDatum second =
newMetricDatum(first, metricDimension, requestDimension);
result.add(second);
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy