/* * Copyright 2010-2019 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; import static com.amazonaws.SDKGlobalConfiguration.DEFAULT_METRICS_SYSTEM_PROPERTY; import com.amazonaws.SDKGlobalConfiguration; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.auth.PropertiesCredentials; import com.amazonaws.regions.Regions; import com.amazonaws.util.AWSRequestMetrics.Field; import com.amazonaws.util.AWSServiceMetrics; import com.amazonaws.logging.LogFactory; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * Used to control the default AWS SDK metric collection system. *
* The default metric collection of the Java AWS SDK is disabled by default. To * enable it, simply specify the system property * "com.amazonaws.sdk.enableDefaultMetrics" when starting up the JVM. * When the system property is specified, a default metric collector will be * started at the AWS SDK level. The default implementation uploads the * request/response metrics captured to Amazon CloudWatch using AWS credentials * obtained via the {@link DefaultAWSCredentialsProviderChain}. *
* For additional optional attributes that can be specified for the system * property, please read the javadoc of the individual fields of this class for * more details. *
* Instead of via system properties, the default AWS SDK metric collection can * also be enabled programmatically via {@link #enableDefaultMetrics()}. * Similarly, metric collection at the AWS SDK level can be disabled via * {@link #disableMetrics()}. *
* Clients who needs to fully customize the metric collection can implement the * SPI {@link MetricCollector}, and then replace the default AWS SDK * implementation of the collector via * {@link #setMetricCollector(MetricCollector)}. *
* Alternatively, for limited customization of the internal collector * implementation provided by the AWS SDK, one can extend the internal Amazon * CloudWatch metric collector. See the javadoc at * com.amazonaws.metrics.internal.cloudwatch.CloudWatchMetricConfig for more * details. */ @SuppressWarnings("checkstyle:nowhitespacebefore") public enum AwsSdkMetrics { ; /** Constant for default metric namespace. */ public static final String DEFAULT_METRIC_NAMESPACE = "AWSSDK/Java"; private static final int QUEUE_POLL_TIMEOUT_MILLI_MINUMUM = 1000; private static final String MBEAN_OBJECT_NAME = "com.amazonaws.management:type=" + AwsSdkMetrics.class.getSimpleName(); /** * Used to enable the use of a single metric namespace for all levels of SDK * generated CloudWatch metrics such as JVM level, host level, etc. * *
     * Example:
     *  -Dcom.amazonaws.sdk.enableDefaultMetrics=useSingleMetricNamespace
     * 
     */
    public static final String USE_SINGLE_METRIC_NAMESPACE = "useSingleMetricNamespace";
    /**
     * Used to exclude the generation of JVM metrics when the AWS SDK default
     * metrics is enabled. By default, jvm metrics is included.
     *
     * 
     * Example:
     *  -Dcom.amazonaws.sdk.enableDefaultMetrics=excludeJvmMetrics
     * 
     */
    public static final String EXCLUDE_MACHINE_METRICS = "excludeMachineMetrics";
    /**
     * Used to generate per host level metrics when the AWS SDK default metrics
     * is enabled. By default, per-host level metrics is excluded.
     *
     * 
     * Example:
     *  -Dcom.amazonaws.sdk.enableDefaultMetrics=includePerHostMetrics
     * 
     */
    public static final String INCLUDE_PER_HOST_METRICS = "includePerHostMetrics";
    /**
     * Used to specify an AWS credential property file. By default, the
     * {@link DefaultAWSCredentialsProviderChain} is used.
     *
     * 
     * Example:
     *  -Dcom.amazonaws.sdk.enableDefaultMetrics=credentialFile=/path/aws.properties
     * 
     */
    public static final String AWS_CREDENTAIL_PROPERTIES_FILE = "credentialFile";
    /**
     * Used to specify the Amazon CloudWatch region for metrics uploading
     * purposes. By default, metrics are uploaded to us-east-1.
     *
     * 
     * Example:
     *  -Dcom.amazonaws.sdk.enableDefaultMetrics=cloudwatchRegion=us-west-2
     * 
     */
    public static final String CLOUDWATCH_REGION = "cloudwatchRegion";
    /**
     * Used to specify the internal in-memory queue size for queuing metrics
     * data points. The default size is 1,000.
     *
     * 
     * Example:
     *  -Dcom.amazonaws.sdk.enableDefaultMetrics=metricQueueSize=1000
     * 
     */
    public static final String METRIC_QUEUE_SIZE = "metricQueueSize";
    /**
     * Used to specify the internal queue polling timeout in millisecond. The
     * default timeout is 1 minute, which is optimal for the default CloudWatch
     * implementation.
     *
     * 
     * Example:
     *  -Dcom.amazonaws.sdk.enableDefaultMetrics=getQueuePollTimeoutMilli=60000
     * 
     */
    public static final String QUEUE_POLL_TIMEOUT_MILLI = "getQueuePollTimeoutMilli";
    /**
     * Used to specify a custom metric name space. The default name space is
     * {@link #DEFAULT_METRIC_NAMESPACE}.
     *
     * 
     * Example:
     *  -Dcom.amazonaws.sdk.enableDefaultMetrics=metricNameSpace=MyNameSpace
     * 
     */
    public static final String METRIC_NAME_SPACE = "metricNameSpace";
    /**
     * Used to generate per JVM level metrics when the AWS SDK default metrics
     * is enabled. By default, JVM level metrics are not generated.
     *
     * 
     * Example:
     *  -Dcom.amazonaws.sdk.enableDefaultMetrics=jvmMetricName=Tomcat1
     * 
     */
    public static final String JVM_METRIC_NAME = "jvmMetricName";
    /**
     * Used to explicitly specify the host name for metric purposes, instead of
     * detecting the host name via {@link InetAddress} when the AWS SDK default
     * metrics is enabled. Specifying the host name also has the side effecting
     * of enabling per host level metrics.
     *
     * 
     * Example:
     *  -Dcom.amazonaws.sdk.enableDefaultMetrics=hostMetricName=MyHost
     * 
     */
    public static final String HOST_METRIC_NAME = "hostMetricName";
    private static final String DEFAULT_METRIC_COLLECTOR_FACTORY =
            "com.amazonaws.metrics.internal.cloudwatch.DefaultMetricCollectorFactory";
    /**
     * True iff the system property {@link #DEFAULT_METRICS_SYSTEM_PROPERTY} has
     * been set; false otherwise.
     */
    private static final boolean DEFAULT_METRICS_ENABLED;
    private static volatile AWSCredentialsProvider credentialProvider;
    /**
     * True if machine metrics is to be excluded; false otherwise.
     */
    private static volatile boolean machineMetricsExcluded;
    /**
     * True if per-host metrics is to be included; false if per-host metrics is
     * to be excluded when {@link #hostMetricName} is not specified. In the
     * absence of {@link #hostMetricName}, the host name will be automatically
     * detected via {@link InetAddress}.
     */
    private static volatile boolean perHostMetricsIncluded;
    private static volatile Regions region;
    private static volatile Integer metricQueueSize;
    private static volatile Long queuePollTimeoutMilli;
    private static volatile String metricNameSpace = DEFAULT_METRIC_NAMESPACE;
    private static volatile String credentialFile;
    /**
     * No JVM level metrics is generated if this field is set to null or blank.
     * Otherwise, the value in this field is used to compose the metric name
     * space. Example:
     * 
     * Caller of this method is responsible for starting the new metric
     * collector specified as the input parameter.
     *
     * @param mc the metric collector to be used by the AWS SDK; or null if no
     *            metric collection is to be performed at the AWS SDK level.
     * @see RequestMetricCollector
     * @see RequestMetricCollector#NONE
     */
    @SuppressWarnings("checkstyle:hiddenfield")
    public static synchronized void setMetricCollector(MetricCollector mc) {
        MetricCollector old = AwsSdkMetrics.mc;
        AwsSdkMetrics.mc = mc;
        if (old != null) {
            old.stop();
        }
    }
    /**
     * Used to set whether the machine metrics is to be excluded.
     *
     * @param excludeMachineMetrics true if machine metrics is to be excluded;
     *            false otherwise.
     */
    public static void setMachineMetricsExcluded(boolean excludeMachineMetrics) {
        AwsSdkMetrics.machineMetricsExcluded = excludeMachineMetrics;
    }
    /**
     * Used to set whether the per-host metrics is to be included.
     *
     * @param includePerHostMetrics true if per-host metrics is to be included;
     *            false otherwise.
     */
    public static void setPerHostMetricsIncluded(boolean includePerHostMetrics) {
        AwsSdkMetrics.perHostMetricsIncluded = includePerHostMetrics;
    }
    /**
     * @return true if the system property
     * {@link SDKGlobalConfiguration#DEFAULT_METRICS_SYSTEM_PROPERTY} has been
     * set; false otherwise.
     */
    public static boolean isDefaultMetricsEnabled() {
        return DEFAULT_METRICS_ENABLED;
    }
    /**
     * @return true if a single metric name space is to be used for all levels
     * of SDK generated CloudWatch metrics, including JVM level, host level,
     * etc.; false otherwise.
     */
    public static boolean isSingleMetricNamespace() {
        return singleMetricNamespace;
    }
    /**
     * Used to set whether a single metric name space is to be used for all
     * levels of SDK generated CloudWatch metrics, including JVM level, host
     * level, etc.
     *
     * @param singleMetricNamespace true if single metric name is to be used;
     *            false otherwise.
     */
    public static void setSingleMetricNamespace(boolean singleMetricNamespace) {
        AwsSdkMetrics.singleMetricNamespace = singleMetricNamespace;
    }
    /**
     * @return true if metrics at the AWS SDK level is enabled; false if
     * disabled.
     */
    @SuppressWarnings("checkstyle:hiddenfield")
    public static boolean isMetricsEnabled() {
        MetricCollector mc = AwsSdkMetrics.mc;
        return mc != null && mc.isEnabled();
    }
    /**
     * @return true if machine metrics is to be excluded.
     */
    public static boolean isMachineMetricExcluded() {
        return machineMetricsExcluded;
    }
    /**
     * @return true if the per-host metrics flag has been set; false otherwise.
     */
    public static boolean isPerHostMetricIncluded() {
        return perHostMetricsIncluded;
    }
    /**
     * @return true if per-host metrics is enabled; false otherwise.
     */
    public static boolean isPerHostMetricEnabled() {
        if (perHostMetricsIncluded)
            return true;
        String host = hostMetricName;
        host = host == null ? "" : host.trim();
        return host.length() > 0;
    }
    /**
     * Starts the default AWS SDK metric collector, but only if no metric
     * collector is currently in use at the AWS SDK level.
     *
     * @return true if the default AWS SDK metric collector has been
     *         successfully started by this call; false otherwise.
     */
    public static synchronized boolean enableDefaultMetrics() {
        if (mc == null || !mc.isEnabled()) {
            if (dirtyEnabling) {
                throw new IllegalStateException("Reentrancy is not allowed");
            }
            dirtyEnabling = true;
            try {
                Class> c = Class.forName(DEFAULT_METRIC_COLLECTOR_FACTORY);
                MetricCollector.Factory f = (MetricCollector.Factory) c.newInstance();
                MetricCollector instance = f.getInstance();
                if (instance != null) {
                    setMetricCollector(instance);
                    return true;
                }
            } catch (Exception e) {
                LogFactory.getLog(AwsSdkMetrics.class)
                        .warn("Failed to enable the default metrics", e);
            } finally {
                dirtyEnabling = false;
            }
        }
        return false;
    }
    /**
     * Convenient method to disable the metric collector at the AWS SDK level.
     */
    public static void disableMetrics() {
        setMetricCollector(MetricCollector.NONE);
    }
    /**
     * Adds the given metric type to the REGISTRY of predefined metrics to be
     * captured at the AWS SDK level.
     * @param type the metric type.
     * @return true if the set of predefined metric types gets changed as a
     *         result of the call
     */
    public static boolean add(MetricType type) {
        return type == null ? false : REGISTRY.addMetricType(type);
    }
    /**
     * Adds the given metric types to the REGISTRY of predefined metrics to be
     * captured at the AWS SDK level.
     * @param types the collection of metric types.
     * @param