Core foundational library for AWS SDK for Java 1.x providing authentication, HTTP transport, regions, protocols, and shared utilities for all AWS service clients
—
The AWS Java SDK Core provides comprehensive metrics collection and monitoring capabilities, including client-side monitoring (CSM), request metrics, JMX integration, and custom metric collection for performance analysis and operational insights.
// Main SDK metrics class
class AwsSdkMetrics {
// Global metrics control
public static boolean isDefaultMetricsEnabled();
public static void setDefaultMetricsEnabled(boolean enabled);
// Request metric collector management
public static RequestMetricCollector getRequestMetricCollector();
public static void setRequestMetricCollector(RequestMetricCollector requestMetricCollector);
// Machine metrics
public static boolean isMachineMetricExcluded(MetricType metricType);
public static void setMachineMetricExcluded(MetricType metricType, boolean exclude);
// Predefined collectors
public static final RequestMetricCollector NONE;
}
// Request metric collector interface
interface RequestMetricCollector {
void collectMetrics(Request<?> request, Response<?> response);
void collectMetrics(Request<?> request, Response<?> response, Exception exception);
// Default implementation
RequestMetricCollector NONE = new RequestMetricCollector() {
public void collectMetrics(Request<?> request, Response<?> response) {}
public void collectMetrics(Request<?> request, Response<?> response, Exception exception) {}
};
}// Base metric type interface
interface MetricType {
String name();
}
// Request metric types enumeration
enum RequestMetricType implements MetricType {
// HTTP client metrics
HttpClientRetryCount("HttpClientRetryCount"),
HttpClientPoolAvailableCount("HttpClientPoolAvailableCount"),
HttpClientPoolLeasedCount("HttpClientPoolLeasedCount"),
HttpClientPoolPendingCount("HttpClientPoolPendingCount"),
// Timing metrics
HttpRequestTime("HttpRequestTime"),
HttpResponseTime("HttpResponseTime"),
ResponseProcessingTime("ResponseProcessingTime"),
RequestExecutionTime("RequestExecutionTime"),
RequestSigningTime("RequestSigningTime"),
// Data transfer metrics
RequestCount("RequestCount"),
RetryCount("RetryCount"),
ThrottledRetryCount("ThrottledRetryCount"),
ResponseSize("ResponseSize"),
RequestSize("RequestSize"),
// Error metrics
ClientExecuteTime("ClientExecuteTime"),
Exception("Exception"),
ThrottleException("ThrottleException");
private final String metricName;
RequestMetricType(String metricName) {
this.metricName = metricName;
}
public String name() {
return metricName;
}
}
// Service-specific metric type interface
interface ServiceMetricType extends MetricType {
String getServiceName();
}
// Simple service metric implementation
class SimpleServiceMetricType implements ServiceMetricType {
public SimpleServiceMetricType(String metricName, String serviceName);
public String name();
public String getServiceName();
}
// Throughput metric type interface
interface ThroughputMetricType extends MetricType {
// Marker interface for throughput metrics
}
// Simple throughput metric implementation
class SimpleThroughputMetricType implements ThroughputMetricType {
public SimpleThroughputMetricType(String metricName);
public String name();
}// Administrative interface for metrics
interface MetricAdmin {
// Region management
String getRegion();
void setRegion(String region);
// Metric collection control
boolean isEnabled();
void setEnabled(boolean enabled);
// Queue management
Integer getRequestMetricQueueSize();
void setRequestMetricQueueSize(Integer requestMetricQueueSize);
// Predicate management
String getRequestMetricQueueSizePredicate();
void setRequestMetricQueueSizePredicate(String requestMetricQueueSizePredicate);
// Host management
String getMetricNameSpace();
void setMetricNameSpace(String metricNameSpace);
String getJvmMetricName();
void setJvmMetricName(String jvmMetricName);
String getHostMetricName();
void setHostMetricName(String hostMetricName);
// Credential provider
String getCredentialProvider();
void setCredentialProvider(String credentialProvider);
}
// JMX MBean for metrics administration
interface MetricAdminMBean extends MetricAdmin {
// Inherits all MetricAdmin methods for JMX exposure
}
// Service latency provider interface
interface ServiceLatencyProvider {
Double getServiceLatency(ServiceMetricType serviceMetricType);
int getSampleCount(ServiceMetricType serviceMetricType);
boolean isEnabled();
}// Input stream with metrics collection
class MetricFilterInputStream extends FilterInputStream {
public MetricFilterInputStream(InputStream in);
public int read() throws IOException;
public int read(byte[] b, int off, int len) throws IOException;
public long skip(long n) throws IOException;
public void close() throws IOException;
// Metrics access
public long getBytesRead();
public long getReadCount();
}
// HTTP entity with metrics collection
class MetricInputStreamEntity extends InputStreamEntity {
public MetricInputStreamEntity(InputStream instream, long length);
public MetricInputStreamEntity(InputStream instream, long length, ContentType contentType);
public InputStream getContent() throws IOException;
public void writeTo(OutputStream outstream) throws IOException;
// Metrics access
public long getBytesRead();
public long getBytesWritten();
}// Base class for monitoring events
abstract class MonitoringEvent {
public abstract String toJsonString();
public abstract MonitoringEvent withTimestamp(Date timestamp);
public Date getTimestamp();
public String getVersion();
public String getUserAgent();
}
// Monitoring event for API calls
class ApiCallMonitoringEvent extends MonitoringEvent {
// Service information
public ApiCallMonitoringEvent withService(String service);
public ApiCallMonitoringEvent withApi(String api);
public ApiCallMonitoringEvent withVersion(int version);
public ApiCallMonitoringEvent withUserAgent(String userAgent);
public ApiCallMonitoringEvent withRegion(String region);
// Timing information
public ApiCallMonitoringEvent withTimestamp(Date timestamp);
public ApiCallMonitoringEvent withLatency(Integer latency);
// Attempt information
public ApiCallMonitoringEvent withAttemptCount(Integer attemptCount);
public ApiCallMonitoringEvent withMaxRetriesExceeded(Integer maxRetriesExceeded);
// Result information
public ApiCallMonitoringEvent withFinalHttpStatusCode(Integer finalHttpStatusCode);
public ApiCallMonitoringEvent withFinalAwsException(String finalAwsException);
public ApiCallMonitoringEvent withFinalAwsExceptionMessage(String finalAwsExceptionMessage);
public ApiCallMonitoringEvent withFinalSdkException(String finalSdkException);
public ApiCallMonitoringEvent withFinalSdkExceptionMessage(String finalSdkExceptionMessage);
// Getters
public String getService();
public String getApi();
public Integer getVersion();
public String getRegion();
public Integer getLatency();
public Integer getAttemptCount();
public Integer getMaxRetriesExceeded();
public Integer getFinalHttpStatusCode();
public String getFinalAwsException();
public String getFinalAwsExceptionMessage();
public String getFinalSdkException();
public String getFinalSdkExceptionMessage();
public String toJsonString();
}
// Monitoring event for API call attempts
class ApiCallAttemptMonitoringEvent extends MonitoringEvent {
// Service information
public ApiCallAttemptMonitoringEvent withService(String service);
public ApiCallAttemptMonitoringEvent withApi(String api);
public ApiCallAttemptMonitoringEvent withVersion(int version);
public ApiCallAttemptMonitoringEvent withUserAgent(String userAgent);
public ApiCallAttemptMonitoringEvent withRegion(String region);
// Timing information
public ApiCallAttemptMonitoringEvent withTimestamp(Date timestamp);
public ApiCallAttemptMonitoringEvent withLatency(Integer latency);
// Attempt information
public ApiCallAttemptMonitoringEvent withAttemptLatency(Integer attemptLatency);
public ApiCallAttemptMonitoringEvent withFqdn(String fqdn);
// HTTP information
public ApiCallAttemptMonitoringEvent withHttpStatusCode(Integer httpStatusCode);
public ApiCallAttemptMonitoringEvent withAwsException(String awsException);
public ApiCallAttemptMonitoringEvent withAwsExceptionMessage(String awsExceptionMessage);
public ApiCallAttemptMonitoringEvent withSdkException(String sdkException);
public ApiCallAttemptMonitoringEvent withSdkExceptionMessage(String sdkExceptionMessage);
// Getters
public String getService();
public String getApi();
public Integer getVersion();
public String getRegion();
public Integer getLatency();
public Integer getAttemptLatency();
public String getFqdn();
public Integer getHttpStatusCode();
public String getAwsException();
public String getAwsExceptionMessage();
public String getSdkException();
public String getSdkExceptionMessage();
public String toJsonString();
}// Client-side monitoring configuration
class CsmConfiguration {
// Configuration parameters
public CsmConfiguration withEnabled(boolean enabled);
public CsmConfiguration withHost(String host);
public CsmConfiguration withPort(int port);
public CsmConfiguration withClientId(String clientId);
// Getters
public boolean isEnabled();
public String getHost();
public int getPort();
public String getClientId();
// Default values
public static final String DEFAULT_HOST = "127.0.0.1";
public static final int DEFAULT_PORT = 31000;
public static final boolean DEFAULT_ENABLED = false;
}
// CSM configuration provider interface
interface CsmConfigurationProvider {
CsmConfiguration getConfiguration() throws SdkClientException;
}
// CSM configuration provider chain
class CsmConfigurationProviderChain implements CsmConfigurationProvider {
public CsmConfigurationProviderChain(CsmConfigurationProvider... providers);
public CsmConfiguration getConfiguration() throws SdkClientException;
}
// Static CSM configuration provider
class StaticCsmConfigurationProvider implements CsmConfigurationProvider {
public StaticCsmConfigurationProvider(CsmConfiguration configuration);
public CsmConfiguration getConfiguration();
}
// Default CSM configuration provider chain
class DefaultCsmConfigurationProviderChain extends CsmConfigurationProviderChain {
public static DefaultCsmConfigurationProviderChain getInstance();
public CsmConfiguration getConfiguration() throws SdkClientException;
}import com.amazonaws.metrics.*;
import com.amazonaws.*;
// Enable default metrics collection
AwsSdkMetrics.setDefaultMetricsEnabled(true);
// Check if metrics are enabled
boolean metricsEnabled = AwsSdkMetrics.isDefaultMetricsEnabled();
System.out.println("Metrics enabled: " + metricsEnabled);
// Get current metric collector
RequestMetricCollector collector = AwsSdkMetrics.getRequestMetricCollector();
System.out.println("Current collector: " + collector.getClass().getSimpleName());import com.amazonaws.metrics.*;
import com.amazonaws.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
public class CustomMetricCollector implements RequestMetricCollector {
private final Map<MetricType, AtomicLong> counters = new ConcurrentHashMap<>();
private final Map<MetricType, AtomicLong> timings = new ConcurrentHashMap<>();
@Override
public void collectMetrics(Request<?> request, Response<?> response) {
// Collect successful request metrics
incrementCounter(RequestMetricType.RequestCount);
if (response != null && response.getAwsResponse() != null) {
// Track response processing time
Long processingTime = getTimingValue(request, RequestMetricType.ResponseProcessingTime);
if (processingTime != null) {
addTiming(RequestMetricType.ResponseProcessingTime, processingTime);
}
// Track HTTP response time
Long httpTime = getTimingValue(request, RequestMetricType.HttpResponseTime);
if (httpTime != null) {
addTiming(RequestMetricType.HttpResponseTime, httpTime);
}
}
}
@Override
public void collectMetrics(Request<?> request, Response<?> response, Exception exception) {
// Collect error metrics
incrementCounter(RequestMetricType.Exception);
if (exception instanceof AmazonServiceException) {
AmazonServiceException ase = (AmazonServiceException) exception;
if (ase.getErrorCode() != null && ase.getErrorCode().contains("Throttl")) {
incrementCounter(RequestMetricType.ThrottleException);
}
}
// Track retry count
Integer retryCount = getRetryCount(request);
if (retryCount != null && retryCount > 0) {
addTiming(RequestMetricType.RetryCount, retryCount.longValue());
}
}
private void incrementCounter(MetricType metricType) {
counters.computeIfAbsent(metricType, k -> new AtomicLong(0)).incrementAndGet();
}
private void addTiming(MetricType metricType, long value) {
timings.computeIfAbsent(metricType, k -> new AtomicLong(0)).addAndGet(value);
}
private Long getTimingValue(Request<?> request, MetricType metricType) {
// Extract timing values from request context
// Implementation depends on specific metric collection setup
return null;
}
private Integer getRetryCount(Request<?> request) {
// Extract retry count from request
// Implementation depends on request context setup
return null;
}
// Metrics reporting methods
public long getCounter(MetricType metricType) {
AtomicLong counter = counters.get(metricType);
return counter != null ? counter.get() : 0;
}
public long getTiming(MetricType metricType) {
AtomicLong timing = timings.get(metricType);
return timing != null ? timing.get() : 0;
}
public void printMetrics() {
System.out.println("=== Request Metrics ===");
for (Map.Entry<MetricType, AtomicLong> entry : counters.entrySet()) {
System.out.println(entry.getKey().name() + ": " + entry.getValue().get());
}
System.out.println("=== Timing Metrics ===");
for (Map.Entry<MetricType, AtomicLong> entry : timings.entrySet()) {
System.out.println(entry.getKey().name() + ": " + entry.getValue().get() + "ms");
}
}
}
// Use custom collector
CustomMetricCollector customCollector = new CustomMetricCollector();
AwsSdkMetrics.setRequestMetricCollector(customCollector);
// After some AWS operations...
customCollector.printMetrics();import com.amazonaws.metrics.*;
// Define service-specific metrics
ServiceMetricType s3PutObjectMetric = new SimpleServiceMetricType("PutObjectLatency", "S3");
ServiceMetricType dynamoQueryMetric = new SimpleServiceMetricType("QueryLatency", "DynamoDB");
ThroughputMetricType uploadThroughput = new SimpleThroughputMetricType("UploadThroughput");
// Custom service metric collector
public class ServiceMetricCollector implements RequestMetricCollector {
private final Map<ServiceMetricType, List<Double>> serviceLatencies = new ConcurrentHashMap<>();
@Override
public void collectMetrics(Request<?> request, Response<?> response) {
String serviceName = extractServiceName(request);
String operationName = extractOperationName(request);
Long latency = extractLatency(request);
if (serviceName != null && operationName != null && latency != null) {
ServiceMetricType metricType = new SimpleServiceMetricType(
operationName + "Latency", serviceName
);
serviceLatencies.computeIfAbsent(metricType, k -> new ArrayList<>())
.add(latency.doubleValue());
}
}
@Override
public void collectMetrics(Request<?> request, Response<?> response, Exception exception) {
// Handle error metrics for services
String serviceName = extractServiceName(request);
if (serviceName != null) {
ServiceMetricType errorMetric = new SimpleServiceMetricType(
"ErrorCount", serviceName
);
// Track error counts...
}
}
public double getAverageLatency(ServiceMetricType metricType) {
List<Double> latencies = serviceLatencies.get(metricType);
if (latencies == null || latencies.isEmpty()) {
return 0.0;
}
return latencies.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
}
public double getMaxLatency(ServiceMetricType metricType) {
List<Double> latencies = serviceLatencies.get(metricType);
if (latencies == null || latencies.isEmpty()) {
return 0.0;
}
return latencies.stream().mapToDouble(Double::doubleValue).max().orElse(0.0);
}
private String extractServiceName(Request<?> request) {
// Extract service name from request
return request.getServiceName();
}
private String extractOperationName(Request<?> request) {
// Extract operation name from request
return request.getOriginalRequest().getClass().getSimpleName();
}
private Long extractLatency(Request<?> request) {
// Extract latency from request timing
// Implementation depends on request context
return null;
}
}import com.amazonaws.monitoring.*;
// Enable CSM via environment variables or system properties
// Environment: AWS_CSM_ENABLED=true, AWS_CSM_PORT=31000, AWS_CSM_HOST=127.0.0.1
// Programmatic CSM configuration
CsmConfiguration csmConfig = new CsmConfiguration()
.withEnabled(true)
.withHost("127.0.0.1")
.withPort(31000)
.withClientId("my-application");
// Static CSM configuration provider
CsmConfigurationProvider staticProvider = new StaticCsmConfigurationProvider(csmConfig);
// Use default provider chain (checks env vars, system properties, etc.)
CsmConfigurationProvider defaultProvider = DefaultCsmConfigurationProviderChain.getInstance();
try {
CsmConfiguration resolvedConfig = defaultProvider.getConfiguration();
System.out.println("CSM enabled: " + resolvedConfig.isEnabled());
System.out.println("CSM host: " + resolvedConfig.getHost());
System.out.println("CSM port: " + resolvedConfig.getPort());
} catch (SdkClientException e) {
System.err.println("CSM configuration error: " + e.getMessage());
}import com.amazonaws.monitoring.*;
import java.util.Date;
// Create API call monitoring event
ApiCallMonitoringEvent apiCallEvent = new ApiCallMonitoringEvent()
.withService("S3")
.withApi("PutObject")
.withVersion(1)
.withRegion("us-east-1")
.withTimestamp(new Date())
.withLatency(150)
.withAttemptCount(1)
.withFinalHttpStatusCode(200);
String apiCallJson = apiCallEvent.toJsonString();
System.out.println("API Call Event: " + apiCallJson);
// Create API call attempt monitoring event
ApiCallAttemptMonitoringEvent attemptEvent = new ApiCallAttemptMonitoringEvent()
.withService("S3")
.withApi("PutObject")
.withVersion(1)
.withRegion("us-east-1")
.withTimestamp(new Date())
.withLatency(150)
.withAttemptLatency(145)
.withFqdn("s3.amazonaws.com")
.withHttpStatusCode(200);
String attemptJson = attemptEvent.toJsonString();
System.out.println("Attempt Event: " + attemptJson);import com.amazonaws.metrics.*;
import java.io.*;
// Wrap input stream with metrics collection
InputStream originalStream = new FileInputStream("large-file.dat");
MetricFilterInputStream metricsStream = new MetricFilterInputStream(originalStream);
try {
// Read from the stream
byte[] buffer = new byte[8192];
int totalBytes = 0;
int bytesRead;
while ((bytesRead = metricsStream.read(buffer)) != -1) {
totalBytes += bytesRead;
// Process data...
}
// Get metrics after reading
long totalBytesRead = metricsStream.getBytesRead();
long readOperations = metricsStream.getReadCount();
System.out.println("Total bytes read: " + totalBytesRead);
System.out.println("Read operations: " + readOperations);
System.out.println("Average bytes per read: " + (totalBytesRead / readOperations));
} finally {
metricsStream.close();
}
// HTTP entity with metrics
InputStream entityStream = new ByteArrayInputStream("HTTP entity content".getBytes());
MetricInputStreamEntity metricsEntity = new MetricInputStreamEntity(entityStream, -1);
// Use in HTTP request...
ByteArrayOutputStream output = new ByteArrayOutputStream();
metricsEntity.writeTo(output);
System.out.println("Bytes written: " + metricsEntity.getBytesWritten());import com.amazonaws.metrics.*;
import javax.management.*;
import java.lang.management.ManagementFactory;
// Custom metrics MBean implementation
public class CustomMetricsMBean implements MetricAdminMBean {
private boolean enabled = true;
private String region = "us-east-1";
private Integer queueSize = 1000;
@Override
public String getRegion() { return region; }
@Override
public void setRegion(String region) { this.region = region; }
@Override
public boolean isEnabled() { return enabled; }
@Override
public void setEnabled(boolean enabled) {
this.enabled = enabled;
AwsSdkMetrics.setDefaultMetricsEnabled(enabled);
}
@Override
public Integer getRequestMetricQueueSize() { return queueSize; }
@Override
public void setRequestMetricQueueSize(Integer queueSize) {
this.queueSize = queueSize;
}
// Implement other MetricAdmin methods...
public String getRequestMetricQueueSizePredicate() { return null; }
public void setRequestMetricQueueSizePredicate(String predicate) {}
public String getMetricNameSpace() { return "AWS/SDK"; }
public void setMetricNameSpace(String nameSpace) {}
public String getJvmMetricName() { return "JVM"; }
public void setJvmMetricName(String name) {}
public String getHostMetricName() { return "Host"; }
public void setHostMetricName(String name) {}
public String getCredentialProvider() { return "DefaultProvider"; }
public void setCredentialProvider(String provider) {}
}
// Register MBean
try {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName = new ObjectName("com.amazonaws.metrics:type=MetricsAdmin");
CustomMetricsMBean mbean = new CustomMetricsMBean();
if (!server.isRegistered(objectName)) {
server.registerMBean(mbean, objectName);
System.out.println("Metrics MBean registered successfully");
}
} catch (Exception e) {
System.err.println("Failed to register metrics MBean: " + e.getMessage());
}Performance Impact: Be aware that metrics collection adds overhead; enable only necessary metrics in production.
Memory Management: Implement bounded collections for metric storage to prevent memory leaks.
Aggregation: Aggregate metrics over time windows rather than storing individual data points.
Sampling: Use sampling for high-volume operations to reduce metrics overhead.
Error Handling: Ensure metrics collection failures don't impact application functionality.
Storage: Consider external metrics storage systems (CloudWatch, Prometheus) for production use.
Monitoring: Monitor the metrics system itself for health and performance.
Security: Protect sensitive information in metrics (don't log credentials or PII).
Alerting: Set up alerts based on key metrics thresholds for operational awareness.
Documentation: Document custom metrics for operational teams and monitoring setup.
The metrics and monitoring system provides comprehensive observability into AWS SDK operations, enabling performance optimization, troubleshooting, and operational insights for production applications.
Install with Tessl CLI
npx tessl i tessl/maven-com-amazonaws--aws-java-sdk-core