Package com.amazonaws.metrics.internal.cloudwatch

Source Code of com.amazonaws.metrics.internal.cloudwatch.PredefinedMetricTransformer

/*
* 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.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 <a href=
* "http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/publishingMetrics.html"
* >http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/
* publishingMetrics.html</a>
*
* @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<MetricDatum> 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<MetricDatum> metricData = aws.getRequestMetricTransformer()
                        .toMetricData(metricType, request, response);
                if (metricData != null)
                    return metricData;
                break;
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("No request metric transformer can be found for metric type " + metricType.name());
        }
        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<MetricDatum> 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<MetricDatum> 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<MetricDatum> latencyMetricOf(MetricType metricType,
            Request<?> req, Object response, boolean includesRequestType) {
        AWSRequestMetrics m = req.getAWSRequestMetrics();
        TimingInfo root = m.getTimingInfo();
        final String metricName = metricType.name();
        List<TimingInfo> subMeasures =
            root.getAllSubMeasurements(metricName);
        if (subMeasures != null) {
            List<MetricDatum> result =
                new ArrayList<MetricDatum>(subMeasures.size());
            for (TimingInfo sub : subMeasures) {
                if (sub.isEndTimeKnown()) { // being defensive
                    List<Dimension> dims = new ArrayList<Dimension>();
                    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<MetricDatum> 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<Dimension> dims = new ArrayList<Dimension>();
            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<MetricDatum> 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<MetricDatum> result = new ArrayList<MetricDatum>();
        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;
    }
}
TOP

Related Classes of com.amazonaws.metrics.internal.cloudwatch.PredefinedMetricTransformer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.