com.amazonaws.metrics.AwsSdkMetrics Maven / Gradle / Ivy
Show all versions of aws-android-sdk-mobileanalytics Show documentation
/*
* 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;
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:
*
* - If jvmMetricName="Tomcat1" and host-level metrics is disabled, the
* metric name space will be something like: "AWSSDK/Java/Tomcat1".
* - If jvmMetricName="Tomcat1" and host-level metrics is enabled, the
* metric name space will be something like:
* "AWSSDK/Java/myhost.mycompany.com/Tomcat1".
* - 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".
*
*/
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;
}
}
}