All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.metrics.AwsSdkMetrics Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2010-2015 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 java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.LogFactory;

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;

/**
 * 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. */ public enum AwsSdkMetrics { ; public static final String DEFAULT_METRIC_NAMESPACE = "AWSSDK/Java"; 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 defaultMetricsEnabled; 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: *
    *
  1. If jvmMetricName="Tomcat1" and host-level metrics is disabled, the * metric name space will be something like: "AWSSDK/Java/Tomcat1".
  2. *
  3. If jvmMetricName="Tomcat1" and host-level metrics is enabled, the * metric name space will be something like: * "AWSSDK/Java/myhost.mycompany.com/Tomcat1".
  4. *
  5. If jvmMetricName="Tomcat1" and host-level metrics is enabled and the * metricNameSpace="MyNameSpace", the metric name space will be something * like: "MyNameSpace/myhost.mycompany.com/Tomcat1".
  6. *
*/ private static volatile String jvmMetricName; private static volatile String hostMetricName; /** * True if the same metric namespace is to be used for all levels (such as * JVM level, host-level, etc.) of AWS Cloudwatch Metrics for the Java SDK; * false otherwise. */ private static volatile boolean singleMetricNamespace; static { String defaultMetrics = System.getProperty(DEFAULT_METRICS_SYSTEM_PROPERTY); defaultMetricsEnabled = defaultMetrics != null; if (defaultMetricsEnabled) { String[] values = defaultMetrics.split(","); boolean excludeMachineMetrics = false; boolean includePerHostMetrics = false; boolean useSingleMetricNamespace = false; for (String s: values) { String part = s.trim(); if (!excludeMachineMetrics && EXCLUDE_MACHINE_METRICS.equals(part)) { excludeMachineMetrics = true; } else if (!includePerHostMetrics && INCLUDE_PER_HOST_METRICS.equals(part)) { includePerHostMetrics = true; } else if (!useSingleMetricNamespace && USE_SINGLE_METRIC_NAMESPACE.equals(part)) { useSingleMetricNamespace = true; } else { String[] pair = part.split("="); if (pair.length == 2) { String key = pair[0].trim(); String value = pair[1].trim(); try { if (AWS_CREDENTAIL_PROPERTIES_FILE.equals(key)) { setCredentialFile0(value); } else if (CLOUDWATCH_REGION.equals(key)) { region = Regions.fromName(value); } else if (METRIC_QUEUE_SIZE.equals(key)) { Integer i = new Integer(value); if (i.intValue() < 1) throw new IllegalArgumentException(METRIC_QUEUE_SIZE + " must be at least 1"); metricQueueSize = i; } else if (QUEUE_POLL_TIMEOUT_MILLI.equals(key)) { Long i = new Long(value); if (i.intValue() < 1000) throw new IllegalArgumentException(QUEUE_POLL_TIMEOUT_MILLI + " must be at least 1000"); queuePollTimeoutMilli = i; } else if (METRIC_NAME_SPACE.equals(key)) { metricNameSpace = value; } else if (JVM_METRIC_NAME.equals(key)) { jvmMetricName = value; } else if (HOST_METRIC_NAME.equals(key)) { hostMetricName = value; } else { LogFactory.getLog(AwsSdkMetrics.class).debug("Ignoring unrecognized parameter: " + part); } } catch (Exception e) { LogFactory.getLog(AwsSdkMetrics.class).debug("Ignoring failure", e); } } } } machineMetricsExcluded = excludeMachineMetrics; perHostMetricsIncluded = includePerHostMetrics; singleMetricNamespace = useSingleMetricNamespace; } } private static final MetricRegistry registry = new MetricRegistry(); private static volatile MetricCollector mc; /** * Used to disallow re-entrancy in enabling the default metric collection system. */ private static boolean dirtyEnabling; /** * Returns a non-null request metric collector for the SDK. If no custom * request metric collector has previously been specified via * {@link #setMetricCollector(MetricCollector)} and the * {@link SDKGlobalConfiguration#DEFAULT_METRICS_SYSTEM_PROPERTY} has been set, then this method * will initialize and return the default metric collector provided by the * AWS SDK on a best-attempt basis. */ public static T getRequestMetricCollector() { if (mc == null) { if (isDefaultMetricsEnabled()) enableDefaultMetrics(); } @SuppressWarnings("unchecked") T t = (T)(mc == null ? RequestMetricCollector.NONE : mc.getRequestMetricCollector()); return t; } public static T getServiceMetricCollector() { if (mc == null) { if (isDefaultMetricsEnabled()) enableDefaultMetrics(); } @SuppressWarnings("unchecked") T t = (T)(mc == null ? ServiceMetricCollector.NONE : mc.getServiceMetricCollector()); return t; } /** * This method should never be called by anyone except the JMX MBean used * for administrative purposes only. */ static MetricCollector getInternalMetricCollector() { return mc; } public static T getMetricCollector() { if (mc == null) { if (isDefaultMetricsEnabled()) enableDefaultMetrics(); } @SuppressWarnings("unchecked") T t = (T)(mc == null ? MetricCollector.NONE : mc); return t; } /** * Sets the metric collector to be used by the AWS SDK, and stop the * previously running collector used by the AWS SDK, if any. Note, however, * a request metric collector specified at the web service client level or * request level, if any, always takes precedence over the one specified at * the AWS SDK level. *

* 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 */ 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; } /** * Returns true if the system property * {@link SDKGlobalConfiguration#DEFAULT_METRICS_SYSTEM_PROPERTY} has been * set; false otherwise. */ public static boolean isDefaultMetricsEnabled() { return defaultMetricsEnabled; } /** * Returns 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; } /** * Returns true if metrics at the AWS SDK level is enabled; false * if disabled. */ public static boolean isMetricsEnabled() { MetricCollector mc = AwsSdkMetrics.mc; return mc != null && mc.isEnabled(); } /** * Returns true if machine metrics is to be excluded. */ public static boolean isMachineMetricExcluded() { return machineMetricsExcluded; } /** * Returns true if the per-host metrics flag has been set; false otherwise. */ public static boolean isPerHostMetricIncluded() { return perHostMetricsIncluded; } /** * Returns 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. * * @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. * * @return true if the set of predefined metric types gets changed as a * result of the call */ public static boolean addAll(Collection types) { return types == null || types.size() == 0 ? false : registry.addMetricTypes(types); } /** * Sets the given metric types to replace the registry of predefined metrics * to be captured at the AWS SDK level. */ public static void set(Collection types) { registry.setMetricTypes(types); } /** * Removes the given metric type from the registry of predefined metrics to * be captured at the AWS SDK level. * * @return true if the set of predefined metric types gets changed as a * result of the call */ public static boolean remove(MetricType type) { return type == null ? false : registry.removeMetricType(type); } /** * Returns an unmodifiable set of the current predefined metrics. */ public static Set getPredefinedMetrics() { return registry.predefinedMetrics(); } /** * Returns the credential provider for the default AWS SDK metric implementation. * This method is restricted to calls from the default AWS SDK metric implementation. * * @throws SecurityException if called outside the default AWS SDK metric implementation. */ public static AWSCredentialsProvider getCredentialProvider() { StackTraceElement[] e = Thread.currentThread().getStackTrace(); for (int i=0; i < e.length; i++) { if (e[i].getClassName().equals(DEFAULT_METRIC_COLLECTOR_FACTORY)) { return credentialProvider; } } SecurityException ex = new SecurityException(); LogFactory.getLog(AwsSdkMetrics.class).warn("Illegal attempt to access the credential provider", ex); throw ex; } /** * Sets the credential provider for the default AWS SDK metric * implementation; or null if the default is to be used. Calling this method * may result in the credential provider being different from the credential * file property. */ public static synchronized void setCredentialProvider( AWSCredentialsProvider provider) { credentialProvider = provider; } /** * Returns the region configured for the default AWS SDK metric collector; * or null if the default is to be used. */ public static Regions getRegion() { return region; } /** * Sets the region to be used for the default AWS SDK metric collector; * or null if the default is to be used. */ public static void setRegion(Regions region) { AwsSdkMetrics.region = region; } /** * Returns the last set AWS credential file, or null if there is none. */ public static String getCredentailFile() { return credentialFile; } /** * Sets the AWS credential file to be used for accessing Amazon CloudWatch. * Successfully calling this method would result in the AWS credential * provider to make use of the given credential file. */ public static void setCredentialFile(String filepath) throws FileNotFoundException, IOException { setCredentialFile0(filepath); } /** * Internal method to implement the {@link #setCredentialFile(String)}. */ private static void setCredentialFile0(String filepath) throws FileNotFoundException, IOException { final PropertiesCredentials cred = new PropertiesCredentials(new File(filepath)); synchronized(AwsSdkMetrics.class) { credentialProvider = new AWSCredentialsProvider() { @Override public void refresh() {} @Override public AWSCredentials getCredentials() { return cred; } }; AwsSdkMetrics.credentialFile = filepath; } } /** * Returns the internal metric queue size to be used for the default AWS SDK * metric collector; or null if the default is to be used. */ public static Integer getMetricQueueSize() { return metricQueueSize; } /** * Sets the metric queue size to be used for the default AWS SDK metric collector; * or null if the default is to be used. */ public static void setMetricQueueSize(Integer size) { metricQueueSize = size; } /** * Returns the internal metric queue timeout in millisecond to be used for * the default AWS SDK metric collector; or null if the default is to be * used. */ public static Long getQueuePollTimeoutMilli() { return queuePollTimeoutMilli; } /** * Sets the queue poll time in millisecond to be used for the default AWS * SDK metric collector; or null if the default is to be used. */ public static void setQueuePollTimeoutMilli(Long timeoutMilli) { queuePollTimeoutMilli = timeoutMilli; } /** * Returns the metric name space, which is never null or blank. */ public static String getMetricNameSpace() { return metricNameSpace; } /** * Sets the metric name space. * * @param metricNameSpace * metric name space which must neither be null or blank. * * @throws IllegalArgumentException * if the specified metric name space is either null or blank. */ public static void setMetricNameSpace(String metricNameSpace) { if (metricNameSpace == null || metricNameSpace.trim().length() == 0) throw new IllegalArgumentException(); AwsSdkMetrics.metricNameSpace = metricNameSpace; } /** * Returns the name of the JVM for generating per-JVM level metrics; * or null or blank if per-JVM level metrics are disabled. */ public static String getJvmMetricName() { return jvmMetricName; } /** * Sets the name of the JVM for generating per-JVM level metrics. * * @param jvmMetricName * name of the JVM for generating per-JVM level metrics; or null * or blank if per-JVM level metrics are to be disabled. */ public static void setJvmMetricName(String jvmMetricName) { AwsSdkMetrics.jvmMetricName = jvmMetricName; } /** * Returns the host name for generating per-host level metrics; or * null or blank if the host is to be automatically detected via * {@link InetAddress}. */ public static String getHostMetricName() { return hostMetricName; } /** * Sets the host name for generating per-host level metrics. * * @param hostMetricName * host name for generating per-host level metrics; or * null or blank if the host is to be automatically detected via * {@link InetAddress}. */ public static void setHostMetricName(String hostMetricName) { AwsSdkMetrics.hostMetricName = hostMetricName; } /** * Used as a registry for the predefined metrics to be captured by the * metric collector at the AWS SDK level. */ private static class MetricRegistry { private final Set metricTypes = new HashSet(); private volatile Set readOnly; MetricRegistry() { metricTypes.add(Field.ClientExecuteTime); metricTypes.add(Field.Exception); metricTypes.add(Field.HttpClientRetryCount); metricTypes.add(Field.HttpRequestTime); metricTypes.add(Field.RequestCount); // metricTypes.add(Field.RequestSigningTime); // metricTypes.add(Field.ResponseProcessingTime); metricTypes.add(Field.RetryCount); metricTypes.add(Field.HttpClientSendRequestTime); metricTypes.add(Field.HttpClientReceiveResponseTime); metricTypes.add(Field.HttpClientPoolAvailableCount); metricTypes.add(Field.HttpClientPoolLeasedCount); metricTypes.add(Field.HttpClientPoolPendingCount); metricTypes.add(AWSServiceMetrics.HttpClientGetConnectionTime); syncReadOnly(); } private void syncReadOnly() { readOnly = Collections.unmodifiableSet(new HashSet(metricTypes)); } public boolean addMetricType(MetricType type) { synchronized(metricTypes) { boolean added = metricTypes.add(type); if (added) syncReadOnly(); return added; } } public boolean addMetricTypes(Collection types) { synchronized(metricTypes) { boolean added = metricTypes.addAll(types); if (added) syncReadOnly(); return added; } } public void setMetricTypes(Collection types) { synchronized(metricTypes) { if (types == null || types.size() == 0) { if (metricTypes.size() == 0) return; if (types == null) types = Collections.emptyList(); } metricTypes.clear(); if (!addMetricTypes(types)) { syncReadOnly(); // avoid missing sync } } } public boolean removeMetricType(MetricType type) { synchronized(metricTypes) { boolean removed = metricTypes.remove(type); if (removed) syncReadOnly(); return removed; } } public Set predefinedMetrics() { return readOnly; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy