

# Configuring service clients in the AWS SDK for Java 2.x
<a name="configuring-service-clients"></a>

To programmatically access AWS services, the SDK for Java 2.x uses a client object for each AWS service. For example, if your application needs to access Amazon EC2, you create an Amazon EC2 client object—an instance of the [Ec2Client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html) class—to interface with that service. You then use the service client to make requests to that AWS service. For most applications, you can use a [singleton instance of a service client](singleton-service-clients.md).



There are many ways to configure SDK behavior, but ultimately everything has to do with the behavior of service clients. Any configuration has no effect until your code creates a service client that uses the configuration.

Examples of the configuration that you provide are:
+ How your code authenticates with AWS when you call a service
+ The AWS Region you want a service client to use
+ Retry and timeout settings for service calls
+ HTTP proxy configuration

Refer to the [AWS SDKs and Tools Reference Guide](https://docs.aws.amazon.com/sdkref/latest/guide/) for settings, features, and other foundational concepts common to many of the AWS SDKs. 

**Topics**
+ [Client configuration externally](configuring-service-clients-ext.md)
+ [Client configuration in code](configuring-service-clients-code.md)
+ [Singleton service clients](singleton-service-clients.md)
+ [AWS Region](region-selection.md)
+ [Credentials providers](credentials.md)
+ [Retries](retry-strategy.md)
+ [Timeouts](timeouts.md)
+ [Observability](observability.md)
+ [Endpoints](endpoint-config.md)
+ [Configure HTTP clients](http-configuration.md)
+ [Interceptors](interceptors.md)

# Configuring service clients for the AWS SDK for Java 2.x externally
<a name="configuring-service-clients-ext"></a>

Many configuration settings can be handled outside of your code. When you handle configuration externally, it can apply to all your applications in the same Java process. Most configuration settings can be set as either environment variables, JVM system properties, or in a separate shared AWS `config` file. The shared `config` file can maintain separate sets of settings, called profiles, to provide different configurations for different environments or tests.

Most environment variables and shared `config` file settings are standardized and shared across AWS SDKs and tools to support consistent functionality across different programming languages and applications. In most cases, the JVM system properties that the SDK for Java can use mirror the environment variables.

See the *[AWS SDKs and Tools Reference Guide](https://docs.aws.amazon.com/sdkref/latest/guide/overview.html)* to learn about configuring your application through these methods, plus details on each cross-sdk setting. To see all the all settings that the SDK can resolve from the environment variables, JVM system properties, or configuration files, see the [Settings reference](https://docs.aws.amazon.com/sdkref/latest/guide/settings-reference.html) in the *AWS SDKs and Tools Reference Guide*.

## Configuration provider chain for client configuration
<a name="configuration-provider-chain"></a>

The SDK checks several places (or sources) to find configuration values.

1. Any explicit setting set in the code or on a service client itself takes precedence over anything else.

1. JVM system properties
   + For details on setting JVM system properties, see [How to set JVM system properties](https://docs.aws.amazon.com/sdkref/latest/guide/jvm-system-properties.html#jvm-sys-props-set) in the *AWS SDKs and Tools Reference Guide*.

1. Environment variables
   + For details on setting environment variables, see [environment variables](https://docs.aws.amazon.com/sdkref/latest/guide/environment-variables.html) in the *AWS SDKs and Tools Reference Guide*.
   + Note that you can configure environment variables for a shell at different levels of scope: system-wide, user-wide, and for a specific terminal session.

1. Shared `config` and `credentials` files
   + For details on setting up these files, see the [Shared `config` and `credentials` files](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html) in the *AWS SDKs and Tools Reference Guide*.

1. Any default value provided by the SDK source code itself is used last.
   + Some properties, such as Region, don't have a default. You must specify them either explicitly in code, in an environment setting, or in the shared `config` file. If the SDK can't resolve required configuration, API requests can fail at runtime.

Besides this general configuration chain, the SDK for Java 2.x also uses specialized provider chains including the [credentials provider chain](credentials-chain.md) and the [AWS Region provider chain](region-selection.md#default-region-provider-chain). These specialized chains add additional providers that take into account the environment that the SDK is running in. For example, in a container or an EC2 instance.

## Create a service client configured using external settings
<a name="create-client-ext-conf"></a>

You need to create a service client in your application to talk to an AWS service. Service clients are your essential connection to AWS services, handling all the complex communication details so you don't have to worry about them. They take care of important tasks like security, error handling, and retries automatically, letting you focus on building your application rather than dealing with technical complications.

### Use the `create()` method
<a name="create-client-ext-builder"></a>

If all configuration settings that you need are coming from external sources, you can create a service client with a simple method:

```
S3Client s3Client = S3Client.create();
```

The previous code snippet creates an `S3Client` instance. During creation, the SDK looks through the configuration provider chain for settings. Once the SDK finds a setting value, the value will be used even if configuration exists that is later in the chain.

For example, assume a users sets the JVM setting for the AWS Region by setting the system property `-Daws.region=us-west-2`. If the `AWS_REGION` environment variable is also set, its value is ignored.

The default region provider chain and the default credentials provider chain will also be used in the creation process. Somewhere in the chain, the SDK must resolve the AWS Region to use and find settings that enable it to retrieve credentials for signing requests. If the SDKs files to find those values, the client creation fails.

Although you can create a client by using this empty builder pattern, you generally use this pattern when you want to [add configuration in code](configuring-service-clients-code.md#conf-service-client-code-basic).

## SDK for Java 2.x environment variables and JVM system properties
<a name="java-ext-config"></a>

Beyond the [cross-sdk settings](https://docs.aws.amazon.com/sdkref/latest/guide/settings-reference.html#settingsPages) supported by most AWS SDKs, the SDK for Java 2.x provides the following settings.

**Note**  
These environment variables and JVM system properties are primarily intended for advanced use cases, testing, or specific deployment scenarios. In most application code, it's preferable to use the programmatic configuration options provided by the SDK's client builders for better type safety and IDE support.

### Container Credential Provider Environment Variables
<a name="java-cred-profvider-envars"></a>

In addition to the standard container credential environment variables documented in the reference guide, the SDK also supports:

`AWS_CONTAINER_SERVICE_ENDPOINT`–This environment variable specifies the endpoint for the container metadata service when using the container credentials provider.

Java system property: `aws.containerServiceEndpoint`

Default value: `http://169.254.170.2`

### HTTP Client Implementation Environment Variables
<a name="java-http-cli-impl-envars"></a>

`SYNC_HTTP_SERVICE_IMPL`–Explicitly identifies the default [synchronous HTTP implementation](http-configuration.md#http-config-sync) the SDK will use. This is useful when there are multiple implementations on the classpath or as a performance optimization since implementation discovery requires classpath scanning.

Java system property: `software.amazon.awssdk.http.service.impl`

`ASYNC_HTTP_SERVICE_IMPL`–Explicitly identifies the default [asynchronous HTTP implementation](http-configuration.md#http-config-async) the SDK will use. This is useful when there are multiple implementations on the classpath or as a performance optimization since implementation discovery requires classpath scanning.

Java system property: `software.amazon.awssdk.http.async.service.impl`

# Configuring service clients in code for the AWS SDK for Java 2.x
<a name="configuring-service-clients-code"></a>

As an alternative to—or in addition to—[configuring service clients externally](configuring-service-clients-ext.md), you can configure them programmatically in code.

By configuring service clients in code, you gain fine-grained control of the many options available to you. Most of the configuration that you can set externally are also available for you to set in code.

## Basic configuration in code
<a name="conf-service-client-code-basic"></a>

For example, the following snippet sets the AWS Region to `EU_SOUTH_2` for an Amazon S3 service client in code:

```
S3Client s3Client = S3Client.builder()
        .region(Region.EU_SOUTH_2)
        .build();
```

The previous snippet shows the static factory method, `builder()`. The `builder()` method returns a `builder` object that allows you to customize the service client. The fluent setter methods return the `builder` object—in this case, an [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3ClientBuilder.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3ClientBuilder.html) instance—so that you can chain the method calls for convenience and for more readable code. After you configure the properties you want, call the `build()` method to create the client.

## Advanced configuration in code
<a name="conf-service-client-code-several"></a>

The following snippet shows additional configuration options:

```
ClientOverrideConfiguration clientOverrideConfiguration =
        ClientOverrideConfiguration.builder()
                .apiCallAttemptTimeout(Duration.ofSeconds(1))
                .addMetricPublisher(CloudWatchMetricPublisher.create())
                .build();

S3Client s3Client = S3Client.builder()
        .region(Region.EU_SOUTH_2)
        .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
        .overrideConfiguration(clientOverrideConfiguration)
        .httpClientBuilder(
                ApacheHttpClient.builder()
                        .maxConnections(100)
                        .connectionTimeout(Duration.ofSeconds(5))
                        .proxyConfiguration(ProxyConfiguration.builder()
                                .endpoint(URI.create("http://proxy:8080"))
                                .build())
        ).build();
```

In the previous snippet, you can see several entry points to configure a service client:
+ [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/client/config/ClientOverrideConfiguration.Builder.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/client/config/ClientOverrideConfiguration.Builder.html) that provides configuration options common across all service clients. These settings are AWS-specific behaviors independent of any HTTP implementation.
+ **HTTP client configuration through a separate HTTP client builder implementation.** The `ApacheHttpClient.Builder` is an example. The service client provides the `httpClientBuilder()` method to associate the configured HTTP client to the service client.
+ **Methods on the [client builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3ClientBuilder.html) itself,** such as `region()` and `credentialsProvider()`

### Same configuration using configuration blocks
<a name="service-client-config-lambda"></a>

Instead of creating separate objects and then passing them to service client methods, the AWS SDK for Java 2.x provides methods that accept lambda expressions to build these objects inline. The configuration methods on the builder are named the same, but have different signatures. For example:
+ [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/client/builder/SdkClientBuilder.html#overrideConfiguration(software.amazon.awssdk.core.client.config.ClientOverrideConfiguration)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/client/builder/SdkClientBuilder.html#overrideConfiguration(software.amazon.awssdk.core.client.config.ClientOverrideConfiguration))
+ [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/client/builder/SdkClientBuilder.html#overrideConfiguration(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/client/builder/SdkClientBuilder.html#overrideConfiguration(java.util.function.Consumer))

The configuration of the S3 client shown earlier using this approach can be done in one block of code:

```
S3Client s3Client = S3Client.builder()
        .region(Region.EU_SOUTH_2)
        .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
        .overrideConfiguration(b -> b
                .apiCallAttemptTimeout(Duration.ofSeconds(1))
                .addMetricPublisher(CloudWatchMetricPublisher.create()))
        .httpClientBuilder(ApacheHttpClient.builder()
                .maxConnections(100)
                .connectionTimeout(Duration.ofSeconds(5))
                .proxyConfiguration(ProxyConfiguration.builder()
                        .endpoint(URI.create("http://proxy:8080"))
                        .build()))
        .build();
```

## Configuration options unavailable in code
<a name="conf-servic-client-only-ext"></a>

Because the following setting affect fundamental initialization processes in the SDK, you can set the following configuration settings only externally and not in code:

### File Location Settings
<a name="code-only-conf-file-loc"></a>

These settings control the location of the shared config and credentials files and cannot be overridden programmatically after the SDK has loaded them:
+ **AWS\$1CONFIG\$1FILE** (environment variable) / **aws.configFile**(JVM system property)
+ **AWS\$1SHARED\$1CREDENTIALS\$1FILE** (environment variable) / **aws.sharedCredentialsFile** (JVM system property)

These settings must be set before the SDK loads the configuration files, as they determine where the SDK looks for configuration. Once the SDK has initialized, changing these values has no effect.

### Instance Metadata Service Disablement
<a name="code-only-conf-imds"></a>
+ **AWS\$1EC2\$1METADATA\$1DISABLED** (environment variable) / **aws.disableEc2Metadata** (JVM system property)

This setting controls whether the SDK attempts to use the EC2 Instance Metadata Service at all. Once the SDK has initialized, you can't change this setting programmatically.

### Profile Selection
<a name="code-only-conf-profile"></a>
+ **AWS\$1PROFILE** (environment variable) / **aws.profile** (JVM system property)

This setting tells the SDK which profile to load from the shared config and credentials files. Once loaded, changing this value has no effect.

### Container Credential Paths
<a name="code-only-conf-container-cred-path"></a>
+ **AWS\$1CONTAINER\$1CREDENTIALS\$1RELATIVE\$1URI**
+ **AWS\$1CONTAINER\$1CREDENTIALS\$1FULL\$1URI**
+ **AWS\$1CONTAINER\$1AUTHORIZATION\$1TOKEN**
+ **AWS\$1CONTAINER\$1AUTHORIZATION\$1TOKEN\$1FILE**

You use these environment variables to tell the SDK how to fetch credentials from container services. After the credential provider chain has been established during service client initialization, you can't change these settings.

### Default HTTP Implementation Selection
<a name="code-only-conf-http-impl"></a>
+ **SYNC\$1HTTP\$1SERVICE\$1IMPL** (environment variable) / **software.amazon.awssdk.http.service.impl** (JVM system property)
+ **ASYNC\$1HTTP\$1SERVICE\$1IMPL** (environment variable) / **software.amazon.awssdk.http.async.service.impl** (JVM system property)

These global settings determine which HTTP client implementation the SDK uses for all service clients unless overridden in code for individual service clients. You must set these before the SDK initializes its HTTP clients and cannot be changed afterward.

# Use singleton service client instances with the AWS SDK for Java 2.x
<a name="singleton-service-clients"></a>

Service clients in the AWS SDK for Java 2.x are thread-safe. You can create one instance of each service client and reuse it throughout your application. This approach improves performance and manages resources more efficiently.

## Benefits of singleton service clients
<a name="singleton-performance-benefits"></a>

Connection pooling  
Service clients maintain internal HTTP connection pools. Creating and destroying these pools is expensive. When you reuse clients, these pools are shared efficiently across requests.

Reduced initialization overhead  
Creating a client involves loading configuration, establishing credentials, and initializing internal components. Singleton instances eliminate this overhead.

Better resource utilization  
Singleton clients prevent resource exhaustion that can occur when you create many client instances.

## Create and use singleton service clients
<a name="singleton-best-practice-example"></a>

The following example shows how to create and use singleton service clients:

```
// Create one instance and use it throughout the application.
public class ServiceClientSource {
    private static final S3Client s3Client = S3Client.create();
    
    public static S3Client getS3Client() {
        return s3Client;
    }
}
```

Don't create new clients for each operation:

```
// This approach creates unnecessary overhead.
public void badExample() {
    try (S3Client s3 = S3Client.create()) {
        s3.listBuckets();
    }
}
```

## Important considerations
<a name="singleton-important-considerations"></a>
+ Service clients are thread-safe. You can safely share them across multiple threads.
+ Close clients only when your application shuts down or if you no longer need the client. Use `client.close()` or try-with-resources at the application level.
+ If you need different configurations such as regions or credentials, create separate singleton instances for each configuration.

If you use dependency injection frameworks like Spring, configure service clients as singleton beans. This ensures proper lifecycle management.

# Setting the AWS Region for the AWS SDK for Java 2.x
<a name="region-selection"></a>

SDK clients connect to an AWS service in a specific AWS Region that you specify when you create the client. This configuration allows your application to interact with AWS resources in that geographical area. When you create a service client without explicitly setting a Region, the SDK uses the default Region from your external configuration. 

## Explicitly configure an AWS Region
<a name="region-selection-choose-region"></a>

To explicitly set a Region, we recommend that you use the constants defined in the [Region](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/regions/Region.html) class. This is an enumeration of all publicly available regions. 

To create a client with an enumerated Region from the class, use the client builder's `region` method.

```
Ec2Client ec2 = Ec2Client.builder()
          .region(Region.US_WEST_2)
          .build();
```

If the Region you want to use isn’t one of the enumerations in the `Region` class, you can create a new Region by using the static `of` method. This method allows you access to new Regions without upgrading the SDK. 

```
Region newRegion = Region.of("us-east-42");
Ec2Client ec2 = Ec2Client.builder()
          .region(newRegion)
          .build();
```

**Note**  
After you build a client with the builder, it’s *immutable* and the AWS Region *cannot be changed*. If you need to work with multiple AWS Regions for the same service, you should create multiple clients—​one per Region.

## Let the SDK automatically determine the default AWS Region from the environment
<a name="automatically-determine-the-aws-region-from-the-environment"></a>

When your code runs on Amazon EC2 or AWS Lambda, you might want to configure clients to use the same AWS Region that your code is running on. This decouples your code from the environment it’s running in and makes it easier to deploy your application to multiple AWS Regions for lower latency or redundancy.

To use the default AWS Region provider chain to determine the Region from the environment, use the client builder’s `create` method.

```
Ec2Client ec2 = Ec2Client.create();
```

You can also configure the client in other ways, but not set the Region. The SDK picks up the AWS Region by using the default region provider chain:

```
Ec2Client ec2Client = Ec2Client.builder()
        .credentialsProvider(ProfileCredentialsProvider.builder()
                .profileName("my-profile")
                .build())
        .build();
```

If you don’t explicitly set an AWS Region by using the `region` method, the SDK consults the default region provider chain to determine the Region to use.

### Understanding the default AWS Region provider chain
<a name="default-region-provider-chain"></a>

 **The SDK takes the following steps to look for an AWS Region:** 

1. Any explicit Region set by using the `region` method on the builder itself takes precedence over anything else.

1. The SDK looks for the JVM system property `aws.region` and uses its value if found.

1. The `AWS_REGION` environment variable is checked. If it’s set, that Region is used to configure the client.
**Note**  
The Lambda container sets this environment variable.

1. The SDK checks the active profile in the [AWS shared config and credentials files](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html). If the `region` property is present, the SDK uses it.

   The `default` profile is the active profile unless overridden by `AWS_PROFILE` environment variable or `aws.profile` JVM system property. If the SDK finds the `region` property in both files for the same profile (including the `default` profile), the SDK uses the value in the shared credentials file.

1. The SDK attempts to use the Amazon EC2 instance metadata service (IMDS) to determine the Region of the currently running Amazon EC2 instance.
   + For greater security, you should disable the SDK from attempting to use version 1 of IMDS. You use the same setting to disable version 1 that are described in the [Securely acquire IAM role credentials](ec2-iam-roles.md#securely-read-IAM-role_credentials) section.

1. If the SDK still hasn’t found a Region by this point, client creation fails with an exception.

When developing AWS applications, a common approach is to use the *shared configuration file* to set the Region for local development, and rely on the default region provider chain to determine the Region when the application runs on AWS infrastructure. This greatly simplifies client creation and keeps your application portable.

## Check to see if a service is available in a Region
<a name="region-selection-query-service"></a>

To see if a particular AWS service is available in a Region, use the static `serviceMetadata` method on a service client:

```
DynamoDbClient.serviceMetadata().regions().forEach(System.out::println);
```

The previous snippet prints out a long list of AWS Region codes that have the DynamoDB service:

```
af-south-1
ap-east-1
ap-northeast-1
ap-northeast-2
ap-northeast-3
ap-south-1
ap-south-2
ap-southeast-1
...
```

You can use a code to look up the [Region class enumeration](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/regions/Region.html) for the Region you need your service client to use.

For example, if you want to work with DynamoDB in the Region with the code `ap-northeast-2`, create your DynamoDB client with at least the following configuration:

```
DynamoDbClient ddb = DynamoDbClient.builder()
    .region(Region.AP_NORTHEAST_2)
    .build();
```

## Choose a specific endpoint
<a name="choosing-a-specific-endpoint"></a>

In certain situations—such as to test preview features of a service before the features graduate to general availability—you may need to specify a specific endpoint in a Region. In these situations, service clients can be configured by calling the `endpointOverride` method.

For example, to configure an Amazon EC2 client to use the Europe (Ireland) Region with a specific endpoint, use the following code.

```
Ec2Client ec2 = Ec2Client.builder()
               .region(Region.EU_WEST_1)
               .endpointOverride(URI.create("https://ec2.eu-west-1.amazonaws.com"))
               .build();
```

See [Regions and Endpoints](https://docs.aws.amazon.com/general/latest/gr/rande.html) for the current list of regions and their corresponding endpoints for all AWS services.

# Using credentials providers in the AWS SDK for Java 2.x
<a name="credentials"></a>

The role of a credentials provider in the AWS SDK for Java 2.x is to source and supply credentials to the SDK's AWS service clients. The SDK uses the credentials it sources to authenticate with the service by cryptographically signing each request. Credentials usually consist of access keys—an access key ID and a secret access key together. 

When you use temporary credentials, which are used when you setup [SSO token provider configuration](https://docs.aws.amazon.com/sdkref/latest/guide/feature-sso-credentials.html#sso-token-config) or configure your runtime to [assume an IAM (AWS Identity and Access Management) role](https://docs.aws.amazon.com/sdkref/latest/guide/access-assume-role.html#credOrSourceAssumeRole) as examples, a session token is added to the access keys, providing time-limited access to AWS resources.

This topic discusses several ways that you enable the SDK to access credentials.

**Topics**
+ [Interactive development work](credentials-temporary.md)
+ [Default credentials provider chain](credentials-chain.md)
+ [Credentials caching](credential-caching.md)
+ [Specify a specific credentials provider](credentials-providers.md)
+ [Use shared configuration profiles](credentials-profiles.md)
+ [Use an external process](credentials-process.md)
+ [Supply credentials in code](credentials-explicit.md)
+ [Read IAM role credentials on Amazon EC2](ec2-iam-roles.md)

# Access credentials for interactive development work using AWS SDK for Java 2.x
<a name="credentials-temporary"></a>

For increased security, AWS recommends that you configure the SDK for Java to [use temporary credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#bp-users-federation-idp) instead of long-lived credentials. Temporary credentials consist of access keys (access key id and secret access key) and a session token.

Several approaches are available to you to work with temporary credentials. The approach you use, and therefore the configuration that you provide to the SDK, depends on your use case. 

When you do interactive development work with the Java SDK, we recommend that you use AWS Console login credentials. 

## Using console login credentials
<a name="using-con-login-creds"></a>

You can use your existing AWS Management Console sign-in credentials for programmatic access to AWS services. After a browser-based authentication flow, AWS generates temporary credentials that work across local development tools like the AWS CLI and the SDK for Java 2.x.

With this process, you can authenticate using root credentials created during initial account set up, an IAM user, or a federated identity from your identity provider, and the AWS CLI automatically manages the temporary credentials for you. This approach enhances security by eliminating the need to store long-term credentials locally.

When you run the `aws login` command, you can select from your active console sessions, or sign in through the browser-based authentication flow and this will automatically generate temporary credentials. The SDK for Java 2.x will automatically refresh these credentials for up to 12 hours.

**Important**  
In addition to the configuration that you set in the shared config file that works for all projects, each individual Java project requires the following dependency in the Maven `pom.xml` file:  

```
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>signin</artifactId>
</dependency>
```
The `signin` dependency provide the code that enables the SDK for Java 2.x to access and use console login credentials.

For more information on prerequsites, logging in and signing out, see [Login for AWS local development using console credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sign-in.html) in the *AWS SDK and Tools Refernce Guide*.

## Single-sign-on approach
<a name="single-sign-on-approach"></a>

When you do interactive development work with the Java SDK, you can alternatively use the single sign-on approach. This approach requires the following setup:
+ [Set up through the IAM Identity Center](get-started-auth.md#setup-auth)
+ [Configure a profile in the AWS shared config file](get-started-auth.md#setup-credentials) 
+ using the AWS CLI and [running a command](get-started-auth.md#setup-login-sso) to login and creating an active session

### IAM Identity Center configuration
<a name="credentials-temporary-idc"></a>

When you configure the SDK to use IAM Identity Center single sign-on access as described in [Setup overview](setup.md#setup-overview) in this guide, the SDK uses temporary credentials. 

The SDK uses the IAM Identity Center access token to gain access to the IAM role that is configured with the `sso_role_name` setting in your `config` file. The SDK assumes this IAM role and retrieves temporary credentials to sign AWS service requests.

For more details about how the SDK gets temporary credentials from the configuration, see the [Understanding IAM Identity Center authentication](https://docs.aws.amazon.com/sdkref/latest/guide/understanding-sso.html) section of the AWS SDKs and Tools Reference Guide.

**Important**  
In addition to the configuration that you set in the shared `config` file that works for all projects, each individual Java project requires the following dependencies in the Maven `pom.xml` file:  

```
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>sso</artifactId>
</dependency>
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>ssooidc</artifactId>
</dependency>
```
The `sso` and `ssooidc` dependencies provide the code that enables the SDK for Java 2.x to access temporary credentials.

### Retrieve temporary credentials from the AWS access portal
<a name="credentials-temporary-from-portal"></a>

As an alternative to IAM Identity Center single sign-on configuration, you can copy and use temporary credentials available in the AWS access portal. You can use the temporary credentials in a profile or use them as values for system properties and environment variables.

**Set up a local credentials file for temporary credentials**

1. [Create a shared credentials file](https://docs.aws.amazon.com/sdkref/latest/guide/file-location.html)

1. In the credentials file, paste the following placeholder text until you paste in working temporary credentials.

   ```
   [default]
   aws_access_key_id=<value from AWS access portal>
   aws_secret_access_key=<value from AWS access portal>
   aws_session_token=<value from AWS access portal>
   ```

1. Save the file. The file `~/.aws/credentials` should now exist on your local development system. This file contains the [[default] profile](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html#file-format-profile) that the SDK for Java uses if a specific named profile is not specified. 

1. [Sign in to the AWS access portal](https://docs.aws.amazon.com/singlesignon/latest/userguide/howtosignin.html)

1. Follow these instructions under the [Manual credential refresh](https://docs.aws.amazon.com/singlesignon/latest/userguide/howtogetcredentials.html#how-to-get-temp-credentials) heading to copy IAM role credentials from the AWS access portal.

   1. For step 2 in the linked instructions, choose `Access keys` for the IAM role name that grants access for your development needs. This role typically has a name like **PowerUserAccess** or ** Developer**.

   1. In the modal dialog box, select the your operating system and copy the contents from **Add a profile to your AWS credentials file**.

1. Paste the copied credentials into your local `credentials` file and remove the generated profile name. Your file should resemble the following.

   ```
   [default]
   aws_access_key_id=AKIAIOSFODNN7EXAMPLE
   aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
   aws_session_token=IQoJb3JpZ2luX2IQoJb3JpZ2luX2IQoJb3JpZ2luX2IQoJb3JpZ2luX2IQoJb3JpZVERYLONGSTRINGEXAMPLE
   ```

1. Save the `credentials` file.

When the SDK for Java creates a service client, it will access these temporary credentials and use them for each request. The settings for the IAM role chosen in step 5a determine [how long the temporary credentials are valid](https://docs.aws.amazon.com/singlesignon/latest/userguide/howtosessionduration.html). The maximum duration is twelve hours.

After the temporary credentials expire, repeat steps 4 through 7.

# Default credentials provider chain in the AWS SDK for Java 2.x
<a name="credentials-chain"></a>

The default credentials provider chain in the AWS SDK for Java 2.x automatically searches for AWS credentials in a predefined sequence of locations, allowing applications to authenticate with AWS services without explicitly specifying credential sources.

The default credentials provider chain is implemented by the [DefaultCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.html) class. It sequentially delegates to other credentials provider implementations that check for configuration in various locations. The first credentials provider that can find all necessary configuration elements causes the chain to end.

To use the default credentials provider chain to supply temporary credentials, create a service client builder but don't specify a credentials provider. The following code snippet creates a `DynamoDbClient` that uses the default credentials provider chain to locate and retrieve configuration settings.

```
// Any external Region configuration is overridden.
// The SDK uses the default credentials provider chain because no specific credentials provider is specified.
Region region = Region.US_WEST_2;
DynamoDbClient ddb = 
    DynamoDbClient.builder()
                  .region(region)
                  .build();
```

## Credential settings retrieval order
<a name="credentials-default"></a>

The default credentials provider chain of the SDK for Java 2.x searches for configuration in your environment using a predefined sequence.

1. Java system properties
   + The SDK uses the [SystemPropertyCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/SystemPropertyCredentialsProvider.html) class to load temporary credentials from the `aws.accessKeyId`, `aws.secretAccessKey`, and `aws.sessionToken` Java system properties.
**Note**  
For information on how to set Java system properties, see the [System Properties](https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html) tutorial on the official *Java Tutorials* website.

1. Environment variables
   + The SDK uses the [EnvironmentVariableCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/EnvironmentVariableCredentialsProvider.html) class to load temporary credentials from the `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN` environment variables.

1. Web identity token and IAM role ARN
   + The SDK uses the [WebIdentityTokenFileCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/WebIdentityTokenFileCredentialsProvider.html) class to load credentials by assuming a role using a web identity token.
   + The credentials provider looks for the following environment variables or JVM system properties:
     + `AWS_WEB_IDENTITY_TOKEN_FILE or aws.webIdentityTokenFile`
     + `AWS_ROLE_ARN` or `aws.roleArn`
     + `AWS_ROLE_SESSION_NAME` or `aws.roleSessionName` (optional)
   + After the SDK acquires the values, it calls the AWS Security Token Service (STS) and uses the temporary credentials it returns to sign requests.
   + Runtime environments such as Amazon Elastic Kubernetes Service (EKS) automatically make web identity tokens available to AWS SDKs, enabling applications to obtain temporary AWS credentials.

1. The shared `credentials` and `config` files
   + The SDK uses the [ProfileCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/ProfileCredentialsProvider.html) to load IAM Identity Center single sign-on settings or temporary credentials from the `[default]` profile in the shared `credentials` and `config` files. 

     The AWS SDKs and Tools Reference Guide has [detailed information](https://docs.aws.amazon.com/sdkref/latest/guide/understanding-sso.html#idccredres) about how the SDK for Java works with the IAM Identity Center single sign-on token to get temporary credentials that the SDK uses to call AWS services.
**Note**  
The `credentials` and `config` files are shared by various AWS SDKs and Tools. For more information, see [The .aws/credentials and .aws/config files](https://docs.aws.amazon.com/sdkref/latest/guide/creds-config-files.html) in the AWS SDKs and Tools Reference Guide.
   + Because a profile in the shared `credentials` and `config` files can contain many different sets of settings, the `ProfileCredentialsProvider` delegates to a series of other providers to look for settings under the `[default]` profile:
     + **Web identity token credentials** (class `WebIdentityTokenCredentialsProvider`): When the profile contains `role_arn` and `web_identity_token_file`.
     + **SSO credentials** (class `SsoCredentialsProvider`): When the profile contains SSO-related properties such as `sso_role_name`, `sso_account_id`.
     + **Role-based credentials with source profile** (class `StsAssumeRoleCredentialsProvider`): When the profile contains `role_arn` and `source_profile`.
     + **Role-based credentials with credential source** (class `StsAssumeRoleWithSourceCredentialsProvider`): When the profile contains `role_arn` and `credential_source`. 
       + When `credential_source = Environment`: It uses a chain of `SystemPropertyCredentialsProvider` and `EnvironmentVariableCredentialsProvider`
       + When `credential_source = Ec2InstanceMetadata`: It uses `InstanceProfileCredentialsProvider`
       + When `credential_source = EcsContainer`: It uses `ContainerCredentialsProvider`
     + **Console login credentials** (class `LoginCredentialsProvider`): When the profile contains `login_session` 
     + **Process credentials** (class `ProcessCredentialsProvider`): When the profile contains `credential_process`.
     + **Session credentials** (class `StaticSessionCredentialsProvider`): When the profile contains `aws_access_key_id`, `aws_secret_access_key`, and `aws_session_token`.
     + **Basic credentials** (class `StaticCredentialsProvider`): When the profile contains `aws_access_key_id` and `aws_secret_access_key`.

1.  Amazon ECS container credentials
   + The SDK uses the [ContainerCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/ContainerCredentialsProvider.html) class to load temporary credentials using the following environment variables:

     1. `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` or `AWS_CONTAINER_CREDENTIALS_FULL_URI`

     1. `AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE` or `AWS_CONTAINER_AUTHORIZATION_TOKEN`

   The ECS container agent automatically sets the `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` environment variable, which points to the ECS credentials endpoint. The other environment variables are typically set in specific scenarios where the standard ECS credential endpoint isn't used.

1.  Amazon EC2 instance IAM role-provided credentials
   + The SDK uses the [InstanceProfileCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProvider.html) class to load temporary credentials from the Amazon EC2 metadata service.

1. If the SDK can't find the necessary configuration settings through all this steps listed above, it throws an exception with output similar to the following:

   ```
   software.amazon.awssdk.core.exception.SdkClientException: Unable to load credentials from any of the providers 
   in the chain AwsCredentialsProviderChain(credentialsProviders=[SystemPropertyCredentialsProvider(), 
   EnvironmentVariableCredentialsProvider(), WebIdentityTokenCredentialsProvider(), ProfileCredentialsProvider(), 
   ContainerCredentialsProvider(), InstanceProfileCredentialsProvider()])
   ```

## Use the `DefaultCredentialsProvider` in code
<a name="default-credentials-provider-in-code"></a>

You can explicitly use the default credentials provider chain in your code. This is functionally equivalent to you not specifying a credentials provider at all, since the SDK uses `DefaultCredentialsProvider` by default. However, explicitly using it can make your code more readable and self-documenting. It clearly shows your intention to use the default credentials chain.

```
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

public class ExplicitDefaultCredentialsExample {
    public static void main(String[] args) {
        // Explicitly create the DefaultCredentialsProvider.
        DefaultCredentialsProvider defaultCredentialsProvider = DefaultCredentialsProvider
                                                                    .builder().build();

        // Use it with any service client.
        S3Client s3Client = S3Client.builder()
            .region(Region.US_WEST_2)
            .credentialsProvider(defaultCredentialsProvider)
            .build();

        // Now you can use the client with the default credentials chain.
        s3Client.listBuckets();
    }
}
```

When you build the default credentials provider you can provide more configuration:

```
DefaultCredentialsProvider customizedProvider = DefaultCredentialsProvider.builder()
    .profileName("custom-profile")  // Use a specific profile if the chain gets to the `ProfileCredentialsProvider` stage.
    .asyncCredentialUpdateEnabled(true)  // Enable async credential updates.
    .build();
```

This approach gives you more control while still providing the convenience of the default credentials chain.

# Credentials caching in the AWS SDK for Java 2.x
<a name="credential-caching"></a>

The AWS SDK for Java 2.x implements credential caching to improve performance and reduce calls to credentials sources. This section explains how credentials caching works and how you can configure it for your applications.

## Understanding credential provider caching
<a name="understanding-credential-provider-caching"></a>

Credential providers in the SDK for Java 2.x use different caching strategies:
+ **Internal credential caching**: Many providers cache credentials that they retrieve.
+ **Automatic refresh**: Providers with cached credentials implement refresh mechanisms.

### Providers with internal credentials caching
<a name="providers-with-internal-caching"></a>

The following credentials providers cache credentials internally, even when you create new instances:
+ **Instance profile credentials provider**: Caches credentials from the Amazon EC2 metadata service.
+ **Container credentials provider**: Caches credentials from the container metadata endpoint.
+ **STS-based providers**: Cache temporary credentials from AWS Security Token Service (STS).
+ **Web identity token providers**: Cache credentials obtained from web identity tokens.
+ **Process credentials provider**: Caches credentials from external processes.

### Providers without internal caching
<a name="providers-without-caching"></a>

The following providers don't implement internal caching:
+ **Environment Variable Credentials Provider**
+ **System Property Credentials Provider**
+ **Static Credentials Provider**

## Configuring credential caching
<a name="configuring-credential-caching"></a>

You can customize caching behavior when building credential providers:

### Stale Time
<a name="stale-time"></a>

Controls when credentials are considered stale and need refreshing:

```
.staleTime(Duration.ofMinutes(2))  // Consider stale 2 minutes before expiration.
```

### Prefetch Time
<a name="prefetch-time"></a>

Determines when to start refreshing credentials before they expire:

```
.prefetchTime(Duration.ofMinutes(10))  // Start refresh 10 minutes before expiration.
```

### Asynchronous Updates
<a name="async-updates"></a>

Enables background credential refreshing:

```
.asyncCredentialUpdateEnabled(true)  // Refresh credentials in background thread.
```

### Session Duration
<a name="session-duration"></a>

For STS-based providers, controls how long temporary credentials remain valid:

```
.refreshRequest(r -> r.durationSeconds(3600))  // 1 hour session.
```

## Caching credentials configuration example
<a name="example-optimized-sts-config"></a>

As an example of configuring caching for a credentials provider implementation, you might want to have the SDK use a background thread to pre-fetch (retrieve in advance) credentials before they expire. That way you can avoid the blocking call that retrieves fresh credentials. 

The following shows an example that creates an `[StsAssumeRoleCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sts/auth/StsAssumeRoleCredentialsProvider.html)` that uses a background thread to pre-fetch credentials by setting the `[asyncCredentialUpdateEnabled](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sts/auth/StsCredentialsProvider.BaseBuilder.html#asyncCredentialUpdateEnabled(java.lang.Boolean))` property to `true` on the builder:

```
StsAssumeRoleCredentialsProvider provider = StsAssumeRoleCredentialsProvider.builder()
    .refreshRequest(r -> r
        .roleArn("arn:aws:iam::111122223333:role/example-role")
        .roleSessionName("example-session")
        .durationSeconds(3600))  // 1 hour session
    .staleTime(Duration.ofMinutes(5))  // Consider stale 5 minutes before expiration
    .prefetchTime(Duration.ofMinutes(10))  // Start refresh 10 minutes before expiration
    .asyncCredentialUpdateEnabled(true)  // Refresh in background
    .build();

S3Client s3 = S3Client.builder()
    .credentialsProvider(provider)
    .build();
```

When you invoke an operation on `s3Client` for the first time, an `[AssumeRoleRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sts/model/AssumeRoleRequest.html)` is sent to the AWS Security Token Service (STS). STS returns temporary credentials that are valid for 15 minutes (900 seconds). The `s3Client` instance uses the cached credentials until it's time to refresh them before the 15 minutes elapse. By default, the SDK attempts to retrieve new credentials for a new session between 5 minutes and 1 minute before the expiration time of the current session. The pre-fetch window is configurable by using the `[prefetchTime](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sts/auth/StsCredentialsProvider.BaseBuilder.html#prefetchTime(java.time.Duration))` and `[staleTime](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sts/auth/StsCredentialsProvider.BaseBuilder.html#staleTime(java.time.Duration))` properties.

You can configure the following session-based credentials providers similarly:
+ `StsWebIdentityTokenFileCredentialsProvider`
+ `StsGetSessionTokenCredentialsProvider`
+ `StsGetFederationTokenCredentialsProvider`
+ `StsAssumeRoleWithWebIdentityCredentialsProvider`
+ `StsAssumeRoleWithSamlCredentialsProvider`
+ `StsAssumeRoleCredentialsProvider`
+ `DefaultCredentialsProvider` (when it delegates to credentials provider that uses sessions)
+ `ProcessCredentialsProvider`
+ `WebIdentityTokenFileCredentialsProvider`
+ `ContainerCredentialsProvider`
+ `InstanceProfileCredentialsProvider`

Understanding credential caching helps you optimize your application's performance and reliability when working with AWS services.

# Specify a specific credentials provider in the AWS SDK for Java 2.x
<a name="credentials-providers"></a>

While the default credentials provider chain is convenient for many scenarios, explicitly specifying credentials providers gives you greater control over authentication behavior, performance, and security.

Reasons that you might want to specify a credentials provider might include:
+ The default provider chain checks multiple sources sequentially, which can add latency:

  ```
  // The default provider chain checks might check multiple sources until it finds
  // sufficient configuration.
  S3Client s3Client = S3Client.builder().build();
  
  // You can specify exactly where to look.
  S3Client optimizedClient = S3Client.builder()
      .credentialsProvider(InstanceProfileCredentialsProvider.create())
      .build();
  ```
+ You need to use non-standard locations for accessing credentials configuration:

  ```
  // Use configuration from a custom file location.
  S3Client s3Client = S3Client.builder()
      .credentialsProvider(ProfileCredentialsProvider.builder()
              .profileFile(ProfileFile.builder()
                      .content(Paths.get("/custom/path/to/configuration/file"))
                      .type(ProfileFile.Type.CONFIGURATION) // Expects all non-default profiles to be prefixed with "profile".
                      .build())
              .profileName("custom")
              .build())
      .build();
  ```
+ Use different credentials for different service clients. For example, if your application needs to access multiple AWS accounts or use different permissions for different services:

  ```
  // S3 client using one set of credentials.
  S3Client s3Client = S3Client.builder()
      .credentialsProvider(ProfileCredentialsProvider.create("s3-readonly"))
      .build();
  
  // DynamoDB client using different credentials.
  DynamoDbClient dynamoDbClient = DynamoDbClient.builder()
      .credentialsProvider(ProfileCredentialsProvider.create("dynamodb-admin"))
      .build();
  ```
+ Control credential refresh behavior:

  ```
  // Create a provider with custom refresh behavior.
  StsAssumeRoleCredentialsProvider customRefreshProvider = 
      StsAssumeRoleCredentialsProvider.builder()
          .refreshRequest(AssumeRoleRequest.builder()
              .roleArn("arn:aws:iam::123456789012:role/my-role")
              .roleSessionName("custom-session")
              .build())
          .stsClient(StsClient.create())
          .asyncCredentialUpdateEnabled(true) // Use a background thread to prefetch credentials.
          .build();
  
  S3Client s3Client = S3Client.builder()
      .credentialsProvider(customRefreshProvider)
      .build();
  ```

# Use AWS shared configuration profiles in the AWS SDK for Java 2.x
<a name="credentials-profiles"></a>

Using the shared `config` and `credentials` file, you can set up several profiles. This enables your application to use multiple sets of credentials configuration. The `[default]` profile was mentioned previously. The SDK uses the [ProfileCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/ProfileCredentialsProvider.html) class to load settings from profiles defined in the shared `credentials` file.

The following code snippet demonstrates how to build a service client that uses the settings defined as part of the profile named `my_profile`.

```
Region region = Region.US_WEST_2;
DynamoDbClient ddb = DynamoDbClient.builder()
      .region(region)
      .credentialsProvider(ProfileCredentialsProvider.create("my_profile"))
      .build();
```

## Set a different profile as the default
<a name="set-a-custom-profile-as-the-default"></a>

To set a profile other than the `[default]` profile as the default for your application, set the `AWS_PROFILE` environment variable to the name of your custom profile.

To set this variable on Linux, macOS, or Unix, use `export`:

```
export AWS_PROFILE="other_profile"
```

To set these variables on Windows, use `set`:

```
set AWS_PROFILE="other_profile"
```

Alternatively, set the `aws.profile` Java system property to the name of the profile.

## Reload profile credentials
<a name="profile-reloading"></a>

You can configure any credentials provider that has a `profileFile()` method on its builder to reload profile credentials. These credentials profile classes are: `ProfileCredentialsProvider`, `DefaultCredentialsProvider`, `InstanceProfileCredentialsProvider`, and `ProfileTokenProvider.`

**Note**  
Profile credential reloading works only with the following settings in the profile file : `aws_access_key_id`, `aws_secret_access_key`, and `aws_session_token`.  
Settings such as `region`, `sso_session`, `sso_account_id`, and `source_profile` are ignored.

To configure a supported credentials provider to reload profile settings, provide an instance of [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/profiles/ProfileFileSupplier.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/profiles/ProfileFileSupplier.html) to the `profileFile()` builder method. The following code example demonstrates a `ProfileCredentialsProvider` that reloads credential settings from the `[default]` profile.

```
ProfileCredentialsProvider provider = ProfileCredentialsProvider
    .builder()
    .profileFile(ProfileFileSupplier.defaultSupplier())
    .build();

// Set up a service client with the provider instance.
DynamoDbClient dynamoDbClient = DynamoDbClient.builder()
                    .region(Region.US_EAST_1)
                    .credentialsProvider(provider)
                    .build();

/*
    Before dynamoDbClient makes a request, it reloads the credentials settings 
    by calling provider.resolveCredentials().
*/
```

When `ProfileCredentialsProvider.resolveCredentials()` is called, the SDK for Java reloads the settings. `ProfileFileSupplier.defaultSupplier()` is one of [several convenience implementations](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/profiles/ProfileFileSupplier.html) of `ProfileFileSupplier` provided by the SDK. If your use case requires, you can provide your own implementation.

The following example shows the use of the `ProfileFileSupplier.reloadWhenModified()` convenience method. `reloadWhenModified()` takes a `Path` parameter, which gives you flexibility in designating the source file for the configuration rather than the standard `~/.aws/credentials` (or `config`) location.

The settings will be reloaded when `resolveCredentials()` is called only if SDK determines the file's content has been modified.

```
Path credentialsFilePath = ...

ProfileCredentialsProvider provider = ProfileCredentialsProvider
    .builder()
    .profileFile(ProfileFileSupplier.reloadWhenModified(credentialsFilePath, ProfileFile.Type.CREDENTIALS))
    .profileName("my-profile")
    .build();
/*
    A service client configured with the provider instance calls provider.resolveCredential()
    before each request.
*/
```

The `ProfileFileSupplier.aggregate()` method merges the contents of multiple configuration files. You decide whether a file is reloaded per call to `resolveCredentials()` or a file's settings are fixed at the time it was first read. 

The following example shows a `DefaultCredentialsProvider` that merges the settings of two files that contain profile settings. The SDK reloads the settings in the file pointed to by the `credentialsFilePath` variable each time `resolveCredentials()` is called and the settings have changed. The settings from the `profileFile` object remain the same.

```
Path credentialsFilePath = ...;
ProfileFile profileFile = ...;

DefaultCredentialsProvider provider = DefaultCredentialsProvider
        .builder()
        .profileFile(ProfileFileSupplier.aggregate(
                ProfileFileSupplier.reloadWhenModified(credentialsFilePath, ProfileFile.Type.CREDENTIALS),
                ProfileFileSupplier.fixedProfileFile(profileFile)))
        .profileName("my-profile")
        .build();
/*
    A service client configured with the provider instance calls provider.resolveCredential()
    before each request.
*/
```

# Load credentials from an external process using the AWS SDK for Java 2.x
<a name="credentials-process"></a>

**Warning**  
The following describes a method of sourcing temporary credentials from an external process. This can potentially be dangerous, so proceed with caution. We recommend that you use other credential providers if at all possible. If using this option, we recommend that you make sure the `config` file is as locked down as possible using security best practices for your operating system.   
Make sure that your custom credentials tool does not write any secret information to `StdErr`. SDKs and AWS CLI can capture and log such information, potentially exposing it to unauthorized users.

With the SDK for Java 2.x, you can acquire temporary credentials from an external process for custom use cases. There are two ways to configure this functionality.

## Use the `credential_process` setting
<a name="credentials-credential_process"></a>

If you have a method that provides temporary credentials, you can integrate it by adding the `credential_process` setting as part of a profile definition in the `config` file. The value you specify must use the full path to the command file. If the file path contains any spaces, you must surround it with quotation marks.

The SDK calls the command exactly as given and then reads JSON data from `stdout`. 

The following examples show the use of this setting for file paths without spaces and file paths with spaces.

------
#### [ Linux/macOS ]

**No spaces in file path**  

```
[profile process-credential-profile]
credential_process = /path/to/credential/file/credential_file.sh --custom-command custom_parameter
```

**Spaces in file path**  

```
[profile process-credential-profile]
credential_process = "/path/with/space to/credential/file/credential_file.sh" --custom-command custom_parameter
```

------
#### [ Windows ]

**No spaces in file path**  

```
[profile process-credential-profile]
credential_process = C:\Path\To\credentials.cmd --custom_command custom_parameter
```

**Spaces in file path**  

```
[profile process-credential-profile]
credential_process = "C:\Path\With Space To\credentials.cmd" --custom_command custom_parameter
```

------

The following code snippet demonstrates how to build a service client that uses the temporary credentials defined as part of the profile named `process-credential-profile`.

```
Region region = Region.US_WEST_2;
S3Client s3Client = S3Client.builder()
      .region(region)
      .credentialsProvider(ProfileCredentialsProvider.create("process-credential-profile"))
      .build();
```

For detailed information about using an external process as a source of temporary credentials, refer to the [process credentials section](https://docs.aws.amazon.com/sdkref/latest/guide/feature-process-credentials.html) in the AWS SDKs and Tools Reference Guide.

## Use a `ProcessCredentialsProvider`
<a name="credentials-procredprovider"></a>

As an alternative to using settings in the `config` file, you can use the SDK's `[ProcessCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/ProcessCredentialsProvider.html)` to load temporary credentials using Java. 

The following examples show various versions of how to specify an external process using the `ProcessCredentialsProvider` and configuring a service client that uses the temporary credentials.

------
#### [ Linux/macOS ]

**No spaces in file path**  

```
ProcessCredentialsProvider credentials = 
    ProcessCredentialsProvider
        .builder()
        .command("/path/to/credentials.sh optional_param1 optional_param2")
        .build();

S3Client s3 = S3Client.builder()
                      .region(Region.US_WEST_2)
                      .credentialsProvider(credentials)
                      .build();
```

**Spaces in file path**  

```
ProcessCredentialsProvider credentials = 
    ProcessCredentialsProvider
        .builder()
        .command("/path\\ with\\ spaces\\ to/credentials.sh optional_param1 optional_param2")
        .build();

S3Client s3 = S3Client.builder()
                      .region(Region.US_WEST_2)
                      .credentialsProvider(credentials)
                      .build();
```

------
#### [ Windows ]

**No spaces in file path**  

```
ProcessCredentialsProvider credentials = 
    ProcessCredentialsProvider
        .builder()
        .command("C:\\Path\\To\\credentials.exe optional_param1 optional_param2")
        .build();

S3Client s3 = S3Client.builder()
                      .region(Region.US_WEST_2)
                      .credentialsProvider(credentials)
                      .build();
```

**Spaces in file path**  

```
ProcessCredentialsProvider credentials = 
    ProcessCredentialsProvider
        .builder()
        .command("\"C:\\Path\\With Spaces To\\credentials.exe\" optional_param1 optional_param2")
        .build();

S3Client s3 = S3Client.builder()
                      .region(Region.US_WEST_2)
                      .credentialsProvider(credentials)
                      .build();
```

------

## Use IAM Roles Anywhere for authentication
<a name="credentials-iam-roles-anywhere"></a>

[IAM Roles Anywhere](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/introduction.html) is an AWS service that allows you to obtain temporary AWS credentials for workloads running outside of AWS. It enables secure access to AWS resources from on-premises or other cloud environments.

Before you can authenticate requests with IAM Roles Anywhere, you first need to gather the required information and download the [credential helper tool](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/credential-helper.html). By following the [Getting started](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/getting-started.html) instructions in the IAM Roles Anywhere User Guide, you can create the necessary artifacts. 

The SDK for Java doesn't have a dedicated credentials provider to retrieve temporary credentials from IAM Roles Anywhere, but you can use the credential helper tool along with one of the options to [retrieve credentials from an external process](#credentials-process).

### Use the `credential_process` setting in a profile
<a name="credentials-iam-roles-anywhere-config"></a>

The following snippet in the shared AWS config file shows a profile named `roles_anywhere` that uses the `credential_process` setting:

```
[profile roles_anywhere]
credential_process = ./aws_signing_helper credential-process \
  --certificate /path/to/certificate \
  --private-key /path/to/private-key \
  --trust-anchor-arn arn:aws:rolesanywhere:region:account:trust-anchor/TA_ID \
  --profile-arn arn:aws:rolesanywhere:region:account:profile/PROFILE_ID \
  --role-arn arn:aws:iam::account:role/role-name-with-path
```

You need to replace the text shown in red with your values after you have assembled all the artifacts. The first element in the setting, `aws_signing_helper`, is the executable of the credential helper tool and `credential-process` is the command.

When you configure a service client to use the `roles_anywhere` profile—as shown in the following code—the SDK caches the temporary credentials and refreshes them before they expire:

```
S3Client s3Client = S3Client.builder()
    .credentialsProvider(ProfileCredentialsProvider.builder()
        .profileName("roles_anywhere").build())
    .build();
```

### Configure a `ProcessCredentialsProvider`
<a name="credentials-iam-roles-anywhere-process"></a>

As shown next, you can use a code-only approach with the `ProcessCredentialsProvider` instead of using profile settings:

```
ProcessCredentialsProvider processCredentialsProvider = ProcessCredentialsProvider.builder()
    .command("""
            ./aws_signing_helper credential-process \
            --certificate /path/to/certificate \
            --private-key /path/to/private-key \
            --trust-anchor-arn arn:aws:rolesanywhere:region:account:trust-anchor/TA_ID \
            --profile-arn arn:aws:rolesanywhere:region:account:profile/PROFILE_ID \
            --role-arn arn:aws:iam::account:role/role-name-with-path
        """).build();

S3Client s3Client = S3Client.builder()
    .credentialsProvider(processCredentialsProvider)
    .build();
```

Replace the text shown in red with your values after you have assembled all the artifacts. 

# Supply credentials in code using the AWS SDK for Java 2.x
<a name="credentials-explicit"></a>

If the default credential chain or a specific or custom provider or provider chain doesn't work for your application, you can supply temporary credentials directly in code. These can be [IAM role credentials](https://docs.aws.amazon.com/singlesignon/latest/userguide/howtogetcredentials.html) as[ described above](credentials-temporary.md#credentials-temporary-from-portal) or temporary credentials retrieved from AWS Security Token Service (AWS STS). If you retrieved temporary credentials using AWS STS, provide them to an AWS service client as shown in the following code example.

1. Assume a role by calling `StsClient.assumeRole()`.

1. Create a [StaticCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/StaticCredentialsProvider.html) object and supply it with the `AwsSessionCredentials` object.

1. Configure the service client builder with the `StaticCredentialsProvider` and build the client.

The following example creates an Amazon S3 service client using temporary credentials returned by AWS STS for an IAM assumed role.

```
    // The AWS IAM Identity Center identity (user) who executes this method does not have permission to list buckets.
    // The identity is configured in the [default] profile.
    public static void assumeRole(String roleArn, String roleSessionName) {
        // The IAM role represented by the 'roleArn' parameter can be assumed by identities in two different accounts
        // and the role permits the user to only list buckets.

        // The SDK's default credentials provider chain will find the single sign-on settings in the [default] profile.
        // The identity configured with the [default] profile needs permission to call AssumeRole on the STS service.
        try {
            Credentials tempRoleCredentials;
            try (StsClient stsClient = StsClient.create()) {
                AssumeRoleRequest roleRequest = AssumeRoleRequest.builder()
                        .roleArn(roleArn)
                        .roleSessionName(roleSessionName)
                        .build();

                AssumeRoleResponse roleResponse = stsClient.assumeRole(roleRequest);
                tempRoleCredentials = roleResponse.credentials();
            }
            // Use the following temporary credential items for the S3 client.
            String key = tempRoleCredentials.accessKeyId();
            String secKey = tempRoleCredentials.secretAccessKey();
            String secToken = tempRoleCredentials.sessionToken();

            // List all buckets in the account associated with the assumed role
            // by using the temporary credentials retrieved by invoking stsClient.assumeRole().
            StaticCredentialsProvider staticCredentialsProvider = StaticCredentialsProvider.create(
                    AwsSessionCredentials.create(key, secKey, secToken));
            try (S3Client s3 = S3Client.builder()
                    .credentialsProvider(staticCredentialsProvider)
                    .build()) {
                List<Bucket> buckets = s3.listBuckets().buckets();
                for (Bucket bucket : buckets) {
                    System.out.println("bucket name: " + bucket.name());
                }
            }
        } catch (StsException | S3Exception e) {
            logger.error(e.getMessage());
            System.exit(1);
        }
    }
```

## Permission set
<a name="credentials-explicit-permission-set"></a>

The following permission set defined in AWS IAM Identity Center allows the identity (user) to perform the following two operations

1. The `GetObject` operation of the Amazon Simple Storage Service.

1. The `AssumeRole` operation of the AWS Security Token Service.

Without assuming the role, the `s3.listBuckets()` method shown in the example would fail.

------
#### [ JSON ]

****  

```
{
	"Version":"2012-10-17",		 	 	 
	"Statement": [
		{
			"Effect": "Allow",
			"Action": [
				"s3:GetObject",
				"sts:AssumeRole"
			],
			"Resource": [
				"*"
			]
		}
	]
}
```

------

## Assumed role
<a name="credentials-explicit-role-to-assume"></a>

### Assumed role permissions policy
<a name="credentials-explicit-role-policy"></a>

The following permissions policy is attached to the role that is assume in the previous example. This permissions policy permits the ability to list all buckets in the same account as the role.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

------

### Assumed role trust policy
<a name="credentials-explicit-trust-policy"></a>

The following trust policy is attached to the role that is assume in the previous example. The policy allows the role to be assumed by identities (users) in two accounts.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::111122223333:root",
                    "arn:aws:iam::555555555555:root"
                ]
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
}
```

------

# Read IAM role credentials on Amazon EC2 using the SDK for Java 2.x
<a name="ec2-iam-roles"></a>

 You can use an IAM role to manage temporary credentials for applications that are running on an EC2 instance and making AWS CLI or AWS API requests. This is preferable to storing access keys within the EC2 instance. To assign an AWS role to an EC2 instance and make it available to all of its applications, you create an instance profile that is attached to the instance. An instance profile contains the role and enables programs that are running on the EC2 instance to get temporary credentials. For more information, see [Use an IAM role to grant permissions to applications running on Amazon EC2 instances](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2.html) in the *IAM User Guide*. 

This topic provides information on how to set up your Java application to run on an EC2 instance and enable the AWS SDK for Java 2.x to acquire IAM role credentials.

## Acquire IAM role credentials from the environment
<a name="default-provider-chain"></a>

If your application creates an AWS service client by using the `create` method (or `builder().build()` methods), the SDK for Java uses the *default credentials provider chain*. The default credentials provider chain searches the execution environment for configuration elements that the SDK can trade for temporary credentials. The [Default credentials provider chain in the AWS SDK for Java 2.x](credentials-chain.md) section describes the full search process.

The final step in the default provider chain is available only when your application runs on an Amazon EC2 instance. In this step, the SDK uses an `InstanceProfileCredentialsProvider` to read the IAM role defined in the EC2 instance profile. The SDK then acquires temporary credentials for that IAM role.

Although these credentials are temporary and would eventually expire, an `InstanceProfileCredentialsProvider` periodically refreshes them for you so that they continue to allow access to AWS.

## Acquire IAM role credentials programmatically
<a name="programmatic-configuration-for-IAM-role"></a>

As an alternative to the default credentials provider chain that eventually uses an `InstanceProfileCredentialsProvider` on EC2, you can configure a service client explicitly with an `InstanceProfileCredentialsProvider`. This approach is shown in the following snippet.

```
S3Client s3 = S3Client.builder()
       .credentialsProvider(InstanceProfileCredentialsProvider.create())
       .build();
```

## Securely acquire IAM role credentials
<a name="securely-read-IAM-role_credentials"></a>

By default, EC2 instances run [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) (Instance Metadata Service) that allows the SDK's `InstanceProfileCredentialsProvider` to access information such as the IAM role that has been configured. EC2 instances run two versions of IMDS by default:
+ Instance Metadata Service Version 1 (IMDSv1) – a request/response method
+ Instance Metadata Service Version 2 (IMDSv2) – a session-oriented method

[IMDSv2 is a more secure approach](https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/) than IMDSv1.

By default, the Java SDK first tries IMDSv2 to get the IAM role, but if that fails, it tries IMDSv1. However, since IMDSv1 is less secure, AWS recommends the use of IMDSv2 only and to disable the SDK from trying IMDSv1. 

To use the more secure approach, disable the SDK from using IMDSv1 by providing one of the following settings with a value of `true`.
+ Environment variable: `AWS_EC2_METADATA_V1_DISABLED`
+ JVM system property: aws.`disableEc2MetadataV1`
+ Shared config file setting: `ec2_metadata_v1_disabled`

With one of these settings set to `true`, the SDK does not load IMDS role credentials by using IMDSv1 if the initial IMDSv2 call fails.

# Configure retry behavior in the AWS SDK for Java 2.x
<a name="retry-strategy"></a>

Calls to AWS services can fail occasionally for unexpected reasons. Certain errors, such as throttling (rate exceeded) or transient errors, might succeed if the call is retried. The AWS SDK for Java 2.x has a built-in mechanism to detect such errors and automatically retry the call that is enabled by default for all clients. 

This page describes how this works, how to configure the distinct modes, and tailor the retry behavior.

## Retry strategies
<a name="retry-strategies"></a>

A retry strategy is a mechanism used in the SDK to implement retries. Each SDK client has a retry strategy created at build time that cannot be modified after the client is built. 

The retry strategy has the following responsibilities.
+ Classify exceptions as retryable or not.
+ Compute the suggested delay to wait before the next attempt.
+ Maintain a [token bucket](https://en.wikipedia.org/wiki/Token_bucket) that provides a mechanism to stop retries when a large percentage of requests are failing and retries are unsuccessful.

**Note**  
Before the release of retry *strategies* with version 2.26.0 of the SDK, retry *policies* provided the retry mechanism in the SDK. The retry *policy* API is made up of the core [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/RetryPolicy.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/RetryPolicy.html) class in the `software.amazon.awssdk.core.retry` package, whereas the `[software.amazon.awssdk.retries](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/retries/package-summary.html)` package contains the retry *strategy* API elements.   
The retry strategy API was introduced as part of the AWS-wide effort to unify the interfaces and behavior of the core components of the SDKs.

The SDK for Java 2.x has three built-in retry strategies: standard, legacy, and adaptive. All three retry strategies are preconfigured to retry on a set of retryable exceptions. Examples of retryable errors are socket timeouts, service-side throttling, concurrency or optimistic lock failures, and transient service errors.

### Standard retry strategy
<a name="retry-strategy-standard"></a>

The [standard retry strategy](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/retries/StandardRetryStrategy.html) is the recommended `RetryStrategy` implementation for normal use cases. Unlike the `AdaptiveRetryStrategy`, the standard strategy is generally useful across all retry use cases.

By default, the standard retry strategy does the following.
+ Retries on the conditions that are configured at build time. You can adjust this with `[StandardRetryStrategy.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/retries/StandardRetryStrategy.Builder.html)#retryOnException`.
+ Retries 2 times for a total of 3 attempts. You can adjust this with `StandardRetryStrategy.Builder#maxAttempts(int)`.
+ For non-throttling exceptions, it uses the `[BackoffStrategy](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/retries/api/BackoffStrategy.html)#exponentialDelay` backoff strategy, with a base delay of 100 milliseconds and a max delay of 20 seconds. You can adjust this with `StandardRetryStrategy.Builder#backoffStrategy`.
+ For throttling exceptions, it uses the `BackoffStrategy#exponentialDelay` backoff strategy, with a base delay of 1 second and a max delay of 20 seconds. You can adjust this with `StandardRetryStrategy.Builder#throttlingBackoffStrategy`.
+ Performs circuit breaking (disabling retries) in the event of high downstream failures. The first attempt is always executed, only retries are disabled. Adjust with `StandardRetryStrategy.Builder#circuitBreakerEnabled`.

### Legacy retry strategy
<a name="retry-strategy-legacy"></a>

The [legacy retry strategy](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/retries/LegacyRetryStrategy.html) is a `RetryStrategy` for normal use cases, however, it is deprecated in favor of the `StandardRetryStrategy`. This is the default retry strategy used by clients when you don't specify another strategy.

It is characterized by treating throttling and non-throttling exceptions differently, for throttling exceptions the base delay for the backoff is larger (500ms) than the base delay for non-throttling exceptions (100ms), and throttling exceptions do not affect the token bucket state. 

Experience using this strategy at scale inside AWS has shown that is not particularly better than the standard retry strategy. Moreover, it fails to protect downstream services from retry storms and can lead to resource starvation on the client side.

By default, the legacy retry strategy does the following.
+ Retries on the conditions that are configured at build time. You can adjust this with `[LegacyRetryStrategy.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/retries/LegacyRetryStrategy.Builder.html)#retryOnException` .
+ Retries 3 times for a total of 4 attempts. You can adjust this with `LegacyRetryStrategy.Builder#maxAttempts(int)`.
+ For non-throttling exceptions, it uses the `BackoffStrategy#exponentialDelay` backoff strategy, with a base delay of 100 milliseconds and a max delay of 20 seconds. You can adjust this with `LegacyRetryStrategy.Builder#backoffStrategy.`
+ For throttling exceptions, it uses the `BackoffStrategy#exponentialDelay` backoff strategy, with a base delay of 500 milliseconds and a max delay of 20 seconds. You can adjust this with `LegacyRetryStrategy.Builder#throttlingBackoffStrategy`.
+ Performs circuit breaking (disabling retries) in the event of high downstream failures. Circuit breaking never prevents a successful first attempt. You can adjust this behavior with `LegacyRetryStrategy.Builder#circuitBreakerEnabled`.
+ The state of the circuit breaker is not affected by throttling exceptions.

### Adaptive retry strategy
<a name="retry-strategy-adaptive"></a>

The [adaptive retry strategy](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/retries/AdaptiveRetryStrategy.html) is a `RetryStrategy` for use cases with a high level of resource constraints. 

The adaptive retry strategy includes all the features of the standard strategy and adds a client-side rate limiter that measures the rate of throttled requests compared to non-throttled requests. The strategy uses this measurement to slow down the requests in an attempt to stay within a safe bandwidth, ideally causing zero throttling errors.

By default, the adaptive retry strategy does the following.
+ Retries on the conditions that are configured at build time. You can adjust this with `[AdaptiveRetryStrategy.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/retries/AdaptiveRetryStrategy.Builder.html)#retryOnException` .
+ Retries 2 times for a total of 3 attempts. You can adjust this with `AdaptiveRetryStrategy.Builder#maxAttempts(int)`.
+ Uses a dynamic backoff delay that is based on the current load against the downstream resource.
+ Performs circuit breaking (disabling retries) when there are high number of downstream failures. Circuit breaking may prevent a second attempt in outage scenarios to protect the downstream service.

**Warning**  
The adaptive retry strategy assumes that the client works against a single resource (for example, one DynamoDB table or one Amazon S3 bucket).   
If you use a single client for multiple resources, throttling or outages associated with one resource result in increased latency and failures when the client accesses all other resources. When you use the adaptive retry strategy, we recommend that you use a single client for each resource.  
We also recommend that you use this strategy in situations where all clients use the adaptive retry strategy against the resource.

**Important**  
The release of retry strategies with 2.26.0 of the Java SDK includes the new [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/RetryMode.html#ADAPTIVE_V2](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/RetryMode.html#ADAPTIVE_V2) enumeration value. The `ADAPTIVE_V2` mode corrects an error that failed to delay the first attempt when throttling errors were detected previously.  
With the 2.26.0 release, users automatically get the `ADAPTIVE_V2` mode behavior by setting the mode as `adaptive` with an environment variable, system property, or profile setting. There is no `adaptive_v2` value for these settings. See the following [Specify a strategy](#retry-strategies-specify) section for how to set the mode.  
Users can get the previous behavior by setting the mode in code using `RetryMode.ADAPTIVE`. 

### Summary: Comparison of retry strategy default values
<a name="retry-strategy-comparison"></a>

The following table shows the default values for the properties of each retry strategy.


| Strategy | Maximum attempts | Base delay for non-throttling errors | Base delay for throttling errors | Token bucket size | Token cost per non-throttling retry | Token cost per throttling retry | 
| --- | --- | --- | --- | --- | --- | --- | 
| Standard | 3 | 100 ms | 1000 ms | 500 | 5 | 5 | 
| Legacy | 4 | 100 ms | 500 ms | 500 | 5 | 0 | 
| Adaptive | 3 | 100 ms | 100 ms | 500 | 5 | 5 | 

**Note**  
DynamoDB clients use a default maximum retry count of 8 for all retry strategies, which is higher than the values shown in the table above for other AWS service clients.

## Specify a strategy
<a name="retry-strategies-specify"></a>

You have four ways to specify a strategy for your service client.

### In code
<a name="retry-strategies-specify-code"></a>

When you build a client, you can configure a lambda expression with a retry strategy. The following snippet configures a standard retry strategy that uses default values on a DynamoDB service client. 

```
DynamoDbClient client = DynamoDbClient.builder()
        .overrideConfiguration(o -> o.retryStrategy(RetryMode.STANDARD))
        .build();
```

You can specify `RetryMode.LEGACY` or `RetryMode.ADAPTIVE` in place of `RetryMode.STANDARD`.

### As a profile setting
<a name="retry-strategies-specify-conf"></a>

Include `retry_mode` as profile setting in the [shared AWS config file](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html). Specify `standard`, `legacy`, or `adaptive` as a value. When set as a profile setting, all service clients that are created while the profile is active use the specified retry strategy with default values. You can override this setting by configuring a retry strategy in code as shown previously.

With the following profile, all service clients use the standard retry strategy.

```
[profile dev]
region = us-east-2
retry_mode = standard
```

### As a JVM system property
<a name="retry-strategies-specify-sysprop"></a>

You can configure a retry stategy for all service clients, unless overridden in code, by using the system property `aws.retryMode`. Specify `standard`, `legacy`, or `adaptive` as a value. 

Use the `-D` switch when you invoke Java as shown in the following command.

```
java -Daws.retryMode=standard ...
```

Alternatively, set the system property in the code *before* creating any client as shown in the following snippet.

```
public void main(String[] args) {
    // Set the property BEFORE any AWS service clients are created.
    System.setProperty("aws.retryMode", "standard");
    ...
}
```

### With an environment variable
<a name="retry-strategies-specify-envvar"></a>

You can also use the `AWS_RETRY_MODE` environment variable with a value of `standard`, `legacy`, or `adaptive`. As with a profile setting or JVM system property, the environment variable configures all service clients with the specified retry mode unless you configure a client in code.

The following command sets the retry mode to `standard` for the current shell session.

```
export AWS_RETRY_MODE=standard
```

## Customize a strategy
<a name="customize-strategy"></a>

You can customize any retry strategy by setting the maximum attempts, backoff strategy, and exceptions that are retryable. You can customize when you build a retry strategy or when you build a client by using a override builder that allows further refinements of the configured strategy.

### Customize maximum attempts
<a name="customize-strategy-max-attempts"></a>

You can configure the maximum number of attempts during client construction as shown in the following statement. The following statement customizes the default retry strategy for the client to a maximum of 5 attempt--a first attempt plus 4 retries.

```
DynamoDbClient client = DynamoDbClient.builder()
        .overrideConfiguration(o -> o.retryStrategy(b -> b.maxAttempts(5)))
        .build();
```

Alternatively, you can build the strategy and provide it to the client as in the following code example. The following code replaces the standard 3 maximum attempts with 10 and configures a DynamoDB client with the customized strategy.

```
StandardRetryStrategy strategy = AwsRetryStrategy.standardRetryStrategy()
         .toBuilder()
         .maxAttempts(10)
         .build();
DynamoDbClient client = DynamoDbClient.builder()
        .overrideConfiguration(o -> o.retryStrategy(strategy))
        .build();
```

**Warning**  
We recommended that you configure each client with a unique `RetryStrategy` instance. If a `RetryStrategy` instance is shared, failures in one client might affect the retry behavior in the other.

You can also set the maximum number of attempts for all clients by using [external settings](https://docs.aws.amazon.com/sdkref/latest/guide/feature-retry-behavior.html) instead of code. You configure this setting as describe in the [Specify a strategy](#retry-strategies-specify) section.

### Customize retryable exceptions
<a name="customize-strategy-retryable-exceptions"></a>

You can configure additional exceptions that trigger retries during client construction. This customization is provided for edge cases where exceptions are thrown that are not included in the default set of retryable exceptions.

The `retryOnException` and `retryOnExceptionOrCause` methods **add** new exception types to the existing set of retryable exceptions; they do not replace the default set. This allows you to extend the retry behavior while maintaining the SDK's default retry capabilities.

The `retryOnExceptionOrCause` method adds a retryable exception if the SDK throws the direct exception or if the exception is wrapped as a cause in another exception.

The following code snippet shows the methods you use to customize the retry exceptions--`retryOnException` and `retryOnExceptionOrCause`. The `retryOnExceptionOrCause` methods adds a retryable exception if the SDK throws the direct exception or if the exception is wrapped.

```
DynamoDbClient client = DynamoDbClient.builder()
        .overrideConfiguration(o -> o.retryStrategy(
                 b -> b.retryOnException(EdgeCaseException.class)
                       .retryOnExceptionOrCause(WrappedEdgeCaseException.class)))
        .build();
```

**Important**  
Retries are disabled for the Kinesis asynchronous client when you call a [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/KinesisAsyncClient.html#subscribeToShard(software.amazon.awssdk.services.kinesis.model.SubscribeToShardRequest,software.amazon.awssdk.services.kinesis.model.SubscribeToShardResponseHandler)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/KinesisAsyncClient.html#subscribeToShard(software.amazon.awssdk.services.kinesis.model.SubscribeToShardRequest,software.amazon.awssdk.services.kinesis.model.SubscribeToShardResponseHandler)) method, regardless of the retry strategy configuration.

### Customize the backoff strategy
<a name="customize-strategy-backoff"></a>

You can build the backoff strategy and supply it to the client.

The following code builds a `BackoffStrategy` that replaces the default, standard strategy's exponential delay backoff strategy. 

```
BackoffStrategy backoffStrategy = 
        BackoffStrategy.exponentialDelay(Duration.ofMillis(150),  // The base delay.
                                         Duration.ofSeconds(15)); // The maximum delay.
DynamoDbClient client = DynamoDbClient.builder()
        .overrideConfiguration(o -> o.retryStrategy(
                b -> b.backoffStrategy(backoffStrategy)))
        .build();
```

## Migrating from `RetryPolicy` to `RetryStrategy`
<a name="migrate-from-retry-policies"></a>

`RetryPolicy` (the retry policy API) will be supported for the foreseeable future. If you currently use an instance of `RetryPolicy` to configure your client, everything is going to work as before. Behind the scenes the Java SDK adapts it to a `RetryStrategy`. The new retry strategy interfaces provide the same functionality as a `RetryPolicy` but are created and configured differently.

# Configure timeouts in AWS SDK for Java 2.x
<a name="timeouts"></a>

The AWS SDK for Java 2.x provides multiple layers of timeout configuration to help you build resilient applications. The SDK offers different types of timeouts that work together to optimize your application's performance and reliability.

There are two main categories of timeouts in the SDK:
+ **Service Client Timeouts** - High-level timeouts that control API operations
+ **HTTP Client Timeouts** - Low-level timeouts that control network communication

## Service client timeouts
<a name="service-client-timeouts"></a>

Service client timeouts operate at the API level and control the overall behavior of service operations, including retries and multiple attempts.

### API call timeout
<a name="api-call-timeout"></a>

The API call timeout sets the maximum amount of time for an entire API operation, including all retry attempts. This timeout provides a hard limit on how long your application waits for a complete operation to finish.

```
S3Client s3Client = S3Client.builder()
    .overrideConfiguration(ClientOverrideConfiguration.builder()
        .apiCallTimeout(Duration.ofMinutes(2))  // Total time for entire operation, such as when you call the getObject method.
        .build())
    .build();
```

Key characteristics:
+ Includes all retry attempts.
+ Includes time spent waiting between retries.
+ Provides absolute maximum wait time.
+ Prevents operations from running indefinitely.

### API call attempt timeout
<a name="api-call-attempt-timeout"></a>

The API call attempt timeout sets the maximum time for a single attempt of an API operation. If this timeout is exceeded, the SDK retries the operation (if retries are configured) rather than failing the entire call.

```
S3Client s3Client = S3Client.builder()
    .overrideConfiguration(ClientOverrideConfiguration.builder()
        .apiCallAttemptTimeout(Duration.ofSeconds(30))  // Time for single attempt.
        .build())
    .build();
```

Key characteristics:
+ Applies to individual attempts only.
+ Enables fast failure and retry for slow requests.
+ Must be shorter than API call timeout.
+ Helps identify and recover from transient issues.

### Configure service client timeouts
<a name="service-timeout-configuration"></a>

You can configure service client timeouts globally for all operations or per-request:

**Global Configuration:**

```
S3Client s3Client = S3Client.builder()
    .overrideConfiguration(b -> b
        .apiCallTimeout(Duration.ofSeconds(105L))
        .apiCallAttemptTimeout(Duration.ofSeconds(25L)))
    .build();
// When you use the s3Client for an API operation, the SDK uses the configured timeout values.
```

**Per-Request Configuration:**

```
S3Client basicS3Client = S3Client.create();

// The following configuration uses the same settings as shown before, but these settings
// apply to only the `putObject` call. When you use `basicS3Client` in another API call without
// supplying the override configuration, there are no API timeout limits. No timeout limits is the default for the SDK.
AwsRequestOverrideConfiguration overrideConfiguration = AwsRequestOverrideConfiguration.builder()
    .apiCallTimeout(Duration.ofSeconds(105L))
    .apiCallAttemptTimeout(Duration.ofSeconds(25L))
    .build();

basicS3Client.putObject(b -> b
        .bucket("amzn-s3-demo-bucket")
        .key("example-key")
        .overrideConfiguration(overrideConfiguration),
    RequestBody.fromString("test"));
```

### Best practices for API timeouts
<a name="timeout-best-practice"></a>

The SDK for Java 2.x doesn't set API call timeouts or individual API call attempt timeouts by default. Set timeouts for both individual attempts and the entire request. This helps your application fail fast when transient issues cause request attempts to take longer or when fatal network issues occur.

## HTTP client timeouts
<a name="http-client-timeouts"></a>

HTTP client timeouts operate at the network level and control various aspects of HTTP communication. These timeouts vary depending on which HTTP client implementation you use.

### Connection timeout
<a name="connection-timeout"></a>

The connection timeout controls how long to wait when establishing a new connection to the AWS service endpoint.

```
// Available with all HTTP clients.
ApacheHttpClient.builder()
    .connectionTimeout(Duration.ofSeconds(5L))
    .build();
```

Purpose:
+ Prevents hanging on network connectivity issues.
+ Fails fast when services are unreachable.
+ Essential for applications that need responsive error handling.

### Socket timeout (Apache and URLConnection clients)
<a name="socket-timeout"></a>

The socket timeout controls how long to wait for data on an established connection.

```
ApacheHttpClient.builder()
    .socketTimeout(Duration.ofSeconds(30L))  // Time to wait for response data.
    .build();
```

### Read and write timeouts (Netty client)
<a name="read-write-timeouts"></a>

The Netty client provides separate timeouts for read and write operations:

```
NettyNioAsyncHttpClient.builder()
    .readTimeout(Duration.ofSeconds(30L))   // Reading response data.
    .writeTimeout(Duration.ofSeconds(30L))  // Writing request data.
    .build();
```

### TLS negotiation timeout (Netty client)
<a name="tls-negotiation-timeout"></a>

Controls the time allowed for TLS/SSL handshake:

```
NettyNioAsyncHttpClient.builder()
    .tlsNegotiationTimeout(Duration.ofSeconds(3L))
    .build();
```

### Connection pool timeouts
<a name="connection-pool-timeouts"></a>

Some HTTP clients provide timeouts for connection pool operations:

```
ApacheHttpClient.builder()
    .connectionAcquisitionTimeout(Duration.ofSeconds(10L))  // Wait for pool connection.
    .connectionTimeToLive(Duration.ofMinutes(5L))           // Maximum connection age.
    .connectionMaxIdleTime(Duration.ofSeconds(60L))         // Maximum idle time.
    .build()
```

The [Configure HTTP clients](http-configuration.md) contains more information on HTTP clients in the AWS SDK for Java 2.x

## Timeout interactions and hierarchy
<a name="timeout-interactions"></a>

Understanding how different timeouts interact is crucial for proper configuration:

### Timeout hierarchy
<a name="timeout-hierarchy"></a>

```
API Call Timeout (2 minutes)
├── Retry Attempt 1
│   ├── API Call Attempt Timeout (45 seconds)
│   └── HTTP Client Timeouts
│       ├── Connection Timeout (5 seconds)
│       ├── TLS Negotiation Timeout (3 seconds)
│       └── Read/Write Timeout (30 seconds)
├── Retry Attempt 2
│   └── [Same structure as Attempt 1]
└── Retry Attempt 3
    └── [Same structure as Attempt 1]
```

### Configuration rules
<a name="configuration-rules"></a>

API call timeout ≥ API call attempt timeout  

```
// Correct configuration.
.apiCallTimeout(Duration.ofMinutes(2))         // 120 seconds.
.apiCallAttemptTimeout(Duration.ofSeconds(30)) // 30 seconds.
```

API call attempt timeout ≥ HTTP client timeouts  

```
// HTTP client timeouts must be less than attempt timeout.
.apiCallAttemptTimeout(Duration.ofSeconds(30L))   // 30 seconds.
// HTTP client configuration.
.connectionTimeout(Duration.ofSeconds(5L))        // 5 seconds.
.readTimeout(Duration.ofSeconds(25L))             // 25 seconds (< 30).
```

Account for multiple attempts  

```
// If you have 3 retry attempts, each taking up to 30 seconds
// API call timeout must be at least 90 seconds plus overhead.
.apiCallTimeout(Duration.ofMinutes(2L))          // 120 seconds.
.apiCallAttemptTimeout(Duration.ofSeconds(30))   // 30 seconds per attempt.
```

## Use smart configuration defaults
<a name="smart-configuration-defaults"></a>

The SDK provides smart defaults that automatically configure appropriate timeout values:

```
// Enable smart defaults.
S3Client client = S3Client.builder()
    .defaultsMode(DefaultsMode.AUTO)  // Automatically choose appropriate defaults.
    .build();

// Available modes:
// - STANDARD: Balanced defaults
// - IN_REGION: Optimized for same-region calls
// - CROSS_REGION: Optimized for cross-region calls  
// - MOBILE: Optimized for mobile applications
// - AUTO: Automatically detect and choose appropriate mode
// - LEGACY: Provides settings that were used before smart defaults existed.
```

Smart defaults automatically configure:
+ Connection timeout values.
+ TLS negotiation timeout values.
+ Other client settings.

## Summary
<a name="timeout-summary"></a>

Effective timeout configuration in AWS SDK for Java 2.x requires understanding the interaction between service client timeouts and HTTP client timeouts:

1. **Service client timeouts** control high-level API behavior.

1. **HTTP client timeouts** control low-level network behavior.

1. **Proper hierarchy** ensures timeouts work together effectively.

1. **Smart defaults** provide good starting points for most applications.

Configure timeouts appropriately for your use case to build applications that are both resilient to network issues and responsive to users.

# Configuring observability features in the AWS SDK for Java 2.x
<a name="observability"></a>

Telemetry is the automated collection and transmission of data from remote sources that enable you to monitor and analyze your system's behavior. 

Observability in the SDK for Java 2.x provides developers with comprehensive insight into how their Java applications interact with AWS services through rich telemetry data that captures the complete request lifecycle. These capabilities enable you to collect, analyze, and visualize telemetry signals such as metrics, logs, and traces, allowing you to monitor request patterns, identify bottlenecks, and optimize your application's AWS interactions for improved reliability and performance.

**Topics**
+ [Metrics](metrics.md)
+ [Monitoring](monitoring-overview.md)
+ [Logging](logging-slf4j.md)

# Publish SDK metrics from the AWS SDK for Java 2.x
<a name="metrics"></a>

With the AWS SDK for Java 2.x you can collect metrics about the service clients and requests in your application, analyze the output in Amazon CloudWatch Logs, and then act on it.

By default, metrics collection is disabled in the SDK. This topic helps you to enable and configure it.

## Getting started with SDK metrics
<a name="getting-started-with-metrics"></a>

To enable metrics collection in your application, choose the appropriate implementation of the `[MetricPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/metrics/MetricPublisher.html)` interface based on your use case and follow the detailed setup instructions:

**For long-running applications:**
+ Use `[CloudWatchMetricPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/metrics/publishers/cloudwatch/CloudWatchMetricPublisher.html)`
+ See [Publish SDK metrics from long-running applications](metric-pub-impl-cwmp.md) for complete setup instructions, code examples, and configuration options.

**For AWS Lambda functions:**
+ Use `[EmfMetricLoggingPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/metrics/publishers/emf/EmfMetricLoggingPublisher.html)`
+ See [Publish SDK metrics for AWS Lambda functions](metric-pub-impl-emf.md) for complete setup instructions, dependencies, and Lambda-specific configuration.

**For troubleshooting and console output:**
+ Use `[LoggingMetricPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/metrics/LoggingMetricPublisher.html)`
+ See [Output SDK metrics to console for development and debugging](metric-pub-impl-logging.md) for setup instructions, formatting options, and examples for local development and troubleshooting.

## Quick implementation preview
<a name="quick-implementation-preview"></a>

Here's what enabling metrics looks like for each use case:

**Long-running applications:**

```
MetricPublisher metricsPub = CloudWatchMetricPublisher.create();
DynamoDbClient ddb = DynamoDbClient.builder()
    .overrideConfiguration(c -> c.addMetricPublisher(metricsPub))
    .build();
```

**Lambda functions:**

```
EmfMetricLoggingPublisher emfPublisher = EmfMetricLoggingPublisher.builder()
    .namespace("MyApp")
    .build();
DynamoDbClient dynamoDb = DynamoDbClient.builder()
    .overrideConfiguration(c -> c.addMetricPublisher(emfPublisher))
    .build();
```

**Development and debugging:**

```
MetricPublisher loggingPublisher = LoggingMetricPublisher.create();
S3Client s3 = S3Client.builder()
    .overrideConfiguration(c -> c.addMetricPublisher(loggingPublisher))
    .build();
```

## Metrics limitation of the AWS CRT-based S3 client
<a name="metrics-using-s3-crt-based-client"></a>

The [AWS CRT-based S3 client](crt-based-s3-client.md) does not currently support SDK metrics collection. The builder for an AWS CRT-based S3 client instance, [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3CrtAsyncClientBuilder.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3CrtAsyncClientBuilder.html), does not provide methods to configure metrics publishers.

## When are metrics available?
<a name="when-are-metrics-available"></a>

Metrics are generally available within 5-10 minutes after the SDK for Java emits them. For accurate and up-to-date metrics, check Cloudwatch at least 10 minutes after emitting the metrics from your Java applications. 

## What information is collected?
<a name="what-information-is-collected"></a>

Metrics collection includes the following:
+ Number of API requests, including whether they succeed or fail
+ Information about the AWS services you call in your API requests, including exceptions returned
+ The duration for various operations such as Marshalling, Signing, and HTTP requests
+ HTTP client metrics, such as the number of open connections, the number of pending requests, and the name of the HTTP client used

**Note**  
The metrics available vary by HTTP client.

For a complete list, see [Service client metrics](metrics-list.md).

## How can I use this information?
<a name="how-can-i-use-this-information"></a>

You can use the metrics the SDK collects to monitor the service clients in your application. You can look at overall usage trends, identify anomalies, review service client exceptions returned, or to dig in to understand a particular issue. Using Amazon CloudWatch Logs, you can also create alarms to notify you as soon as your application reaches a condition that you define.

For more information, see [Using Amazon CloudWatch Logs Metrics](http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/working_with_metrics.html) and [Using Amazon CloudWatch Logs Alarms](http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html) in the [ Amazon CloudWatch Logs User Guide](http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/).

# Publish SDK metrics from long-running applications using the AWS SDK for Java 2.x
<a name="metric-pub-impl-cwmp"></a>

Because the `[CloudWatchMetricPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/metrics/publishers/cloudwatch/CloudWatchMetricPublisher.html)` implementation aggregates and periodically uploads metrics to Amazon CloudWatch with a delay, its use is best suited for long-running applications. 

The default settings of the metrics publisher are meant to minimize memory usage and CloudWatch cost, while still providing a useful amount of insight into the metric data.

## Set-up
<a name="prerequisitesmetrics"></a>

Before you can enable and use metrics by using `CloudWatchMetricPublisher`, complete the following steps.

### Step 1: Add required dependency
<a name="cwmp-set-up-deps"></a>

Configure your project dependencies (for example, in your `pom.xml` or `build.gradle` file) to use version `2.14.0` or later of the AWS SDK for Java.

Include the artifactId `cloudwatch-metric-publisher` with the version number `2.14.0` or later in your project's dependencies.

For example:

```
<project>
  <dependencyManagement>
   <dependencies>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>bom</artifactId>
        <version>[2.30.11](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)</version>  <!-- Navigate the link to see the latest version. -->
        <type>pom</type>
        <scope>import</scope>
      </dependency>
   </dependencies>
  </dependencyManagement>
  <dependencies>
   <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>cloudwatch-metric-publisher</artifactId>
   </dependency>
  </dependencies>
</project>
```

### Step 2: Configure required permissions
<a name="cwmp-set-up-perms"></a>

Enable `cloudwatch:PutMetricData` permissions for the IAM identity used by the metrics publisher to allow the SDK for Java to write metrics.

## Enable metrics for a specific request
<a name="enable-metrics-for-a-specific-request"></a>

The following class shows how to enable the CloudWatch metrics publisher for a request to Amazon DynamoDB. It uses the default metrics publisher configuration.

```
import software.amazon.awssdk.metrics.MetricPublisher;
import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.ListTablesRequest;

public class DefaultConfigForRequest {
    // Use one MetricPublisher for your application. It can be used with requests or service clients.
    static MetricPublisher metricsPub = CloudWatchMetricPublisher.create();

    public static void main(String[] args) {
        DynamoDbClient ddb = DynamoDbClient.create();
        // Publish metrics the for ListTables operation.
        ddb.listTables(ListTablesRequest.builder()
            .overrideConfiguration(c -> c.addMetricPublisher(metricsPub))
            .build());

        // Perform more work in your application.

        // A MetricsPublisher has its own lifecycle independent of any service client or request that uses it.
        // If you no longer need the publisher, close it to free up resources.
        metricsPub.close();  // All metrics stored in memory are flushed to CloudWatch.

        // Perform more work with the DynamoDbClient instance without publishing metrics.
        // Close the service client when you no longer need it.
        ddb.close();
    }
}
```

**Important**  
Make sure your application calls `close` on the `[MetricPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/metrics/MetricPublisher.html)` instance when the service client is no longer in use. Failure to do so results in possible thread or file descriptor leaks.

## Enable summary metrics for a specific service client
<a name="enable-metrics-for-a-specific-service-client"></a>

The following code snippet shows how to enable a CloudWatch metrics publisher with default settings for a service client.

```
MetricPublisher metricsPub = CloudWatchMetricPublisher.create();

DynamoDbClient ddb = DynamoDbClient.builder()
          .overrideConfiguration(c -> c.addMetricPublisher(metricsPub))
          .build();
```

## Customize a CloudWatch metrics publisher
<a name="customize-metrics-publisher"></a>

The following class demonstrates how to set up a custom configuration for the metrics publisher for a specific service client. The customizations include loading a specific profile, specifying a AWS Region where the metrics publisher sends requests, and customizing how often the publisher sends metrics to CloudWatch.

```
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.core.metrics.CoreMetric;
import software.amazon.awssdk.metrics.MetricPublisher;
import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;

import java.time.Duration;

public class CustomConfigForDDBClient {
    // Use one MetricPublisher for your application. It can be used with requests or service clients.
    static MetricPublisher metricsPub = CloudWatchMetricPublisher.builder()
        .cloudWatchClient(CloudWatchAsyncClient.builder()
            .region(Region.US_WEST_2)
            .credentialsProvider(ProfileCredentialsProvider.create("cloudwatch"))
            .build())
        .uploadFrequency(Duration.ofMinutes(5))
        .maximumCallsPerUpload(100)
        .namespace("ExampleSDKV2Metrics")
        .detailedMetrics(CoreMetric.API_CALL_DURATION)
        .build();

    public static void main(String[] args) {
        DynamoDbClient ddb = DynamoDbClient.builder()
            .overrideConfiguration(c -> c.addMetricPublisher(metricsPub))
            .build();
        // Publish metrics for DynamoDB operations.
        ddb.listTables();
        ddb.describeEndpoints();
        ddb.describeLimits();
        // Perform more work in your application.

        // A MetricsPublisher has its own lifecycle independent of any service client or request that uses it.
        // If you no longer need the publisher, close it to free up resources.
        metricsPub.close();  // All metrics stored in memory are flushed to CloudWatch.


        // Perform more work with the DynamoDbClient instance without publishing metrics.
        // Close the service client when you no longer need it.
        ddb.close();
    }
}
```

The customizations shown in the previous snippet have the following effects.
+ The `cloudWatchClient` method lets you customize the CloudWatch client used to send metrics. In this example, we use a different region from the default of *us-east-1* where the client sends metrics. We also use a different named profile, *cloudwatch*, whose credentials will be used to authenticate requests to CloudWatch. Those credentials must have permissions to `cloudwatch:PutMetricData`.
+ The `uploadFrequency` method allows you to specify how frequently the metrics publisher uploads metrics to CloudWatch. The default is once a minute.
+ The `maximumCallsPerUpload` method limits the number of calls made per upload. The default is unlimited.
+ By default, the SDK for Java 2.x publishes metrics under the namespace `AwsSdk/JavaSdk2`. You can use the `namespace` method to specify a different value.
+ By default, the SDK publishes summary metrics. Summary metrics consist of average, minimum, maximum, sum, and sample count. By specifying one or more SDK metrics in the `detailedMetrics` method, the SDK publishes additional data for each metric. This additional data enables percentile statistics like p90 and p99 that you can query in CloudWatch. The detailed metrics are especially useful for latency metrics like `APICallDuration`, which measures the end-to-end latency for SDK client requests. You can use fields of the `[CoreMetric](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/metrics/CoreMetric.html)` class to specify other common SDK metrics. 

**Next steps:** If you're also working with Lambda functions, see [Publish SDK metrics for AWS Lambda functions](metric-pub-impl-emf.md) for EMF-based metrics publishing.

# Publish SDK metrics for AWS Lambda functions using the AWS SDK for Java 2.x
<a name="metric-pub-impl-emf"></a>

Because Lambda functions typically execute for milliseconds to minutes, any delay in sending the metrics, which happens with the `CloudWatchMetricPublisher`, risks the loss of data. 

`[EmfMetricLoggingPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/metrics/publishers/emf/EmfMetricLoggingPublisher.html)` provides a more suitable approach by immediately writing metrics as structured log entries in [CloudWatch Embedded Metric Format (EMF)](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html). `EmfMetricLoggingPublisher` works in execution environments that have built-in integration with Amazon CloudWatch Logs such as AWS Lambda and Amazon Elastic Container Service.

## Set-up
<a name="metric-pub-impl-emf-set-up"></a>

Before you can enable and use metrics by using `EmfMetricLoggingPublisher`, complete the following steps.

### Step 1: Add required dependency
<a name="metric-pub-impl-emf-set-up-deps"></a>

Configure your project dependencies (for example, in your `pom.xml` or `build.gradle` file) to use version `2.30.3` or later of the AWS SDK for Java.

Include the artifactId `emf-metric-logging-publisher` with the version number `2.30.3` or later in your project's dependencies.

For example:

```
<project>
  <dependencyManagement>
   <dependencies>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>bom</artifactId>
        <version>[2.30.11](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)</version>  <!-- Navigate the link to see the latest version. -->
        <type>pom</type>
        <scope>import</scope>
      </dependency>
   </dependencies>
  </dependencyManagement>
  <dependencies>
   <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>emf-metric-logging-publisher</artifactId>
   </dependency>
  </dependencies>
</project>
```

### Step 2: Configure required permissions
<a name="metric-pub-impl-emf-set-up-perm"></a>

Enable `logs:PutLogEvents` permissions for the IAM identity used by the metrics publisher to allow the SDK for Java to write EMF-formatted logs.

### Step 3: Setup logging
<a name="metric-pub-impl-emf-set-up-logger"></a>

To ensure proper metric collection, configure your logging to output to the console at the `INFO` level or lower (such as `DEBUG`). In your `log4j2.xml` file:

```
<Loggers>
  <Root level="WARN">
   <AppenderRef ref="ConsoleAppender"/>
  </Root>
  <Logger name="software.amazon.awssdk.metrics.publishers.emf.EmfMetricLoggingPublisher" level="INFO" />
</Loggers>
```

See the [logging topic](logging-slf4j.md) in this guide for more information on how to set up a `log4j2.xml` file. 

## Configure and use `EmfMetricLoggingPublisher`
<a name="metric-pub-impl-emf-use"></a>

The following Lambda function class first creates and configures an `EmfMetricLoggingPublisher` instance and then uses it with a Amazon DynamoDB service client:

```
public class GameIdHandler implements RequestHandler<Map<String, String>, String> {
    private final EmfMetricLoggingPublisher emfPublisher;
    private final DynamoDbClient dynamoDb;

    public GameIdHandler() {
        // Build the publisher. 
        this.emfPublisher = EmfMetricLoggingPublisher.builder()
                .namespace("namespace")
                .dimensions(CoreMetric.SERVICE_ID,
                        CoreMetric.OPERATION_NAME)
                .build();
        // Add the publisher to the client.
        this.dynamoDb = DynamoDbClient.builder()
                .overrideConfiguration(c -> c.addMetricPublisher(emfPublisher))
                .region(Region.of(System.getenv("AWS_REGION")))
                .build();
    }

    @Override
    public String handleRequest(Map<String, String> event, Context context) {
        Map<String, AttributeValue> gameItem = new HashMap<>();

        gameItem.put("gameId", AttributeValue.builder().s(event.get("id")).build());

        PutItemRequest putItemRequest = PutItemRequest.builder()
                .tableName("games")
                .item(gameItem)
                .build();

        dynamoDb.putItem(putItemRequest);

        return "Request handled";
    }
}
```

When the DynamoDB client executes the `putItem` method, it automatically publishes metrics to a CloudWatch log stream in EMF format. 

### Example of an EMF log event
<a name="emf-logged-output"></a>

For example, if you send the following event to the GameHandler Lambda function with logging configured as shown previously:

```
{
  "id": "23456"
}
```

After the function processes the event, you find two log events that look similar to the following example. The JSON object in the second event contains the Java SDK metric data for the `PutItem` operation to DynamoDB.

When CloudWatch receives a log event in EMF format, it automatically parses the structured JSON to extract metric data. CloudWatch then creates corresponding metrics while storing the original log entry in CloudWatch Logs.

```
2025-07-11 15:58:30 [main] INFO  org.example.GameIdHandler:39 - Received map: {id=23456}

2025-07-11 15:58:34 [main] INFO  software.amazon.awssdk.metrics.publishers.emf.EmfMetricLoggingPublisher:43 - 
{
    "_aws": {
        "Timestamp": 1752249513975,
        "LogGroupName": "/aws/lambda/GameId",
        "CloudWatchMetrics": [
            {
                "Namespace": "namespace",
                "Dimensions": [
                    [
                        "OperationName",
                        "ServiceId"
                    ]
                ],
                "Metrics": [
                    {
                        "Name": "AvailableConcurrency"
                    },
                    {
                        "Name": "PendingConcurrencyAcquires"
                    },
                    {
                        "Name": "ServiceCallDuration",
                        "Unit": "Milliseconds"
                    },
                    {
                        "Name": "EndpointResolveDuration",
                        "Unit": "Milliseconds"
                    },
                    {
                        "Name": "MaxConcurrency"
                    },
                    {
                        "Name": "BackoffDelayDuration",
                        "Unit": "Milliseconds"
                    },
                    {
                        "Name": "MarshallingDuration",
                        "Unit": "Milliseconds"
                    },
                    {
                        "Name": "LeasedConcurrency"
                    },
                    {
                        "Name": "SigningDuration",
                        "Unit": "Milliseconds"
                    },
                    {
                        "Name": "ConcurrencyAcquireDuration",
                        "Unit": "Milliseconds"
                    },
                    {
                        "Name": "ApiCallSuccessful"
                    },
                    {
                        "Name": "RetryCount"
                    },
                    {
                        "Name": "UnmarshallingDuration",
                        "Unit": "Milliseconds"
                    },
                    {
                        "Name": "ApiCallDuration",
                        "Unit": "Milliseconds"
                    },
                    {
                        "Name": "CredentialsFetchDuration",
                        "Unit": "Milliseconds"
                    }
                ]
            }
        ]
    },
    "AvailableConcurrency": 0,
    "PendingConcurrencyAcquires": 0,
    "OperationName": "PutItem",
    "ServiceCallDuration": 1339,
    "EndpointResolveDuration": 81,
    "MaxConcurrency": 50,
    "BackoffDelayDuration": 0,
    "ServiceId": "DynamoDB",
    "MarshallingDuration": 181,
    "LeasedConcurrency": 1,
    "SigningDuration": 184,
    "ConcurrencyAcquireDuration": 83,
    "ApiCallSuccessful": 1,
    "RetryCount": 0,
    "UnmarshallingDuration": 85,
    "ApiCallDuration": 1880,
    "CredentialsFetchDuration": 138
}
```

The [API documentation](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/metrics/publishers/emf/EmfMetricLoggingPublisher.Builder.html) for `EmfMetricLoggingPublisher.Builder` shows the configuration options that you can use.

You can also enable EMF metric logging for a single request as [shown for the CloudWatchMetricPublisher](metric-pub-impl-cwmp.md#enable-metrics-for-a-specific-request).

**Next steps:** For long-running applications, see [Publish SDK metrics from long-running applications](metric-pub-impl-cwmp.md) for CloudWatch-based metrics publishing.

# Output SDK metrics to the console using the AWS SDK for Java 2.x
<a name="metric-pub-impl-logging"></a>

The `[LoggingMetricPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/metrics/LoggingMetricPublisher.html)` implementation outputs metrics directly to your application's console or log files. This approach is ideal for development, debugging, and understanding what metrics the SDK collects without requiring external services like Amazon CloudWatch.

Unlike `CloudWatchMetricPublisher` and `EmfMetricLoggingPublisher`, `LoggingMetricPublisher` provides immediate output with no delays or external dependencies. This makes it perfect for local development and troubleshooting scenarios.

## When to use LoggingMetricPublisher
<a name="logging-metric-publisher-when-to-use"></a>

Use `LoggingMetricPublisher` when you need to:
+ Debug metric collection during development
+ Understand what metrics the SDK collects for your operations
+ Troubleshoot performance issues locally
+ Test metric collection without external service dependencies
+ View metrics immediately in your console or log files

**Note**  
`LoggingMetricPublisher` is not recommended for production environments where you need persistent metric storage and analysis capabilities.

## Set up console logging for metrics
<a name="logging-metric-publisher-setup"></a>

To see `LoggingMetricPublisher` output, configure your logging framework to display `INFO` level messages. The following `log4j2.xml` configuration ensures metrics appear in your console:

```
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="ConsoleAppender" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="ConsoleAppender"/>
        </Root>
        <!-- Ensure LoggingMetricPublisher output appears. -->
        <Logger name="software.amazon.awssdk.metrics.LoggingMetricPublisher" level="INFO" />
    </Loggers>
</Configuration>
```

This configuration directs the SDK to output metrics to your console at the `INFO` level. The `LoggingMetricPublisher` logger configuration ensures that metric output appears even if your root logger uses a higher level like `WARN` or `ERROR`.

## Enable console metrics for a service client
<a name="logging-metric-publisher-basic-usage"></a>

The following example shows how to create a `LoggingMetricPublisher` and use it with an Amazon Simple Storage Service client:

```
import software.amazon.awssdk.metrics.LoggingMetricPublisher;
import software.amazon.awssdk.metrics.MetricPublisher;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

// Create a LoggingMetricPublisher with default settings.
MetricPublisher metricPublisher = LoggingMetricPublisher.create();

// Add the publisher to your service client.
S3Client s3Client = S3Client.builder()
    .region(Region.US_EAST_1)
    .overrideConfiguration(config -> config.addMetricPublisher(metricPublisher))
    .build();

// Make requests - metrics will appear in your console.
s3Client.listBuckets();

// Clean up resources.
metricPublisher.close();
s3Client.close();
```

## Choose metric output format
<a name="logging-metric-publisher-formatting-options"></a>

`LoggingMetricPublisher` supports two output formats:
+ **PLAIN format (default):** Outputs metrics as compact, single-line entries
+ **PRETTY format:** Outputs metrics in a multi-line, human-readable format

The following example shows how to use the PRETTY format for easier reading during development:

```
import org.slf4j.event.Level;
import software.amazon.awssdk.metrics.LoggingMetricPublisher;

// Create a LoggingMetricPublisher with PRETTY format.
MetricPublisher prettyMetricPublisher = LoggingMetricPublisher.create(
    Level.INFO, 
    LoggingMetricPublisher.Format.PRETTY
);

// Use with your service client.
S3Client s3Client = S3Client.builder()
    .region(Region.US_EAST_1)
    .overrideConfiguration(config -> config.addMetricPublisher(prettyMetricPublisher))
    .build();
```

## Complete example
<a name="logging-metric-publisher-complete-example"></a>

The following example demonstrates using `LoggingMetricPublisher` in two ways:
+ At the service client level
+ For a single request

```
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import software.amazon.awssdk.metrics.LoggingMetricPublisher;
import software.amazon.awssdk.metrics.MetricPublisher;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.ListBucketsRequest;
import software.amazon.awssdk.services.s3.model.ListBucketsResponse;

/**
 * Demonstrates how to use LoggingMetricPublisher with AWS S3 SDK for Java 2.x.
 * <p>
 * This demo focuses on the S3 listBuckets operation to show how metrics are collected
 * and logged to the console for development and debugging purposes.
 * <p>
 * LoggingMetricPublisher is ideal for:
 * - Development and debugging
 * - Console output for troubleshooting
 * - Understanding what metrics are being collected
 * - Testing metric collection without external dependencies
 */
public class S3LoggingMetricPublisherDemo {

    private static final Logger logger = LoggerFactory.getLogger(S3LoggingMetricPublisherDemo.class);

    public static void main(String[] args) {
        S3LoggingMetricPublisherDemo demo = new S3LoggingMetricPublisherDemo();
        demo.demonstrateUsage();
    }

    /**
     * Demonstrates basic usage with S3Client and metrics enabled at the client level.
     */
    private void demonstrateUsage() {

        // Create a LoggingMetricPublisher with default settings. The SDK logs metrics as text in a single line.
        // The default settings are equivalent to using `LoggingMetricPublisher.Format.PLAIN`.

        MetricPublisher metricPublisher = LoggingMetricPublisher.create();

        // Create an S3 client with metrics enabled.
        try (S3Client s3Client = S3Client.builder()
                .region(Region.US_EAST_1)
                .overrideConfiguration(config -> config.addMetricPublisher(metricPublisher))
                .build()) {

            // Make the listBuckets request - metrics will be logged to console.
            ListBucketsResponse response = s3Client.listBuckets(ListBucketsRequest.builder().build());

            // The next block shows the using a different LoggingMetricPublisher with a `PRETTY` format.
            // Since the metric publisher is added to the request using the `overrideConfiguration`, this formatting
            // applies only to the one request.
            try {
                s3Client.listBuckets(ListBucketsRequest.builder()
                        .overrideConfiguration(config -> config
                                .addMetricPublisher(LoggingMetricPublisher.create(
                                        Level.INFO, LoggingMetricPublisher.Format.PRETTY)))
                        .build());
            } catch (Exception e) {
                logger.info("Request failed with metrics logged: {}", e.getMessage());
            }
            logger.info("Found {} buckets in your AWS account.", response.buckets().size());

        } catch (Exception e) {
            logger.error("Error during S3 operation: {}", e.getMessage());
            logger.info("Note: This is expected if AWS credentials are not configured.");
        }

        // Close the metric publisher to flush any remaining metrics.
        metricPublisher.close();
    }
}
```

The code logs the following to the console:

```
INFO  LoggingMetricPublisher - Metrics published: MetricCollection(name=ApiCall, metrics=[MetricRecord(metric=MarshallingDuration, value=PT0.005409792S), MetricRecord(metric=RetryCount, value=0), MetricRecord(metric=ApiCallSuccessful, value=true), MetricRecord(metric=OperationName, value=ListBuckets), MetricRecord(metric=EndpointResolveDuration, value=PT0.000068S), MetricRecord(metric=ApiCallDuration, value=PT0.163802958S), MetricRecord(metric=CredentialsFetchDuration, value=PT0.145686542S), MetricRecord(metric=ServiceEndpoint, value=https://s3.amazonaws.com), MetricRecord(metric=ServiceId, value=S3)], children=[MetricCollection(name=ApiCallAttempt, metrics=[MetricRecord(metric=TimeToFirstByte, value=PT0.138816S), MetricRecord(metric=SigningDuration, value=PT0.007803459S), MetricRecord(metric=ReadThroughput, value=165153.96002660287), MetricRecord(metric=ServiceCallDuration, value=PT0.138816S), MetricRecord(metric=AwsExtendedRequestId, value=e13Swj3uwn0qP1Oz+m7II5OGq7jf8xxT8H18iDfRBCQmDg+gU4ek91Xrsl8XxRLROlIzCAPQtsQF0DAAWOb8ntuKCzX2AJdj), MetricRecord(metric=HttpStatusCode, value=200), MetricRecord(metric=BackoffDelayDuration, value=PT0S), MetricRecord(metric=TimeToLastByte, value=PT0.148915667S), MetricRecord(metric=AwsRequestId, value=78AW9BM7SWR6YMGB)], children=[MetricCollection(name=HttpClient, metrics=[MetricRecord(metric=MaxConcurrency, value=50), MetricRecord(metric=AvailableConcurrency, value=0), MetricRecord(metric=LeasedConcurrency, value=1), MetricRecord(metric=ConcurrencyAcquireDuration, value=PT0.002623S), MetricRecord(metric=PendingConcurrencyAcquires, value=0), MetricRecord(metric=HttpClientName, value=Apache)], children=[])])])
INFO  LoggingMetricPublisher - [4e6f2bb5] ApiCall
INFO  LoggingMetricPublisher - [4e6f2bb5] ┌──────────────────────────────────────────┐
INFO  LoggingMetricPublisher - [4e6f2bb5] │ MarshallingDuration=PT0.000063S          │
INFO  LoggingMetricPublisher - [4e6f2bb5] │ RetryCount=0                             │
INFO  LoggingMetricPublisher - [4e6f2bb5] │ ApiCallSuccessful=true                   │
INFO  LoggingMetricPublisher - [4e6f2bb5] │ OperationName=ListBuckets                │
INFO  LoggingMetricPublisher - [4e6f2bb5] │ EndpointResolveDuration=PT0.000024375S   │
INFO  LoggingMetricPublisher - [4e6f2bb5] │ ApiCallDuration=PT0.018463083S           │
INFO  LoggingMetricPublisher - [4e6f2bb5] │ CredentialsFetchDuration=PT0.000022334S  │
INFO  LoggingMetricPublisher - [4e6f2bb5] │ ServiceEndpoint=https://s3.amazonaws.com │
INFO  LoggingMetricPublisher - [4e6f2bb5] │ ServiceId=S3                             │
INFO  LoggingMetricPublisher - [4e6f2bb5] └──────────────────────────────────────────┘
INFO  LoggingMetricPublisher - [4e6f2bb5]     ApiCallAttempt
INFO  LoggingMetricPublisher - [4e6f2bb5]     ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
INFO  LoggingMetricPublisher - [4e6f2bb5]     │ TimeToFirstByte=PT0.0165575S                                                                                          │
INFO  LoggingMetricPublisher - [4e6f2bb5]     │ SigningDuration=PT0.000301125S                                                                                        │
INFO  LoggingMetricPublisher - [4e6f2bb5]     │ ReadThroughput=1195591.792850103                                                                                      │
INFO  LoggingMetricPublisher - [4e6f2bb5]     │ ServiceCallDuration=PT0.0165575S                                                                                      │
INFO  LoggingMetricPublisher - [4e6f2bb5]     │ AwsExtendedRequestId=3QI1eenRuokdszWqZBmBMDUmko6FlSmHkM+CUMNMeLor7gJml4D4lv6QXUZ1zWoTgG+tHbr6yo2vHdz4h1P8PDovvtMFRCeB │
INFO  LoggingMetricPublisher - [4e6f2bb5]     │ HttpStatusCode=200                                                                                                    │
INFO  LoggingMetricPublisher - [4e6f2bb5]     │ BackoffDelayDuration=PT0S                                                                                             │
INFO  LoggingMetricPublisher - [4e6f2bb5]     │ TimeToLastByte=PT0.017952625S                                                                                         │
INFO  LoggingMetricPublisher - [4e6f2bb5]     │ AwsRequestId=78AVFAF795AAWAXH                                                                                         │
INFO  LoggingMetricPublisher - [4e6f2bb5]     └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
INFO  LoggingMetricPublisher - [4e6f2bb5]         HttpClient
INFO  LoggingMetricPublisher - [4e6f2bb5]         ┌───────────────────────────────────────┐
INFO  LoggingMetricPublisher - [4e6f2bb5]         │ MaxConcurrency=50                     │
INFO  LoggingMetricPublisher - [4e6f2bb5]         │ AvailableConcurrency=0                │
INFO  LoggingMetricPublisher - [4e6f2bb5]         │ LeasedConcurrency=1                   │
INFO  LoggingMetricPublisher - [4e6f2bb5]         │ ConcurrencyAcquireDuration=PT0.00004S │
INFO  LoggingMetricPublisher - [4e6f2bb5]         │ PendingConcurrencyAcquires=0          │
INFO  LoggingMetricPublisher - [4e6f2bb5]         │ HttpClientName=Apache                 │
INFO  LoggingMetricPublisher - [4e6f2bb5]         └───────────────────────────────────────┘
INFO  S3LoggingMetricPublisherDemo - Found 6 buckets in your AWS account.
```

### Additional artifacts for the example
<a name="logging-metric-publisher-complete-example-artifacts"></a>

Maven `pom.xml` file

```
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>s3-logging-metric-publisher-demo</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <name>AWS S3 LoggingMetricPublisher Demo</name>
    <description>Demonstrates how to use LoggingMetricPublisher with AWS S3 SDK for Java 2.x</description>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <aws.java.sdk.version>2.31.66</aws.java.sdk.version>
        <log4j.version>2.24.3</log4j.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- AWS SDK BOM for dependency management -->
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>${aws.java.sdk.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- Log4j BOM for logging dependency management -->
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-bom</artifactId>
                <version>${log4j.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- AWS S3 SDK for demonstration -->
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
        </dependency>

        <!-- Log4j2 SLF4J implementation -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
        </dependency>

        <!-- Log4j2 Core -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```

`Log4j2.xml` configuration file

```
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="ConsoleAppender" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="ConsoleAppender"/>
        </Root>
        <!-- Ensure LoggingMetricPublisher output appears. -->
        <Logger name="software.amazon.awssdk.metrics.LoggingMetricPublisher" level="INFO"/>
    </Loggers>
</Configuration>
```

The metrics include timing information, service details, operation names, and HTTP status codes that help you understand your application's AWS API usage patterns.

## Next steps
<a name="logging-metric-publisher-next-steps"></a>

After using `LoggingMetricPublisher` for development and debugging, consider these options for production environments:
+ For long-running applications, use [CloudWatchMetricPublisher](metric-pub-impl-cwmp.md) to send metrics to Amazon CloudWatch for analysis and alerting
+ For AWS Lambda functions, use [EmfMetricLoggingPublisher](metric-pub-impl-emf.md) to publish metrics in CloudWatch Embedded Metric Format

# AWS SDK for Java 2.x: Comprehensive Metrics Reference
<a name="metrics-list"></a>

With the AWS SDK for Java 2.x, you can collect metrics from the service clients in your application and then publish (output) those metrics to [Amazon CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html).

These tables list the metrics that you can collect and any HTTP client usage requirement.

For more information about enabling and configuring metrics for the SDK, see [Enabling SDK metrics](metrics.md).

## Metrics collected with each request
<a name="metrics-perrequest"></a>


| Metric name | Description | Type | 
| --- | --- | --- | 
|  ApiCallDuration  |  The duration of the API call. This includes all call attempts made.  |  Duration\$1  | 
|  ApiCallSuccessful  |  True if the API call succeeded, false otherwise.  |  Boolean  | 
|  CredentialsFetchDuration  |  The duration of time to fetch signing credentials for the API call.  |  Duration\$1  | 
| EndpointResolveDuration | The duration of time to resolve the endpoint used for the API call. | Duration\$1 | 
|  MarshallingDuration  |  The duration of time to marshall the SDK request to an HTTP request.  |  Duration\$1  | 
|  OperationName  |  The name of the service operation being invoked.  |  String  | 
|  RetryCount  |  The number of retries that the SDK performed in the execution of the request. 0 implies that the request worked the first time and that no retries were attempted. For more information about configuring retry behavior, see [Retry strategies](retry-strategy.md#retry-strategies).  |  Integer  | 
|  ServiceId  |  The unique ID for the service.  |  String  | 
|  ServiceEndpoint  |  The endpoint for the service.  |  URI  | 
|  TokenFetchDuration  | The duration of time to fetch signing credentials for the API call. | Duration\$1 | 

\$1[java.time.Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html).

## Metrics collected for each request attempt
<a name="metrics-perattempt"></a>

Each API call might require multiple attempts before a response is received. These metrics are collected for each attempt.

### Core metrics
<a name="metrics-perattempt-core"></a>


| Metric name | Description | Type | 
| --- | --- | --- | 
|  AwsExtendedRequestId  |  The extended request ID of the service request.  |  String  | 
|  AwsRequestId  |  The request ID of the service request.  |  String  | 
|  BackoffDelayDuration  |  The duration of time that the SDK has waited before this API call attempt. The value is based on the `[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/retries/api/BackoffStrategy.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/retries/api/BackoffStrategy.html)` set on the client. See the [Retry strategies](retry-strategy.md#retry-strategies) section in this guide for more information.  |  Duration\$1  | 
| ErrorType |  The type of error that occurred for a call attempt. The following are possible values: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/metrics-list.html)  | String | 
| ReadThroughput |  The read throughput of the client, defined as `NumberOfResponseBytesRead / (TTLB - TTFB)`. This value is in bytes per second. Note that this metric only measures the bytes read from within the `ResponseTransformer` or `AsyncResponseTransformer`. Data that is read outside the transformer—for example when the response stream is returned as the result of the transformer—is not included in the calculation.  | Double | 
| WriteThroughput |  The write throughput of the client, defined as `RequestBytesWritten / (LastByteWrittenTime - FirstByteWrittenTime)`. This value is in bytes per second. This metric measures the rate at which the SDK provides the request body to the HTTP client. It excludes connection setup, TLS handshake time, and server processing time. This metric is only reported for requests that have a streaming body such as S3 PutObject. Note that this metric does not account for buffering in the HTTP client layer. The actual network transmission rate may be lower if the HTTP client buffers data before sending. This metric represents an upper bound of the network throughput.  | Double | 
|  ServiceCallDuration  |  The duration of time to connect to the service (or acquire a connection from the connection pool), send the serialized request and receive the initial response (for example HTTP status code and headers). This DOES NOT include the time to read the entire response from the service.  |  Duration\$1  | 
|  SigningDuration  |  The duration of time to sign the HTTP request.  |  Duration\$1  | 
| TimeToFirstByte | The duration of time from sending the HTTP request (including acquiring a connection) to the service, and receiving the first byte of the headers in the response. | Duration\$1 | 
| TimeToLastByte |  The duration of time from sending the HTTP request (including acquiring a connection) to the service, and receiving the last byte of the response. Note that for APIs that return streaming responses, this metric spans the time until the `ResponseTransformer` or `AsyncResponseTransformer` completes.  | Duration\$1 | 
|  UnmarshallingDuration  |  The duration of time to unmarshall the HTTP response to an SDK response. Note: For streaming operations, this does not include the time to read the response payload.  |  Duration\$1  | 

\$1[java.time.Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html).

### HTTP Metrics
<a name="metrics-perattempt-http"></a>


| Metric name | Description | Type | HTTP client required\$1 | 
| --- | --- | --- | --- | 
|  AvailableConcurrency  |  The number of additional concurrent requests that the HTTP client supports without establishing new connections to the target server. For HTTP/1 operations, this equals the number of idle TCP connections established with the service. For HTTP/2 operations, this equals the number of idle streams. Note: This value varies by HTTP client implementation: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/metrics-list.html) The value is scoped to an individual HTTP client instance and excludes concurrency from other HTTP clients in the same JVM.  |  Integer  | Apache, Netty, CRT | 
|  ConcurrencyAcquireDuration  |  The duration of time to acquire a channel from the connection pool. For HTTP/1 operations, a channel equals a TCP connection. For HTTP/2 operations, a channel equals an HTTP/2 stream channel. Acquiring a new channel may include time for: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/metrics-list.html)  |  Duration\$1  |  Apache, Netty, CRT  | 
|  HttpClientName  |  The name of the HTTP used for the request.  |  String  |  Apache, Netty, CRT  | 
|  HttpStatusCode  |  The status code of the HTTP response.  |  Integer  |  Any  | 
|  LeasedConcurrency  |  The number of requests that the HTTP client currently executes.  For HTTP/1 operations, this equals the number of active TCP connections with the service (excluding idle connections). For HTTP/2 operations, this equals the number of active HTTP streams with the service (excluding idle stream capacity).  Note: This value varies by HTTP client implementation: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/metrics-list.html) The value is scoped to an individual HTTP client instance and excludes concurrency from other HTTP clients in the same JVM.  |  Integer  |  Apache, Netty, CRT  | 
|  LocalStreamWindowSize  |  The local HTTP/2 window size in bytes for the stream that executes this request.  |  Integer  |  Netty  | 
|  MaxConcurrency  |  The maximum number of concurrent requests that the HTTP client supports. For HTTP/1 operations, this equals the maximum number of TCP connections that the HTTP client can pool. For HTTP/2 operations, this equals the maximum number of streams that the HTTP client can pool. Note: This value varies by HTTP client implementation: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/metrics-list.html) The value is scoped to an individual HTTP client instance and excludes concurrency from other HTTP clients in the same JVM.  |  Integer  |  Apache, Netty, CRT  | 
|  PendingConcurrencyAcquires  |  The number of requests that wait for concurrency from the HTTP client. For HTTP/1 operations, this equals the number of requests waiting for a TCP connection to establish or return from the connection pool. For HTTP/2 operations, this equals the number of requests waiting for a new stream (and possibly a new HTTP/2 connection) from the connection pool. Note: This value varies by HTTP client implementation: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/metrics-list.html) The value is scoped to an individual HTTP client instance and excludes concurrency from other HTTP clients in the same JVM.  |  Integer  |  Apache, Netty, CRT  | 
|  RemoteStreamWindowSize  |  The remote HTTP/2 window size in bytes for the stream that executes this request.  |  Integer  |  Netty  | 

\$1[java.time.Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html).

The terms used in the column mean:
+ Apache: the Apache-based HTTP client (`[ApacheHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache/ApacheHttpClient.html)`)
+ Netty: the Netty-based HTTP client (`[NettyNioAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.html)`)
+ CRT: the AWS CRT-based HTTP client (`[AwsCrtAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtAsyncHttpClient.html)`)
+ Any: the collection of metric data does not depend on the HTTP client; this includes the URLConnection-based HTTP client (`[UrlConnectionHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.html)`)

# Monitoring AWS SDK for Java 2.x applications
<a name="monitoring-overview"></a>

Monitoring is an important part of maintaining the reliability, availability, and performance of applications using the AWS SDK for Java 2.x. AWS provides the following monitoring tools to watch SDK for Java 2.x, report when something is wrong, and take automatic actions when appropriate:
+ *Amazon CloudWatch* monitors your AWS resources and and the applications you run on AWS in real time. You can collect and track metrics, create customized dashboards, and set alarms that notify you or take actions when a specified metric reaches a threshold that you specify. For example, you can have CloudWatch track CPU usage or other metrics of your Amazon EC2 instances and automatically launch new instances when needed. For more information, see the [Amazon CloudWatch User Guide](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/).
+ *Amazon CloudWatch Logs* enables you to monitor, store, and access your log files from Amazon EC2 instances, CloudTrail, and other sources. CloudWatch Logs can monitor information in the log files and notify you when certain thresholds are met. You can also archive your log data in highly durable storage. For more information, see the [Amazon CloudWatch Logs User Guide](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/).
+ *AWS CloudTrail* captures API calls and related events made by or on behalf of your AWS account and delivers the log files to an Amazon S3 bucket that you specify. You can identify which users and accounts called AWS, the source IP address from which the calls were made, and when the calls occurred. For more information, see the [AWS CloudTrail User Guide](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/).

# Logging with the SDK for Java 2.x
<a name="logging-slf4j"></a>

The AWS SDK for Java 2.x uses [SLF4J](https://www.slf4j.org/manual.html), which is an abstraction layer that enables the use of any one of several logging systems at runtime.

Supported logging systems include the Java Logging Framework and Apache[ Log4j 2](https://logging.apache.org/log4j/2.x/), among others. This topic shows you how to use Log4j 2 as the logging system for working with the SDK.

## Log4j 2 configuration file
<a name="log4j-configuration-file"></a>

You typically use a configuration file, named`log4j2.xml` with Log4j 2. Example configuration files are shown below. To learn more about the values used in the configuration file, see the [manual for Log4j configuration](https://logging.apache.org/log4j/2.x/manual/configuration.html).

The `log4j2.xml` file needs to be on the classpath when your application starts up. For a Maven project, put the file in the `<project-dir>/src/main/resources` directory.

The `log4j2.xml` configuration file specifies properties such as [logging level](https://logging.apache.org/log4j/2.x/manual/configuration.html#Loggers), where logging output is sent (for example, [to a file or to the console](https://logging.apache.org/log4j/2.x/manual/appenders.html)), and the [format of the output](https://logging.apache.org/log4j/2.x/manual/layouts.html). The logging level specifies the level of detail that Log4j 2 outputs. Log4j 2 supports the concept of multiple logging [https://logging.apache.org/log4j/2.x/manual/architecture.html#](https://logging.apache.org/log4j/2.x/manual/architecture.html#). The logging level is set independently for each hierarchy. The main logging hierarchy that you use with the AWS SDK for Java 2.x is `software.amazon.awssdk`.

## Add logging dependency
<a name="sdk-java-logging-classpath"></a>

To configure the Log4j 2 binding for SLF4J in your build file, use the following.

------
#### [ Maven ]

Add the following elements to your `pom.xml` file.

```
...
<dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-slf4j2-impl</artifactId>
   <version>VERSION</version>
</dependency>
...
```

------
#### [ Gradle–Kotlin DSL ]

Add the following to your `build.gradle.kts` file.

```
...
dependencies {
    ...
    implementation("org.apache.logging.log4j:log4j-slf4j2-impl:VERSION")
    ...
}
...
```

------

Use `2.20.0` for the minimum version of the `log4j-slf4j2-impl` artifact. For the latest version, use the version published to [Maven central](https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-slf4j2-impl). Replace *VERSION* with version you'll use.

## SDK-specific errors and warnings
<a name="sdk-java-logging-service"></a>

We recommend that you always leave the "software.amazon.awssdk" logger hierarchy set to "WARN" to catch any important messages from the SDK's client libraries. For example, if the Amazon S3 client detects that your application hasn’t properly closed an `InputStream` and could be leaking resources, the S3 client reports it through a warning message to the logs. This also ensures that messages are logged if the client has any problems handling requests or responses.

The following `log4j2.xml` file sets the `rootLogger` to "WARN", which causes warning and error-level messages from all loggers in the application to be output, *including* those in the "software.amazon.awssdk" hierarchy. Alternatively, you can explicitly set the "software.amazon.awssdk" logger hierarchy to "WARN" if `<Root level="ERROR">` is used.

**Example Log4j2.xml configuration file**

This configuration will log messages at the "ERROR" and "WARN" levels to the console for all logger hierarchies.

```
<Configuration status="WARN">
 <Appenders>
  <Console name="ConsoleAppender" target="SYSTEM_OUT">
   <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c:%L - %m%n" />
  </Console>
 </Appenders>

 <Loggers>
  <Root level="WARN">
   <AppenderRef ref="ConsoleAppender"/>
  </Root>
 </Loggers>
</Configuration>
```

## Request/response summary logging
<a name="sdk-java-logging-request-response"></a>

Every request to an AWS service generates a unique AWS request ID that is useful if you run into an issue with how an AWS service is handling a request. AWS request IDs are accessible programmatically through [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/exception/SdkServiceException.html#requestId()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/exception/SdkServiceException.html#requestId()) objects in the SDK for any failed service call, and can also be reported through the "DEBUG" log level of the "software.amazon.awssdk.request" logger.

The following `log4j2.xml` file enables a summary of requests and responses.

```
<Configuration status="WARN">
 <Appenders>
  <Console name="ConsoleAppender" target="SYSTEM_OUT">
   <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c:%L - %m%n" />
  </Console>
 </Appenders>

 <Loggers>
  <Root level="ERROR">
   <AppenderRef ref="ConsoleAppender"/>
  </Root>
  <Logger name="software.amazon.awssdk" level="WARN" />
  <Logger name="software.amazon.awssdk.request" level="DEBUG" />
 </Loggers>
</Configuration>
```

Here is an example of the log output:

```
2022-09-23 16:02:08 [main] DEBUG software.amazon.awssdk.request:85 - Sending Request: DefaultSdkHttpFullRequest(httpMethod=POST, protocol=https, host=dynamodb.us-east-1.amazonaws.com, encodedPath=/, headers=[amz-sdk-invocation-id, Content-Length, Content-Type, User-Agent, X-Amz-Target], queryParameters=[])
2022-09-23 16:02:08 [main] DEBUG software.amazon.awssdk.request:85 - Received successful response: 200, Request ID: QS9DUMME2NHEDH8TGT9N5V53OJVV4KQNSO5AEMVJF66Q9ASUAAJG, Extended Request ID: not available
```

If you are interested in only the request ID use `<Logger name="software.amazon.awssdk.requestId" level="DEBUG" />`.

## Debug-level SDK logging
<a name="sdk-debug-level-logging"></a>

If you need more detail about what the SDK is doing, you can set the logging level of the `software.amazon.awssdk` logger to `DEBUG`. At this level, the SDK outputs a large amount of detail, so we recommend that you set this level to resolve errors using integration tests. 

At this logging level, the SDK logs information about configuration, credentials resolution, execution interceptors, high-level TLS activity, request signing, and much more.

The following is a sampling of statements that are output by the SDK at `DEBUG` level for a `S3Client#listBuckets()` call.

```
DEBUG s.a.a.r.p.AwsRegionProviderChain:57 - Unable to load region from software.amazon.awssdk.regions.providers.SystemSettingsRegionProvider@324dcd31:Unable to load region from system settings. Region must be specified either via environment variable (AWS_REGION) or  system property (aws.region).
DEBUG s.a.a.c.i.h.l.ClasspathSdkHttpServiceProvider:85 - The HTTP implementation loaded is software.amazon.awssdk.http.apache.ApacheSdkHttpService@a23a01d
DEBUG s.a.a.c.i.ExecutionInterceptorChain:85 - Creating an interceptor chain that will apply interceptors in the following order: [software.amazon.awssdk.core.internal.interceptor.HttpChecksumValidationInterceptor@69b2f8e5, software.amazon.awssdk.awscore.interceptor.HelpfulUnknownHostExceptionInterceptor@6331250e, software.amazon.awssdk.awscore.eventstream.EventStreamInitialRequestInterceptor@a10c1b5, software.amazon.awssdk.awscore.interceptor.TraceIdExecutionInterceptor@644abb8f, software.amazon.awssdk.services.s3.auth.scheme.internal.S3AuthSchemeInterceptor@1a411233, software.amazon.awssdk.services.s3.endpoints.internal.S3ResolveEndpointInterceptor@70325d20, software.amazon.awssdk.services.s3.endpoints.internal.S3RequestSetEndpointInterceptor@7c2327fa, software.amazon.awssdk.services.s3.internal.handlers.StreamingRequestInterceptor@4d847d32, software.amazon.awssdk.services.s3.internal.handlers.CreateBucketInterceptor@5f462e3b, software.amazon.awssdk.services.s3.internal.handlers.CreateMultipartUploadRequestInterceptor@3d7fa3ae, software.amazon.awssdk.services.s3.internal.handlers.DecodeUrlEncodedResponseInterceptor@58065f0c, software.amazon.awssdk.services.s3.internal.handlers.GetBucketPolicyInterceptor@3605c4d3, software.amazon.awssdk.services.s3.internal.handlers.S3ExpressChecksumInterceptor@585c13de, software.amazon.awssdk.services.s3.internal.handlers.AsyncChecksumValidationInterceptor@187eb9a8, software.amazon.awssdk.services.s3.internal.handlers.SyncChecksumValidationInterceptor@726a6b94, software.amazon.awssdk.services.s3.internal.handlers.EnableTrailingChecksumInterceptor@6ad11a56, software.amazon.awssdk.services.s3.internal.handlers.ExceptionTranslationInterceptor@522b2631, software.amazon.awssdk.services.s3.internal.handlers.GetObjectInterceptor@3ff57625, software.amazon.awssdk.services.s3.internal.handlers.CopySourceInterceptor@1ee29c84, software.amazon.awssdk.services.s3.internal.handlers.ObjectMetadataInterceptor@7c8326a4]
DEBUG s.a.a.u.c.CachedSupplier:85 - (SsoOidcTokenProvider()) Cached value is stale and will be refreshed.
...
DEBUG s.a.a.c.i.ExecutionInterceptorChain:85 - Creating an interceptor chain that will apply interceptors in the following order: [software.amazon.awssdk.core.internal.interceptor.HttpChecksumValidationInterceptor@51351f28, software.amazon.awssdk.awscore.interceptor.HelpfulUnknownHostExceptionInterceptor@21618fa7, software.amazon.awssdk.awscore.eventstream.EventStreamInitialRequestInterceptor@15f2eda3, software.amazon.awssdk.awscore.interceptor.TraceIdExecutionInterceptor@34cf294c, software.amazon.awssdk.services.sso.auth.scheme.internal.SsoAuthSchemeInterceptor@4d7aaca2, software.amazon.awssdk.services.sso.endpoints.internal.SsoResolveEndpointInterceptor@604b1e1d, software.amazon.awssdk.services.sso.endpoints.internal.SsoRequestSetEndpointInterceptor@62566842]
...
DEBUG s.a.a.request:85 - Sending Request: DefaultSdkHttpFullRequest(httpMethod=GET, protocol=https, host=portal.sso.us-east-1.amazonaws.com, encodedPath=/federation/credentials, headers=[amz-sdk-invocation-id, User-Agent, x-amz-sso_bearer_token], queryParameters=[role_name, account_id])
DEBUG s.a.a.c.i.h.p.s.SigningStage:85 - Using SelectedAuthScheme: smithy.api#noAuth
DEBUG s.a.a.h.a.i.c.SdkTlsSocketFactory:366 - Connecting socket to portal.sso.us-east-1.amazonaws.com/18.235.195.183:443 with timeout 2000
...
DEBUG s.a.a.requestId:85 - Received successful response: 200, Request ID: bb4f40f4-e920-4b5c-8648-58f26e7e08cd, Extended Request ID: not available
DEBUG s.a.a.request:85 - Received successful response: 200, Request ID: bb4f40f4-e920-4b5c-8648-58f26e7e08cd, Extended Request ID: not available
DEBUG s.a.a.u.c.CachedSupplier:85 - (software.amazon.awssdk.services.sso.auth.SsoCredentialsProvider@b965857) Successfully refreshed cached value. Next Prefetch Time: 2024-04-25T22:03:10.097Z. Next Stale Time: 2024-04-25T22:05:30Z
DEBUG s.a.a.c.i.ExecutionInterceptorChain:85 - Interceptor 'software.amazon.awssdk.services.s3.endpoints.internal.S3RequestSetEndpointInterceptor@7c2327fa' modified the message with its modifyHttpRequest method.
...
DEBUG s.a.a.c.i.h.p.s.SigningStage:85 - Using SelectedAuthScheme: aws.auth#sigv4
...
DEBUG s.a.a.a.s.Aws4Signer:85 - AWS4 Canonical Request: GET
...
DEBUG s.a.a.h.a.a.i.s.DefaultV4RequestSigner:85 - AWS4 String to sign: AWS4-HMAC-SHA256
20240425T210631Z
20240425/us-east-1/s3/aws4_request
aafb7784627fa7a49584256cb746279751c48c2076f813259ef767ecce304d64
DEBUG s.a.a.h.a.i.c.SdkTlsSocketFactory:366 - Connecting socket to s3.us-east-1.amazonaws.com/52.217.41.86:443 with timeout 2000
...
```

The following `log4j2.xml` file configures the previous output.

```
<Configuration status="WARN">
    <Appenders>
        <Console name="ConsoleAppender" target="SYSTEM_OUT">
            <PatternLayout pattern="%-5p %c{1.}:%L - %m%n" />
        </Console>
    </Appenders>

    <Loggers>
        <Root level="WARN">
            <AppenderRef ref="ConsoleAppender"/>
        </Root>
        <Logger name="software.amazon.awssdk" level="DEBUG" />
    </Loggers>
</Configuration>
```

## Enable wire logging
<a name="sdk-java-logging-verbose"></a>

It can be useful to see the exact requests and responses that the SDK for Java 2.x sends and receives. If you need access to this information, you can temporarily enable it by adding the necessary configuration depending on the HTTP client the service client uses.

By default, synchronous service clients, such as the [S3Client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html), use an underlying Apache HttpClient, and asynchronous service clients, such as the [S3AsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html), use a Netty non-blocking HTTP client.

Here is a breakdown of HTTP clients you can use for the two categories of service clients:


| Synchronous HTTP Clients | Asynchronous HTTP Clients | 
| --- | --- | 
| [ApacheHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache/ApacheHttpClient.html) (default) | [NettyNioAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.html) (default) | 
| [UrlConnectionHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.html) | [AwsCrtAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtAsyncHttpClient.html) | 
| [AwsCrtHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtHttpClient.html) |  | 
| [Apache5HttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache5/Apache5HttpClient.html)  | 

Consult the appropriate tab below for configuration settings you need to add depending on the underlying HTTP client.

**Warning**  
We recommend you only use wire logging for debugging purposes. Disable it in your production environments because it can log sensitive data. It logs the full request or response without encryption, even for an HTTPS call. For large requests (e.g., to upload a file to Amazon S3) or responses, verbose wire logging can also significantly impact your application’s performance.

------
#### [ ApacheHttpClient ]

Add the "org.apache.http.wire" logger to the `log4j2.xml` configuration file and set the level to "DEBUG".

The following `log4j2.xml` file turns on full wire logging for the Apache HttpClient.

```
<Configuration status="WARN">
 <Appenders>
  <Console name="ConsoleAppender" target="SYSTEM_OUT">
   <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c:%L - %m%n" />
  </Console>
 </Appenders>

 <Loggers>
  <Root level="WARN">
   <AppenderRef ref="ConsoleAppender"/>
  </Root>
  <Logger name="software.amazon.awssdk" level="WARN" />
  <Logger name="software.amazon.awssdk.request" level="DEBUG" />
  <Logger name="org.apache.http.wire" level="DEBUG" />
 </Loggers>
</Configuration>
```

An additional Maven dependency on the `log4j-1.2-api` artifact is required for wire logging with Apache since it uses 1.2 under the hood. 

The full set of Maven dependencies for log4j 2, including wire logging for the Apache HTTP client are shown in the following build file snippets.

**Maven**

```
...
<dependencyManagement>
    ...
    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-bom</artifactId>
            <version>VERSION</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
     </dependencies>
</dependencyManagement>
...
<!-- The following is needed for Log4j2 with SLF4J -->
<dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-slf4j2-impl</artifactId>
</dependency>

<!-- The following is needed for Apache HttpClient wire logging -->
<dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-1.2-api</artifactId>
</dependency>
...
```

**Gradle–Kotlin DSL**

```
...
dependencies {
    ...
    implementation(platform("org.apache.logging.log4j:log4j-bom:VERSION"))
    implementation("org.apache.logging.log4j:log4j-slf4j2-impl")
    implementation("org.apache.logging.log4j:log4j-1.2-api")
}
...
```

Use `2.20.0` for the minimum version of the `log4j-bom` artifact. For the latest version, use the version published to [Maven central](https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-bom). Replace *VERSION* with version you'll use.

------
#### [ Apache5HttpClient ]

Add the "org.apache.hc.client5.http.wire" logger to the `log4j2.xml` configuration file and set the level to "DEBUG".

The following `log4j2.xml` file turns on full wire logging for the Apache5 HttpClient.

```
<Configuration status="WARN">
 <Appenders>
  <Console name="ConsoleAppender" target="SYSTEM_OUT">
   <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c:%L - %m%n" />
  </Console>
 </Appenders>

 <Loggers>
  <Root level="WARN">
   <AppenderRef ref="ConsoleAppender"/>
  </Root>
  <Logger name="software.amazon.awssdk" level="WARN" />
  <Logger name="software.amazon.awssdk.request" level="DEBUG" />
  <Logger name="org.apache.hc.client5.http.wire" level="DEBUG" />
 </Loggers>
</Configuration>
```

------
#### [ UrlConnectionHttpClient ]

To log details for service clients that use the `UrlConnectionHttpClient`, first create a `logging.properties` file with the following contents:

```
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=FINEST
sun.net.www.protocol.http.HttpURLConnection.level=ALL
```

Set the following JVM system property with the full path of the `logging.properties`:

```
-Djava.util.logging.config.file=/full/path/to/logging.properties
```

This configuration will log the only the headers of the request and response, for example:

```
<Request>  FINE: sun.net.www.MessageHeader@35a9782c11 pairs: {GET /fileuploadtest HTTP/1.1: null}{amz-sdk-invocation-id: 5f7e707e-4ac5-bef5-ba62-00d71034ffdc}{amz-sdk-request: attempt=1; max=4}{Authorization: AWS4-HMAC-SHA256 Credential=<deleted>/20220927/us-east-1/s3/aws4_request, SignedHeaders=amz-sdk-invocation-id;amz-sdk-request;host;x-amz-content-sha256;x-amz-date;x-amz-te, Signature=e367fa0bc217a6a65675bb743e1280cf12fbe8d566196a816d948fdf0b42ca1a}{User-Agent: aws-sdk-java/2.17.230 Mac_OS_X/12.5 OpenJDK_64-Bit_Server_VM/25.332-b08 Java/1.8.0_332 vendor/Amazon.com_Inc. io/sync http/UrlConnection cfg/retry-mode/legacy}{x-amz-content-sha256: UNSIGNED-PAYLOAD}{X-Amz-Date: 20220927T133955Z}{x-amz-te: append-md5}{Host: tkhill-test1.s3.amazonaws.com}{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}{Connection: keep-alive}
<Response> FINE: sun.net.www.MessageHeader@70a36a6611 pairs: {null: HTTP/1.1 200 OK}{x-amz-id-2: sAFeZDOKdUMsBbkdjyDZw7P0oocb4C9KbiuzfJ6TWKQsGXHM/dFuOvr2tUb7Y1wEHGdJ3DSIxq0=}{x-amz-request-id: P9QW9SMZ97FKZ9X7}{Date: Tue, 27 Sep 2022 13:39:57 GMT}{Last-Modified: Tue, 13 Sep 2022 14:38:12 GMT}{ETag: "2cbe5ad4a064cedec33b452bebf48032"}{x-amz-transfer-encoding: append-md5}{Accept-Ranges: bytes}{Content-Type: text/plain}{Server: AmazonS3}{Content-Length: 67}
```

To see the request/response bodies, add `-Djavax.net.debug=all` to the JVM properties. This additional property logs a great deal of information, including all SSL information. 

Within the log console or log file, search for `"GET"` or `"POST"` to quickly go to the section of the log containing actual requests and responses. Search for `"Plaintext before ENCRYPTION"` for requests and `"Plaintext after DECRYPTION"` for responses to see the full text of the headers and bodies.

------
#### [ NettyNioAsyncHttpClient ]

If your asynchronous service client uses the default `NettyNioAsyncHttpClient`, add two additional loggers to your `log4j2.xml` file to log HTTP headers and request/response bodies.

```
<Logger name="io.netty.handler.logging" level="DEBUG" />
<Logger name="io.netty.handler.codec.http2.Http2FrameLogger" level="DEBUG" />
```

Here is a complete `log4j2.xml` example:

```
<Configuration status="WARN">
    <Appenders>
        <Console name="ConsoleAppender" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c:%L - %m%n" />
        </Console>
    </Appenders>

    <Loggers>
        <Root level="WARN">
            <AppenderRef ref="ConsoleAppender"/>
        </Root>
        <Logger name="software.amazon.awssdk" level="WARN" />
        <Logger name="software.amazon.awssdk.request" level="DEBUG" />
        <Logger name="io.netty.handler.logging" level="DEBUG" />
        <Logger name="io.netty.handler.codec.http2.Http2FrameLogger" level="DEBUG" />
    </Loggers>
</Configuration>
```

These settings log all header details and request/response bodies.

------
#### [ AwsCrtAsyncHttpClient/AwsCrtHttpClient ]

If you have configured your service client to use an instance of an AWS CRT-based HTTP client, you can log details by setting JVM system properties or programmatically.


|  | 
| --- |
|  Log to a file at "Debug" level  | 
|  Using system properties: <pre>-Daws.crt.log.level=Trace <br />-Daws.crt.log.destination=File <br />-Daws.crt.log.filename=<path to file></pre>  |  Programmatically: <pre>import software.amazon.awssdk.crt.Log;<br /><br />// Execute this statement before constructing the SDK service client.<br />Log.initLoggingToFile(Log.LogLevel.Trace, "<path to file>");</pre>  | 
|  Log to the console at "Debug" level  | 
|  Using system properties: <pre>-Daws.crt.log.level=Trace <br />-Daws.crt.log.destination=Stdout</pre>  |  Programmatically: <pre>import software.amazon.awssdk.crt.Log;<br /><br />// Execute this statement before constructing the SDK service client.<br />Log.initLoggingToStdout(Log.LogLevel.Trace);</pre>  | 

For security reasons, at the "Trace" level the AWS CRT-based HTTP clients log only response headers. Request headers, request bodies, and response bodies are not logged.

------

# Configuring client endpoints in the AWS SDK for Java 2.x
<a name="endpoint-config"></a>

The SDK for Java 2.x provides multiple ways to configure service endpoints. An endpoint is the URL that the SDK uses to make API calls to AWS services. By default, the SDK automatically determines the appropriate endpoint for each service based on the AWS Region you've configured. However, there are scenarios where you might need to customize or override these endpoints: 
+ Working with local or third-party service implementations (such as LocalStack)
+ Connecting to AWS services through a proxy or VPC endpoint
+ Testing against beta or pre-release service endpoints

## Endpoint configuration options
<a name="endpoint-configuration-options"></a>

 The AWS SDK for Java 2.x provides several ways to configure endpoints: 
+ In-code configuration by using the service client builder
+ External configuration with environment variables
+ External configuration with JVM system properties
+ External configuration with shared AWS config file

## In-code endpoint configuration
<a name="in-code-endpoint-configuration"></a>

### Using `endpointOverride`
<a name="endpoint-override"></a>

 The most direct way to configure an endpoint is by using the `endpointOverride` method on the service client builder. This method accepts a `URI` object representing the custom endpoint URL. 

**Example Setting a custom endpoint for an Amazon S3 client**  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import java.net.URI;

S3Client s3 = S3Client.builder()
        .region(Region.US_WEST_2)
        .endpointOverride(URI.create("https://my-custom-s3-endpoint.example.com"))
        .build();
```

When using `endpointOverride`, you must still specify a region for the client, even though the endpoint is being explicitly set. The region is used for signing requests. 

### Endpoint discovery
<a name="endpoint-discovery"></a>

Some AWS services support endpoint discovery, where the SDK can automatically discover the optimal endpoint to use. You can enable or disable this feature using the `endpointDiscoveryEnabled` method on the service client builder. 

**Example Enabling endpoint discovery for a DynamoDB client**  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;

DynamoDbClient dynamoDb = DynamoDbClient.builder()
        .region(Region.US_WEST_2)
        .endpointDiscoveryEnabled(true)
        .build();
```

## Request-level endpoint configuration
<a name="request-level-endpoint-configuration"></a>

In some cases, you might need to override the endpoint for a specific request while using the same client for other requests with the default endpoint. The AWS SDK for Java 2.x supports this through request overrides. 

**Example Overriding the endpoint for a specific request**  

```
import software.amazon.awssdk.core.SdkRequest;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.http.SdkHttpRequest;

S3Client s3 = S3Client.builder()
        .region(Region.US_WEST_2)
        .build();

// Create a request
GetObjectRequest getObjectRequest = GetObjectRequest.builder()
        .bucket("amzn-s3-demo-bucket")
        .key("my-key")
        .overrideConfiguration(c -> c.putHeader("Host", "custom-endpoint.example.com"))
        .build();

// Execute the request with the custom endpoint
s3.getObject(getObjectRequest);
```

Note that request-level endpoint overrides are limited and may not work for all services or scenarios. For most cases, it's recommended to use client-level endpoint configuration. 

## External endpoint configuration
<a name="external-endpoint-configuration"></a>

### Using environment variables
<a name="environment-variables-for-endpoints"></a>

You can configure endpoints using environment variables. The SDK supports service-specific endpoint configuration through environment variables in the format `AWS_ENDPOINT_URL_[SERVICE]`, where `[SERVICE]` is the uppercase service identifier. 

**Example Setting an S3 endpoint using environment variables**  

```
# For Linux/macOS
export AWS_ENDPOINT_URL_S3=https://my-custom-s3-endpoint.example.com

# For Windows
set AWS_ENDPOINT_URL_S3=https://my-custom-s3-endpoint.example.com
```

 You can also set a global endpoint URL prefix or suffix using the following environment variables: 
+ `AWS_ENDPOINT_URL` - Sets a global endpoint for all services
+ `AWS_ENDPOINT_URL_PREFIX` - Adds a prefix to all service endpoints
+ `AWS_ENDPOINT_URL_SUFFIX` - Adds a suffix to all service endpoints

### Using JVM system properties
<a name="jvm-system-properties-for-endpoints"></a>

 You can also configure endpoints using JVM system properties. The format is similar to environment variables but uses a different naming convention. 

**Example Setting an S3 endpoint using JVM system properties**  

```
java -Daws.endpointUrl.s3=https://my-custom-s3-endpoint.example.com -jar your-application.jar
```

 Global endpoint configuration is also available through system properties: 
+ `aws.endpointUrl` - Sets a global endpoint for all services
+ `aws.endpointUrl.prefix` - Adds a prefix to all service endpoints
+ `aws.endpointUrl.suffix` - Adds a suffix to all service endpoints

### Using the shared AWS config file
<a name="aws-config-file-for-endpoints"></a>

 The AWS SDK for Java 2.x also supports endpoint configuration through the shared AWS config file, typically located at `~/.aws/config` (Linux/macOS) or `%USERPROFILE%\.aws\config` (Windows). See the [AWS SDKs and Tools Reference Guide](https://docs.aws.amazon.com/sdkref/latest/guide/feature-ss-endpoints.html#ss-endpoints-config) for information and examples.

## Configuration precedence
<a name="endpoint-configuration-precedence"></a>

 When multiple endpoint configurations are present, the SDK follows this order of precedence (from highest to lowest): 

1. Request-level overrides (when applicable)

1. Client-level configuration via `endpointOverride`

1. Environment variables

1. JVM system properties

1. Shared AWS config file

1. Default endpoints based on the configured AWS Region

## Service-specific endpoint configuration
<a name="service-specific-endpoint-configuration"></a>

 Some AWS services have additional endpoint configuration options specific to that service. Here are a few examples: 

### Amazon S3 Endpoint Configuration
<a name="s3-endpoint-configuration"></a>

 Amazon S3 supports several endpoint configurations through the `S3Configuration` class: 
+ `dualstackEnabled` - Enables IPv6 support
+ `accelerateModeEnabled` - Enables S3 Transfer Acceleration
+ `pathStyleAccessEnabled` - Uses path-style access instead of virtual-hosted style
+ `useArnRegionEnabled` - Uses the region from an ARN for cross-region requests
+ `fipsModeEnabled` - Routes requests to FIPS-compliant endpoints

**Example Configuring S3-specific endpoint options**  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3Configuration;

S3Client s3 = S3Client.builder()
        .region(Region.US_WEST_2)
        .serviceConfiguration(S3Configuration.builder()
                .accelerateModeEnabled(true)
                .dualstackEnabled(true)
                .pathStyleAccessEnabled(false)
                .fipsModeEnabled(true)
                .build())
        .build();
```

### DynamoDB endpoint configuration
<a name="dynamodb-endpoint-configuration"></a>

 For DynamoDB, you might want to use endpoint discovery or connect to [DynamoDB local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html) for testing: 

**Example Connecting to DynamoDB local**  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import java.net.URI;

DynamoDbClient dynamoDb = DynamoDbClient.builder()
        .endpointOverride(URI.create("http://localhost:8000"))
        // The region is meaningless for DynamoDB local but required for the client builder.
        .region(Region.US_WEST_2)
        .build();
```

DynamoDB also supports the use of [account-based endpoints](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html), which you can configure in code or using external settings. The following example shows how to disable the use of account-based endpoints in code when you create the client (the default settings is *preferred*):

```
DynamoDbClient dynamoDbClient = DynamoDbClient.builder()
    .region(Region.US_EAST_1)
    .accountIdEndpointMode(AccountIdEndpointMode.DISABLED)
    .build();
```

## Best practices
<a name="endpoint-configuration-best-practices"></a>

 When configuring endpoints in the AWS SDK for Java 2.x, consider these best practices: 
+  *Use external configuration for environment-specific endpoints*—Use environment variables, system properties, or the AWS config file for endpoints that vary between environments (development, testing, production). 
+  *Use in-code configuration for application-specific endpoints*— Use the client builder's `endpointOverride` method for endpoints that are specific to your application's design. 
+  *Always specify a region*—Even when overriding endpoints, always specify a region as it's used for request signing. 
+  *Be cautious with global endpoint overrides*—Using global endpoint overrides can affect all services, which might not be what you intend. 
+  *Consider security implications*—When using custom endpoints, ensure they have appropriate security measures, especially for production workloads. 

# Configure HTTP clients in the AWS SDK for Java 2.x
<a name="http-configuration"></a>

You can change the HTTP client to use for your service client as well as change the default configuration for HTTP clients with the AWS SDK for Java 2.x. This section discusses HTTP clients and settings for the SDK.

## HTTP clients available in the SDK for Java
<a name="http-clients-available"></a>

### Synchronous clients
<a name="http-config-sync"></a>

Synchronous HTTP clients in the SDK for Java implement the [SdkHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/SdkHttpClient.html) interface. A synchronous service client, such as the `S3Client` or the `DynamoDbClient`, requires the use of a synchronous HTTP client. The AWS SDK for Java offers three synchronous HTTP clients.

**ApacheHttpClient (default)**  
[ApacheHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache/ApacheHttpClient.html) is the default HTTP client for synchronous service clients. For information about configuring the `ApacheHttpClient`, see [Configure the Apache-based HTTP client](http-configuration-apache.md). 

**AwsCrtHttpClient**  
[AwsCrtHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtHttpClient.html) provides high throughput and non-blocking IO. It is built on the AWS Common Runtime (CRT) Http Client. For information about configuring the `AwsCrtHttpClient` and using it with service clients, see [Configure AWS CRT-based HTTP clients](http-configuration-crt.md).

**UrlConnectionHttpClient**  
To minimize the number of jars and third-party libraries you application uses, you can use the [UrlConnectionHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.html). For information about configuring the `UrlConnectionHttpClient`, see [Configure the URLConnection-based HTTP client](http-configuration-url.md).

**Apache5HttpClient**  
[Apache5HttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache5/Apache5HttpClient.html) is an updated version of `ApacheHttpClient` that is built on the *Apache 5.x HttpClient. Version 5.x * is the version actively maintained by Apache, and improves on the the previous version used by `ApacheHttpClient` by bringing modern Java ecosystem compatibility including virtual thread support for Java 21, and enhanced logging flexibility through SLF4J. `Apache5HttpClient` will replace `ApacheHttpClient` as the default synchronous client in a future version of the AWS SDK for Java 2.x. It has an identical API and features, making it ideal as a drop-in replacement. For information about configuring the `Apache5HttpClient`, see [Configure the Apache 5.x based HTTP client](http-configuration-apache5.md).

### Asynchronous clients
<a name="http-config-async"></a>

Asynchronous HTTP clients in the SDK for Java implement the [SdkAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/async/SdkAsyncHttpClient.html) interface. An asynchronous service client, such as the `S3AsyncClient` or the `DynamoDbAsyncClient`, requires the use of an asynchronous HTTP client. The AWS SDK for Java offers two asynchronous HTTP clients.

**NettyNioAsyncHttpClient (default)**  
[NettyNioAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.html) is the default HTTP client used by asynchronous clients. For information about configuring the `NettyNioAsyncHttpClient`, see [Configure the Netty-based HTTP client](http-configuration-netty.md).

**AwsCrtAsyncHttpClient**  
The [AwsCrtAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtAsyncHttpClient.html) is based on the AWS Common Runtime (CRT) HTTP Client. For information about configuring the `AwsCrtAsyncHttpClient`, see [Configure AWS CRT-based HTTP clients](http-configuration-crt.md). 

## HTTP client recommendations
<a name="http-clients-recommend"></a>

Several factors come into play when you choose an HTTP client implementation. Use the following information to help you decide.

### HTTP client comparison
<a name="http-clients-recommend-compare"></a>

The following table provides detailed information for each HTTP client. 


| HTTP client | Sync or async | When to use | Limitation/drawback | 
| --- | --- | --- | --- | 
|  Apache-based HTTP client *(default sync HTTP client)*  | Sync | Use it if you prefer low latency over high throughput  | Slower startup time compared to other HTTP clients | 
| URLConnection-based HTTP client | Sync | Use it if you have a hard requirement for limiting third-party dependencies | Does not support the HTTP PATCH method, required by some APIS like Amazon APIGateway Update operations | 
| AWS CRT-based sync HTTP client1  | Sync |  • Use it if your application is running in AWS Lambda • Use it if you prefer high throughput over low latency • Use it if you prefer sync SDK clients  |  The following Java system properties are not supported: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration.html)  | 
|  Netty-based HTTP client *(default async HTTP client)*  | Async |  • Use it if your application relies on Java system properties for TLS configuration (such as `javax.net.ssl.keyStore`)  | Slower startup time compared to other HTTP clients | 
|  AWS CRT-based async HTTP client1  | Async | • Use it if your application is running in AWS Lambda• Use it if you prefer high throughput over low latency• Use it if you prefer async SDK clients |  The following Java system properties are not supported: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration.html)  | 

1Because of their added benefits, we recommend that you use the AWS CRT-based HTTP clients if possible.

## Smart configuration defaults
<a name="http-config-smart-defaults"></a>

The AWS SDK for Java 2.x (version 2.17.102 or later) offers a smart configuration defaults feature. This feature optimizes two HTTP client properties along with other properties that don't affect the HTTP client. 

The smart configuration defaults set sensible values for the `connectTimeoutInMillis` and `tlsNegotiationTimeoutInMillis` properties based on a defaults mode value that you provide. You choose the defaults mode value based on your application's characteristics. 

For more information about smart configuration defaults and how to choose the defaults mode value that is best suited for your applications, see the [AWS SDKs and Tools Reference Guide](https://docs.aws.amazon.com/sdkref/latest/guide/feature-smart-config-defaults.html).

Following are four ways to set the defaults mode for your application.

------
#### [ Service client ]

Use the service client builder to configure the defaults mode directly on the service client. The following example sets the defaults mode to `auto` for the `DynamoDbClient`.

```
DynamoDbClient ddbClient = DynamoDbClient.builder()
                            .defaultsMode(DefaultsMode.AUTO)
                            .build();
```

------
#### [ System property ]

You can use the `aws.defaultsMode` system property to specify the defaults mode. If you set the system property in Java, you need to set the property before initializing any service client.

The following example shows you how to set the defaults mode to `auto` using a system property set in Java.

```
System.setProperty("aws.defaultsMode", "auto");
```

The following example demonstrates how you set the defaults mode to `auto` using a `-D` option of the `java` command.

```
java -Daws.defaultsMode=auto
```

------
#### [ Environment variable ]

Set a value for environment variable `AWS_DEFAULTS_MODE` to select the defaults mode for your application. 

The following information shows the command to run to set the value for the defaults mode to `auto` using an environment variable.


| Operating system | Command to set environment variables | 
| --- | --- | 
|  Linux, macOS, or Unix  | export AWS\$1DEFAULTS\$1MODE=auto | 
|  Windows  | set AWS\$1DEFAULTS\$1MODE=auto | 

------
#### [ AWS config file ]

You can add a `defaults_mode` configuration property to the shared AWS `config` file as the following example shows.

```
[default]
defaults_mode = auto
```

------

If you set the defaults mode globally with the system property, environment variable, or AWS config file, you can override the settings when you build an HTTP client. 

When you build an HTTP client with the `httpClientBuilder()` method, settings apply only to the instance that you are building. An example of this is shown [here](http-configuration-netty.md#http-config-netty-one-client). The Netty-based HTTP client in this example overrides any default mode values set globally for `connectTimeoutInMillis` and `tlsNegotiationTimeoutInMillis`.

# Configure the Apache-based HTTP client
<a name="http-configuration-apache"></a>

Synchronous service clients in the AWS SDK for Java 2.x use an Apache-based HTTP client, [ApacheHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache/ApacheHttpClient.html) by default. The SDK's `ApacheHttpClient` is based on the Apache [HttpClient](https://hc.apache.org/httpcomponents-client-4.5.x/index.html).

The SDK also offers the [UrlConnectionHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.html), which loads more quickly, but has fewer features. For information about configuring the `UrlConnectionHttpClient`, see [Configure the URLConnection-based HTTP client](http-configuration-url.md). 

To see the full set of configuration options available to you for the `ApacheHttpClient`, see [ApacheHttpClient.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache/ApacheHttpClient.Builder.html) and [ProxyConfiguration.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache/ProxyConfiguration.Builder.html).

## Access the `ApacheHttpClient`
<a name="http-apache-dependency"></a>

In most situations, you use the `ApacheHttpClient` without any explicit configuration. You declare your service clients and the SDK will configure the `ApacheHttpClient` with standard values for you.

If you want to explicitly configure the `ApacheHttpClient` or use it with multiple service clients, you need to make it available for configuration.

### No configuration needed
<a name="http-config-apache-no-config"></a>

When you declare a dependency on a service client in Maven, the SDK adds a *runtime* dependency on the `apache-client` artifact. This makes the `ApacheHttpClient` class available to your code at runtime, but not at compile time. If you are not configuring the Apache-based HTTP client, you do not need to specify a dependency for it.

In the following XML snippet of a Maven `pom.xml` file, the dependency declared with `<artifactId>s3</artifactId>` automatically brings in the Apache-based HTTP client. You don't need to declare a dependency specifically for it.

```
<dependencyManagement>
   <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.27.21</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <!-- The s3 dependency automatically adds a runtime dependency on the ApacheHttpClient-->
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
    </dependency>
</dependencies>
```

With these dependencies, you cannot make any explicit HTTP configuration changes, because the `ApacheHttpClient` library is only on the runtime classpath. 

### Configuration needed
<a name="http-config-apache-yes-config"></a>

To configure the `ApacheHttpClient`, you need to add a dependency on the `apache-client` library at *compile* time. 

Refer to the following example of a Maven `pom.xml` file to configure the `ApacheHttpClient`.

```
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>2.27.21</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
        </dependency>
        <!-- By adding the apache-client dependency, ApacheHttpClient will be added to 
             the compile classpath so you can configure it. -->
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>apache-client</artifactId>
        </dependency>
    </dependencies>
```

## Use and configure the `ApacheHttpClient`
<a name="http-apache-config"></a>

You can configure an instance of `ApacheHttpClient` along with building a service client, or you can configure a single instance to share across multiple service clients. 

With either approach, you use the `[ApacheHttpClient.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache/ApacheHttpClient.Builder.html)` to configure the properties for the Apache-based HTTP client.

### Best practice: dedicate an `ApacheHttpClient` instance to a service client
<a name="http-config-apache-recomm"></a>

If you need to configure an instance of the `ApacheHttpClient`, we recommend that you build the dedicated `ApacheHttpClient` instance. You can do so by using the `httpClientBuilder` method of the service client's builder. This way, the lifecycle of the HTTP client is managed by the SDK, which helps avoid potential memory leaks if the `ApacheHttpClient` instance is not closed down when it's no longer needed.

The following example creates an `S3Client` and configures the embedded instance of `ApacheHttpClient` with `maxConnections` and `connectionTimeout` values. The HTTP instance is created using the `httpClientBuilder` method of `S3Client.Builder`.

 **Imports** 

```
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.services.s3.S3Client;
import java.time.Duration;
```

 **Code** 

```
S3Client s3Client = S3Client   // Singleton: Use the s3Client for all requests.
    .builder()
    .httpClientBuilder(ApacheHttpClient.builder()
        .maxConnections(100)
        .connectionTimeout(Duration.ofSeconds(5))
    ).build();

// Perform work with the s3Client.

s3Client.close();   // Requests completed: Close all service clients.
```

### Alternative approach: share an `ApacheHttpClient` instance
<a name="http-config-apache-alt"></a>

To help keep resource and memory usage lower for your application, you can configure an `ApacheHttpClient` and share it across multiple service clients. The HTTP connection pool will be shared, which lowers resource usage.

**Note**  
When an `ApacheHttpClient` instance is shared, you must close it when it is ready to be disposed. The SDK will not close the instance when the service client is closed.

The following example configures an Apache-based HTTP client that is used by two service clients. The configured `ApacheHttpClient` instance is passed to the `httpClient` method of each builder. When the service clients and the HTTP client are no longer needed, the code explicitly closes them. The code closes the HTTP client last.

**Imports**

```
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.s3.S3Client;
```

 **Code** 

```
SdkHttpClient apacheHttpClient = ApacheHttpClient.builder()
        .maxConnections(100).build();

// Singletons: Use the s3Client and dynamoDbClient for all requests.
S3Client s3Client = 
    S3Client.builder()
            .httpClient(apacheHttpClient).build();

DynamoDbClient dynamoDbClient = 
    DynamoDbClient.builder()
                  .httpClient(apacheHttpClient).build();

// Perform work with the s3Client and dynamoDbClient.

// Requests completed: Close all service clients.
s3Client.close();
dynamoDbClient.close();
apacheHttpClient.close();  // Explicitly close apacheHttpClient.
```

## Proxy configuration example
<a name="http-configuration-apache-proxy-conf-ex"></a>

The following code snippet uses the [proxy configuration builder for the Apache HTTP client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache/ProxyConfiguration.Builder.html).

```
SdkHttpClient apacheHttpClient = ApacheHttpClient.builder()
                .proxyConfiguration(ProxyConfiguration.builder()
                        .endpoint(URI.create("http://example.com:1234"))
                        .username("username")
                        .password("password")
                        .addNonProxyHost("localhost")
                        .addNonProxyHost("host.example.com")
                        .build())
                .build();
```

The equivalent Java system properties for the proxy configuration are shown in the following command line snippet.

```
$ java -Dhttp.proxyHost=example.com -Dhttp.proxyPort=1234 -Dhttp.proxyUser=username \
-Dhttp.proxyPassword=password -Dhttp.nonProxyHosts=localhost|host.example.com -cp ... App
```

The equivalent setup that uses environment variables is:

```
// Set the following environment variables.
// $ export HTTP_PROXY="http://username:password@example.com:1234"
// $ export NO_PROXY="localhost|host.example.com"

// Set the 'useSystemPropertyValues' to false on the proxy configuration.
SdkHttpClient apacheHttpClient = ApacheHttpClient.builder()
                .proxyConfiguration(ProxyConfiguration.builder()
                        .useSystemPropertyValues(Boolean.FALSE)
                        .build())
                .build();

// Run the application.
// $ java -cp ... App
```

**Note**  
The Apache HTTP client does not currently support HTTPS proxy system properties or the HTTPS\$1PROXY environment variable.

# Configure the URLConnection-based HTTP client
<a name="http-configuration-url"></a>

The AWS SDK for Java 2.x offers a lighter-weight `[UrlConnectionHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.html)` HTTP client in comparison to the default `ApacheHttpClient`. The `UrlConnectionHttpClient` is based on Java's `[URLConnection](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/net/URLConnection.html)`.

The `UrlConnectionHttpClient` loads more quickly than the Apache-based HTTP client, but has fewer features. Because it loads more quickly, it is a [good solution](lambda-optimize-starttime.md) for Java AWS Lambda functions.

The `UrlConnectionHttpClient` has several [configurable options](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.Builder.html) that you can access.

**Note**  
The `UrlConnectionHttpClient` does not support the HTTP PATCH method.   
A handful of AWS API operations require PATCH requests. Those operation names usually start with `Update*`. The following are several examples.  
[Several `Update*` operations](https://docs.aws.amazon.com/securityhub/1.0/APIReference/API_Operations.html) in the AWS Security Hub CSPM API and also the [BatchUpdateFindings](https://docs.aws.amazon.com/securityhub/1.0/APIReference/API_BatchUpdateFindings.html) operation
All Amazon API Gateway API [`Update*` operations](https://docs.aws.amazon.com/apigateway/latest/api/API_UpdateAccount.html)
If you might use the `UrlConnectionHttpClient`, first refer to the API Reference for the AWS service that you're using. Check to see if the operations you need use the PATCH operation.

## Access the `UrlConnectionHttpClient`
<a name="http-url-dependency"></a>

To configure and use the `UrlConnectionHttpClient`, you declare a dependency on the `url-connection-client` Maven artifact in your `pom.xml` file.

Unlike the `ApacheHttpClient`, the `UrlConnectionHttpClient` is not automatically added to your project, so use must specifically declare it.

The following example of a `pom.xml` file shows the dependencies required to use and configure the HTTP client.

```
<dependencyManagement>
   <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.27.21</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- other dependencies such as s3 or dynamodb -->

<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>url-connection-client</artifactId>
    </dependency>
</dependencies>
```

## Use and configure the `UrlConnectionHttpClient`
<a name="http-url-config"></a>

You can configure an instance of `UrlConnectionHttpClient` along with building a service client, or you can configure a single instance to share across multiple service clients. 

With either approach, you use the [UrlConnectionHttpClient.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.Builder.html) to configure the properties for the URLConnection-based HTTP client.

### Best practice: dedicate an `UrlConnectionHttpClient` instance to a service client
<a name="http-config-url-one-client"></a>

If you need to configure an instance of the `UrlConnectionHttpClient`, we recommend that you build the dedicated `UrlConnectionHttpClient` instance. You can do so by using the `httpClientBuilder` method of the service client's builder. This way, the lifecycle of the HTTP client is managed by the SDK, which helps avoid potential memory leaks if the `UrlConnectionHttpClient` instance is not closed down when it's no longer needed.

The following example creates an `S3Client` and configures the embedded instance of `UrlConnectionHttpClient` with `socketTimeout` and `proxyConfiguration` values. The `proxyConfiguration` method takes a Java lambda expression of type ` Consumer<[ProxyConfiguration.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/ProxyConfiguration.Builder.html)>`.

 **Imports** 

```
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
import java.net.URI;
import java.time.Duration;
```

 **Code** 

```
// Singleton: Use the s3Client for all requests.
S3Client s3Client = 
    S3Client.builder()
            .httpClientBuilder(UrlConnectionHttpClient.builder()
                    .socketTimeout(Duration.ofMinutes(5))
                    .proxyConfiguration(proxy -> proxy.endpoint(URI.create("http://proxy.mydomain.net:8888"))))
            .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
            .build();

// Perform work with the s3Client.

s3Client.close();   // Requests completed: Close the s3client.
```

### Alternative approach: share an `UrlConnectionHttpClient` instance
<a name="http-config-url-multi-clients"></a>

To help keep resource and memory usage lower for your application, you can configure an `UrlConnectionHttpClient` and share it across multiple service clients. The HTTP connection pool will be shared, which lowers resource usage.

**Note**  
When an `UrlConnectionHttpClient` instance is shared, you must close it when it is ready to be disposed. The SDK will not close the instance when the service client is closed.

The following example configures an URLConnection-based HTTP client that is used by two service clients. The configured `UrlConnectionHttpClient` instance is passed to the `httpClient` method of each builder. When the service clients and the HTTP client are no longer needed, the code explicitly closes them. The code closes the HTTP client last.

**Imports**

```
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.urlconnection.ProxyConfiguration;
import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.s3.S3Client;
import java.net.URI;
import java.time.Duration;
```

 **Code** 

```
SdkHttpClient urlHttpClient = UrlConnectionHttpClient.create();

// Singletons: Use the s3Client and dynamoDbClient for all requests.
S3Client s3Client = 
    S3Client.builder()
            .httpClient(urlHttpClient)
            .defaultsMode(DefaultsMode.IN_REGION)
            .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
            .build();

DynamoDbClient dynamoDbClient = 
    DynamoDbClient.builder()
                  .httpClient(urlHttpClient)
                  .defaultsMode(DefaultsMode.IN_REGION)
                  .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
                  .build();

// Perform work with the s3Client and dynamoDbClient.

// Requests completed: Close all service clients.
s3Client.close();
dynamoDbClient.close();
urlHttpClient.close();
```

#### Use `URLConnectionHttpClient` and `ApacheHttpClient` together
<a name="http-config-url-caveat"></a>

When you use the `UrlConnectionHttpClient` in your application, you must supply each service client with either a `URLConnectionHttpClient` instance or a `ApacheHttpClient` instance using the service client builder's `httpClientBuilder` method. 

An exception occurs if your program uses multiple service clients and both of the following are true:
+ One service client is configured to use a `UrlConnectionHttpClient` instance
+ Another service client uses the default `ApacheHttpClient` without explicitly building it with the `httpClient()` or `httpClientBuilder()` methods

The exception will state that multiple HTTP implementations were found on the classpath.

The following example code snippet leads to an exception.

```
// The dynamoDbClient uses the UrlConnectionHttpClient
DynamoDbClient dynamoDbClient = DynamoDbClient.builder()
        .httpClient(UrlConnectionHttpClient.create())
        .build();

// The s3Client below uses the ApacheHttpClient at runtime, without specifying it.
// An SdkClientException is thrown with the message that multiple HTTP implementations were found on the classpath.
S3Client s3Client = S3Client.create();

// Perform work with the s3Client and dynamoDbClient.

dynamoDbClient.close();
s3Client.close();
```

Avoid the exception by explicitly configuring the `S3Client` with an `ApacheHttpClient`.

```
DynamoDbClient dynamoDbClient = DynamoDbClient.builder()
        .httpClient(UrlConnectionHttpClient.create())
        .build();

S3Client s3Client = S3Client.builder()
        .httpClient(ApacheHttpClient.create())    // Explicitly build the ApacheHttpClient.
        .build();

// Perform work with the s3Client and dynamoDbClient.

dynamoDbClient.close();
s3Client.close();
```

**Note**  
To explicitly create the `ApacheHttpClient`, you must [add a dependency](http-configuration-apache.md#http-apache-dependency) on the `apache-client` artifact in your Maven project file.

## Proxy configuration example
<a name="http-configuration-url-proxy-conf-ex"></a>

The following code snippet uses the [proxy configuration builder for the URL connection HTTP client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/ProxyConfiguration.Builder.html).

```
SdkHttpClient urlHttpClient = UrlConnectionHttpClient.builder()
                .proxyConfiguration(ProxyConfiguration.builder()
                        .endpoint(URI.create("http://example.com:1234"))
                        .username("username")
                        .password("password")
                        .addNonProxyHost("localhost")
                        .addNonProxyHost("host.example.com")
                        .build())
                .build();
```

The equivalent Java system properties for the proxy configuration are shown in the following command line snippet.

```
$ java -Dhttp.proxyHost=example.com -Dhttp.proxyPort=1234 -Dhttp.proxyUser=username \
-Dhttp.proxyPassword=password -Dhttp.nonProxyHosts=localhost|host.example.com -cp ... App
```

The equivalent setup that uses environment variables is:

```
// Set the following environment variables.
// $ export HTTP_PROXY="http://username:password@example.com:1234"
// $ export NO_PROXY="localhost|host.example.com"

// Set the 'useSystemPropertyValues' to false on the proxy configuration.
SdkHttpClient apacheHttpClient = UrlConnectionHttpClient.builder()
                .proxyConfiguration(ProxyConfiguration.builder()
                        .useSystemPropertyValues(Boolean.FALSE)
                        .build())
                .build();

// Run the application.
// $ java -cp ... App
```

**Note**  
The URLConnection-based HTTP client does not currently support HTTPS proxy system properties or the HTTPS\$1PROXY environment variable.

# Configure the Netty-based HTTP client
<a name="http-configuration-netty"></a>

The default HTTP client for asynchronous operations in the AWS SDK for Java 2.x is the Netty-based [NettyNioAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.html). The Netty-based client is based on the asynchronous event-driven network framework of the [Netty project](https://netty.io/).

As an alternative HTTP client, you can use the new [AWS CRT-based HTTP client](http-configuration-crt.md). This topic shows you how to configure the `NettyNioAsyncHttpClient`.

## Access the `NettyNioAsyncHttpClient`
<a name="http-config-netty-access"></a>

In most situations, you use the `NettyNioAsyncHttpClient` without any explicit configuration in asynchronous programs. You declare your asynchronous service clients and the SDK will configure the `NettyNioAsyncHttpClient` with standard values for you.

If you want to explicitly configure the `NettyNioAsyncHttpClient` or use it with multiple service clients, you need to make it available for configuration.

### No configuration needed
<a name="http-config-netty-no-config"></a>

When you declare a dependency on a service client in Maven, the SDK adds a *runtime* dependency on the `netty-nio-client` artifact. This makes the `NettyNioAsyncHttpClient` class available to your code at runtime, but not at compile time. If you are not configuring the Netty-based HTTP client, you don't need to specify a dependency for it.

In the following XML snippet of a Maven `pom.xml` file, the dependency declared with `<artifactId>dynamodb-enhanced</artifactId>` transitively brings in the Netty-based HTTP client. You don't need to declare a dependency specifically for it.

```
<dependencyManagement>
   <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.27.21</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>dynamodb-enhanced</artifactId>
    </dependency>
</dependencies>
```

With these dependencies, you cannot make any HTTP configuration changes, since the `NettyNioAsyncHttpClient` library is only on the runtime classpath. 

### Configuration needed
<a name="http-config-netty-yes-config"></a>

To configure the `NettyNioAsyncHttpClient`, you need to add a dependency on the `netty-nio-client` artifact at *compile* time. 

Refer to the following example of a Maven `pom.xml` file to configure the `NettyNioAsyncHttpClient`.

```
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>2.27.21</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>dynamodb-enhanced</artifactId>
        </dependency>
        <!-- By adding the netty-nio-client dependency, NettyNioAsyncHttpClient will be 
             added to the compile classpath so you can configure it. -->
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>netty-nio-client</artifactId>
        </dependency>
    </dependencies>
```

## Use and configure the `NettyNioAsyncHttpClient`
<a name="http-netty-config"></a>

You can configure an instance of `NettyNioAsyncHttpClient` along with building a service client, or you can configure a single instance to share across multiple service clients. 

With either approach, you use the [NettyNioAsyncHttpClient.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.Builder.html) to configure the properties for the Netty-based HTTP client instance.

### Best practice: dedicate a `NettyNioAsyncHttpClient` instance to a service client
<a name="http-config-netty-one-client"></a>

If you need to configure an instance of the `NettyNioAsyncHttpClient`, we recommend that you build a dedicated `NettyNioAsyncHttpClient` instance. You can do so by using the `httpClientBuilder` method of the service client's builder. This way, the lifecycle of the HTTP client is managed by the SDK, which helps avoid potential memory leaks if the `NettyNioAsyncHttpClient` instance is not closed down when it's no longer needed.

The following example creates a `DynamoDbAsyncClient` instance that is used by a `DynamoDbEnhancedAsyncClient` instance. The `DynamoDbAsyncClient` instance contains the `NettyNioAsyncHttpClient` instance with `connectionTimeout` and `maxConcurrency` values. The HTTP instance is created using `httpClientBuilder` method of `DynamoDbAsyncClient.Builder`.

 **Imports** 

```
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient;
import software.amazon.awssdk.enhanced.dynamodb.extensions.AutoGeneratedTimestampRecordExtension;
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import java.time.Duration;
```

 **Code** 

```
// DynamoDbAsyncClient is the lower-level client used by the enhanced client.
DynamoDbAsyncClient dynamoDbAsyncClient = 
    DynamoDbAsyncClient
        .builder()
            .httpClientBuilder(NettyNioAsyncHttpClient.builder()
            .connectionTimeout(Duration.ofMillis(5_000))
            .maxConcurrency(100)
            .tlsNegotiationTimeout(Duration.ofMillis(3_500)))
        .defaultsMode(DefaultsMode.IN_REGION)
        .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
        .build();

// Singleton: Use dynamoDbAsyncClient and enhancedClient for all requests.
DynamoDbEnhancedAsyncClient enhancedClient = 
    DynamoDbEnhancedAsyncClient
        .builder()
        .dynamoDbClient(dynamoDbAsyncClient)
        .extensions(AutoGeneratedTimestampRecordExtension.create())
        .build();

// Perform work with the dynamoDbAsyncClient and enhancedClient.

// Requests completed: Close dynamoDbAsyncClient.
dynamoDbAsyncClient.close();
```

### Alternative approach: share a `NettyNioAsyncHttpClient` instance
<a name="http-config-netty-multi-clients"></a>

To help keep resource and memory usage lower for your application, you can configure a `NettyNioAsyncHttpClient` and share it across multiple service clients. The HTTP connection pool will be shared, which lowers resource usage.

**Note**  
When a `NettyNioAsyncHttpClient` instance is shared, you must close it when it is ready to be disposed. The SDK will not close the instance when the service client is closed.

The following example configures a Netty-based HTTP client that is used by two service clients. The configured `NettyNioAsyncHttpClient` instance is passed to the `httpClient` method of each builder. When the service clients and the HTTP client are no longer needed, the code explicitly closes them. The code closes the HTTP client last.

**Imports**

```
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.s3.S3Client;
```

 **Code** 

```
// Create a NettyNioAsyncHttpClient shared instance.
SdkAsyncHttpClient nettyHttpClient = NettyNioAsyncHttpClient.builder().maxConcurrency(100).build();

// Singletons: Use the s3AsyncClient, dbAsyncClient, and enhancedAsyncClient for all requests.
S3AsyncClient s3AsyncClient = 
    S3AsyncClient.builder()
                 .httpClient(nettyHttpClient)
                 .build();

DynamoDbAsyncClient dbAsyncClient = 
    DynamoDbAsyncClient.builder()
                       .httpClient(nettyHttpClient)
                       .defaultsMode(DefaultsMode.IN_REGION)
                       .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
                       .build();

DynamoDbEnhancedAsyncClient enhancedAsyncClient = 
    DynamoDbEnhancedAsyncClient.builder()
                               .dynamoDbClient(dbAsyncClient)
                               .extensions(AutoGeneratedTimestampRecordExtension.create())
                               .build();

// Perform work with s3AsyncClient, dbAsyncClient, and enhancedAsyncClient.

// Requests completed: Close all service clients.
s3AsyncClient.close();
dbAsyncClient.close()
nettyHttpClient.close();  // Explicitly close nettyHttpClient.
```

## Configure ALPN protocol negotiation
<a name="http-netty-config-alpn"></a>

ALPN (Application-Layer Protocol Negotiation) is a TLS extension that allows the application layer to negotiate which protocol should be performed over a secure connection in a manner that avoids additional round trips and provides better performance.

To enable the Netty-based HTTP client to use ALPN, call the builder methods as shown in the following snippet:

```
import software.amazon.awssdk.http.Protocol;
import software.amazon.awssdk.http.ProtocolNegotiation;
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
import software.amazon.awssdk.services.transcribestreaming.TranscribeStreamingAsyncClient;


// Configure the Netty-based HTTP client to use the ALPN protocol.
SdkAsyncHttpClient nettyClient = NettyNioAsyncHttpClient.builder()
                                                        .protocol(Protocol.HTTP2)
                                                        .protocolNegotiation(ProtocolNegotiation.ALPN)
                                                        .build();
// Use the Netty-based HTTP client with a service client.
TranscribeStreamingAsyncClient transcribeClient = TranscribeStreamingAsyncClient.builder()
                                                                                .httpClient(nettyClient)
                                                                                .build();
```

ALPN protocol negotiation currently works with only with the HTTP/2 protocol as shown in the previous snippet.

## Proxy configuration example
<a name="http-config-netty-proxy-ex"></a>

The following code snippet uses the [proxy configuration builder for the Netty HTTP client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/nio/netty/ProxyConfiguration.Builder.html).

```
SdkAsyncHttpClient nettyHttpClient = NettyNioAsyncHttpClient.builder()
    .proxyConfiguration(ProxyConfiguration.builder()
        .scheme("https")
        .host("myproxy")
        .port(1234)
        .username("username")
        .password("password")
        .nonProxyHosts(Set.of("localhost", "host.example.com"))
        .build())
    .build();
```

The equivalent Java system properties for the proxy configuration are shown in the following command line snippet.

```
$ java -Dhttps.proxyHost=myproxy -Dhttps.proxyPort=1234 -Dhttps.proxyUser=username \
-Dhttps.proxyPassword=password -Dhttp.nonProxyHosts=localhost|host.example.com -cp ... App
```

**Important**  
To use any of the HTTPS proxy system properties, the `scheme` property must be set in code to `https`. If the scheme property is not set in code, the scheme defaults to HTTP and the SDK looks only for `http.*` system properties.

The equivalent setup that uses environment variables is:

```
// Set the following environment variables.
// $ export HTTPS_PROXY="https://username:password@myproxy:1234"
// $ export NO_PROXY="localhost|host.example.com"

// Set the 'useSystemPropertyValues' to false on the proxy configuration.
SdkAsyncHttpClient nettyHttpClient = NettyNioAsyncHttpClient.builder()
    .proxyConfiguration(ProxyConfiguration.builder()
        .useSystemPropertyValues(Boolean.FALSE)
        .build())
    .build();

// Run the application.
// $ java -cp ... App
```

# Configure AWS CRT-based HTTP clients
<a name="http-configuration-crt"></a>

The AWS CRT-based HTTP clients include the synchronous [AwsCrtHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtHttpClient.html) and asynchronous [AwsCrtAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtAsyncHttpClient.html). The AWS CRT-based HTTP clients provide the following HTTP client benefits:
+ Faster SDK startup time
+ Smaller memory footprint
+ Reduced latency time
+ Connection health management
+ DNS load balancing

**AWS CRT-based components in the SDK**

The AWS CRT-based* HTTP* clients, described in this topic, and the AWS CRT-based *S3* client are different components in the SDK. 

The synchronous and asynchronous **AWS CRT-based HTTP clients** are implementations SDK HTTP client interfaces and are used for general HTTP communication. They are alternatives to the other synchronous or asynchronous HTTP clients in the SDK with additional benefits.

The **[AWS CRT-based S3 client](crt-based-s3-client.md)** is an implementation of the [S3AsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html) interface and is used for working with the Amazon S3 service. It is an alternative to the Java-based implementation of the `S3AsyncClient` interface and offers several advantages.

Although both components use libraries from the [AWS Common Runtime](https://docs.aws.amazon.com/sdkref/latest/guide/common-runtime.html), the AWS CRT-based HTTP clients do not use the [aws-c-s3 library](https://github.com/awslabs/aws-c-s3) and do not support the [S3 multipart upload API](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html) features. The AWS CRT-based S3 client, by contrast, was purpose-built to support the S3 multipart upload API features.

## Access the AWS CRT-based HTTP clients
<a name="http-config-crt-access"></a>

Before you can use the AWS CRT-based HTTP clients, add the `aws-crt-client` artifact with a minimum version of 2.22.0 to your project's dependencies.

Use one of the following options to set up your Maven `pom.xml` file.

**Note**  
 You might choose to use the *Platform-specific jar option* if you need to keep the size of the runtime dependencies smaller, for example if your application runs in an AWS Lambda function.

------
#### [ Uber-jar option ]

By default, the `aws-crt-client` uses an uber-jar of AWS CRT artifacts that contains binaries for several platforms, including Linux, Windows, and macOS.

```
<project>
   <properties>
     <aws.sdk.java.version>2.29.10*</aws.sdk.java.version>
  </properties>
  <dependencyManagement>
   <dependencies>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>bom</artifactId>
        <version>${aws.sdk.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
   </dependencies>
  </dependencyManagement>
  <dependencies>
   <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>aws-crt-client</artifactId>
   </dependency>
  </dependencies>
</project>
```

\$1Replace the version shown in red with the version of the Java SDK that you want to use. Find the latest on [Maven Central](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

------
#### [ Platform-specific jar option ]

To restrict the Java runtime to platform-specific version of the AWS CRT library, make the following changes to the *Uber-jar option*.
+ Add an `exclusions` element to the SDK's `aws-crt-client` artifact. This exclusion prevents the SDK from transitively using the AWS CRT uber-jar.
+ Add a dependency element for the specific AWS CRT platform version you need. See the **Steps to determine the AWS CRT artifact version** below for how you can determine the correct version.

```
<project>
   <properties>
     <aws.sdk.java.version>2.29.101</aws.sdk.java.version>
  </properties>
   <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>${aws.sdk.java.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>aws-crt-client</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>software.amazon.awssdk.crt</groupId>
                    <artifactId>aws-crt</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk.crt</groupId>
            <artifactId>aws-crt</artifactId>
            <version>0.31.32</version>
            <classifier>linux-x86_643</classifier>
        </dependency>
    </dependencies>
```

1Replace the version shown in red with the version of the Java SDK that you want to use. Find the latest on [Maven Central](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

2Replace the version of `software.amazon.awssdk.crt:aws-crt` that would be provided by the *Uber-jar option*. See the following **Steps to determine the AWS CRT artifact version**.

3Replace the `classifier` value with one for your platform. Refer to the AWS CRT for Java GitHub page for a [listing of available values](https://github.com/awslabs/aws-crt-java?tab=readme-ov-file#platform-specific-jars).

**Steps to determine the AWS CRT artifact version**

Use the following steps to determine the AWS CRT artifact version that is compatible with the version of the SDK for Java that you are using.

1. Set up your `pom.xml` file as shown in the *Uber-jar option*. This setup allows you to see what version of `software.amazon.awssdk.crt:aws-crt` the SDK brings in by default.

1. At the root of the project (in the same directory as the `pom.xml` file), run the following Maven command:

   ```
   mvn dependency:tree -Dincludes=software.amazon.awssdk.crt:aws-crt
   ```

   Maven might perform other actions, but at the end you should see console output of the `software.amazon.awssdk.crt:aws-crt` dependency that the SDK transitively uses. The following snippet shows sample output based on an SDK version of `2.29.10`:

   ```
   [INFO] org.example:yourProject:jar:1.0-SNAPSHOT
   [INFO] \- software.amazon.awssdk:aws-crt-client:jar:2.29.10:compile
   [INFO]    \- software.amazon.awssdk.crt:aws-crt:jar:0.31.3:compile
   ```

1. Use the version that the console shows for the `software.amazon.awssdk.crt:aws-crt` artifact. In this case, add `0.31.3` to your `pom.xml` file.

------

## Use and configure an AWS CRT-based HTTP client
<a name="http-crt-config"></a>

You can configure an AWS CRT-based HTTP client along with building a service client, or you can configure a single instance to share across multiple service clients. 

With either approach, you use a builder to [configure the properties](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtHttpClient.Builder.html) for the AWS CRT-based HTTP client instance.

### Best practice: dedicate an instance to a service client
<a name="http-config-crt-one-client"></a>

If you need to configure an instance of an AWS CRT-based HTTP client, we recommend that you dedicate the instance by building it along with the service client . You can do so by using the `httpClientBuilder` method of the service client's builder. This way, the lifecycle of the HTTP client is managed by the SDK, which helps avoid potential memory leaks if the AWS CRT-based HTTP client instance is not closed down when it's no longer needed.

The following example creates an S3 service client and configures an AWS CRT-based HTTP client with `connectionTimeout` and `maxConcurrency` values. 

------
#### [ Synchronous client ]

**Imports**

```
import software.amazon.awssdk.http.crt.AwsCrtHttpClient;
import software.amazon.awssdk.services.s3.S3Client;
import java.time.Duration;
```

**Code**

```
// Singleton: Use s3Client for all requests.
S3Client s3Client = S3Client.builder()
    .httpClientBuilder(AwsCrtHttpClient
        .builder()
        .connectionTimeout(Duration.ofSeconds(3))
        .maxConcurrency(100))
    .build();

// Perform work with the s3Client.

// Requests completed: Close the s3Client.
s3Client.close();
```

------
#### [ Asynchronous client ]

**Imports**

```
import software.amazon.awssdk.http.crt.AwsCrtAsyncHttpClient;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import java.time.Duration;
```

**Code**

```
// Singleton: Use s3AsyncClient for all requests.
S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
    .httpClientBuilder(AwsCrtAsyncHttpClient
        .builder()
        .connectionTimeout(Duration.ofSeconds(3))
        .maxConcurrency(100))
    .build();

// Perform work with the s3AsyncClient.

// Requests completed: Close the s3AsyncClient.
s3AsyncClient.close();
```

------

### Alternative approach: share an instance
<a name="http-config-crt-multi-clients"></a>

To help keep resource and memory usage lower for your application, you can configure an AWS CRT-based HTTP client and share it across multiple service clients. The HTTP connection pool will be shared, which lowers resource usage.

**Note**  
When an AWS CRT-based HTTP client instance is shared, you must close it when it is ready to be disposed. The SDK will not close the instance when the service client is closed.

The following example configures an AWS CRT-based HTTP client instance with `connectionTimeout` and `maxConcurrency` values. The configured instance is passed to the `httpClient` method of each service client's builder. When the service clients and the HTTP client are no longer needed, they are explicitly closed. The HTTP client is closed last.

------
#### [ Synchronous client ]

**Imports**

```
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.crt.AwsCrtHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.s3.S3Client;
import java.time.Duration;
```

**Code**

```
// Create an AwsCrtHttpClient shared instance.
SdkHttpClient crtHttpClient = AwsCrtHttpClient.builder()
    .connectionTimeout(Duration.ofSeconds(3))
    .maxConcurrency(100)
    .build();

// Singletons: Use the s3Client and dynamoDbClient for all requests.
S3Client s3Client = S3Client.builder()
    .httpClient(crtHttpClient)
    .credentialsProvider(EnvironmentVariableCredentialsProvider.crea
    .defaultsMode(DefaultsMode.IN_REGION)
    .region(Region.US_EAST_1)
    .build();

DynamoDbClient dynamoDbClient = DynamoDbClient.builder()
    .httpClient(crtHttpClient)
    .credentialsProvider(EnvironmentVariableCredentialsProvider.crea
    .defaultsMode(DefaultsMode.IN_REGION)
    .region(Region.US_EAST_1)
    .build();

// Requests completed: Close all service clients.
s3Client.close();
dynamoDbClient.close();
crtHttpClient.close();  // Explicitly close crtHttpClient.
```

------
#### [ Asynchronous client ]

**Imports**

```
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode;
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
import software.amazon.awssdk.http.crt.AwsCrtAsyncHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import java.time.Duration;
```

**Code**

```
// Create an AwsCrtAsyncHttpClient shared instance.
SdkAsyncHttpClient crtAsyncHttpClient = AwsCrtAsyncHttpClient.builder()
    .connectionTimeout(Duration.ofSeconds(3))
    .maxConcurrency(100)
    .build();

// Singletons: Use the s3AsyncClient and dynamoDbAsyncClient for all requests.
S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
    .httpClient(crtAsyncHttpClient)
    .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
    .defaultsMode(DefaultsMode.IN_REGION)
    .region(Region.US_EAST_1)
    .build();

DynamoDbAsyncClient dynamoDbAsyncClient = DynamoDbAsyncClient.builder()
    .httpClient(crtAsyncHttpClient)
    .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
    .defaultsMode(DefaultsMode.IN_REGION)
    .region(Region.US_EAST_1)
    .build();

// Requests completed: Close all service clients.
s3AsyncClient.close();
dynamoDbAsyncClient.close();
crtAsyncHttpClient.close();  // Explicitly close crtAsyncHttpClient.
```

------

## Set an AWS CRT-based HTTP client as the default
<a name="setting-the-crt-based-http-client-as-the-default"></a>

You can setup your Maven build file to have the SDK use an AWS CRT-based HTTP client as the default HTTP client for service clients.

You do this by adding an `exclusions` element with the default HTTP client dependencies to each service client artifact.

In the following `pom.xml` example, the SDK uses an AWS CRT-based HTTP client for S3 services. If the service client in your code is an `S3AsyncClient`, the SDK uses `AwsCrtAsyncHttpClient`. If the service client is an S3Client, the SDK uses `AwsCrtHttpClient`. With this setup the default Netty-based asynchronous HTTP client and the default Apache-based synchronous HTTP are not available.

```
<project>
   <properties>
     <aws.sdk.version>VERSION</aws.sdk.version>
  </properties>
  <dependencies>
   <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>s3</artifactId>
      <version>${aws.sdk.version}</version>
      <exclusions>
         <exclusion>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>netty-nio-client</artifactId>
         </exclusion>
         <exclusion>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>apache-client</artifactId>
         </exclusion>
      </exclusions>
   </dependency>
   <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>aws-crt-client</artifactId>
   </dependency>
  </dependencies>
</project>
```

Visit the Maven central repository for the latest [https://central.sonatype.com/artifact/software.amazon.awssdk/bom](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) value.

**Note**  
If multiple service clients are declared in a `pom.xml` file, all require the `exclusions` XML element.

### Use a Java system property
<a name="setting-via-java-system-property"></a>

To use the AWS CRT-based HTTP clients as the default HTTP for your application, you can set the Java system property `software.amazon.awssdk.http.async.service.impl` to a value of `software.amazon.awssdk.http.crt.AwsCrtSdkHttpService`.

To set during application startup, run a command similar to the following.

```
java app.jar -Dsoftware.amazon.awssdk.http.async.service.impl=\
software.amazon.awssdk.http.crt.AwsCrtSdkHttpService
```

Use the following code snippet to set the system property in your application code.

```
System.setProperty("software.amazon.awssdk.http.async.service.impl",
"software.amazon.awssdk.http.crt.AwsCrtSdkHttpService");
```

**Note**  
You need to add a dependency on the `aws-crt-client` artifact in your `poml.xml` file when you use a system property to configure the use of the AWS CRT-based HTTP clients.

## Advanced configuration of AWS CRT-based HTTP clients
<a name="configuring-the-crt-based-http-client"></a>

You can use various configuration settings of the AWS CRT-based HTTP clients, including connection health configuration and maximum idle time. You can review the configuration [options available](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtAsyncHttpClient.Builder.html) for the `AwsCrtAsyncHttpClient`. You can configure the same options for the `AwsCrtHttpClient`.

### Connection health configuration
<a name="connection-health-checks"></a>

You can configure connection health configuration for the AWS CRT-based HTTP clients by using the `connectionHealthConfiguration` method on the HTTP client builder. 

The following example creates an S3 service client that uses a AWS CRT-based HTTP client instance configured with connection health configuration and a maximum idle time for connections. 

------
#### [ Synchronous client ]

**Imports**

```
import software.amazon.awssdk.http.crt.AwsCrtHttpClient;
import software.amazon.awssdk.services.s3.S3Client;
import java.time.Duration;
```

**Code**

```
// Singleton: Use the s3Client for all requests.
S3Client s3Client = S3Client.builder()
    .httpClientBuilder(AwsCrtHttpClient
        .builder()
        .connectionHealthConfiguration(builder -> builder
            .minimumThroughputInBps(32000L)
            .minimumThroughputTimeout(Duration.ofSeconds(3)))
        .connectionMaxIdleTime(Duration.ofSeconds(5)))
    .build();

// Perform work with s3Client.

// Requests complete: Close the service client.
s3Client.close();
```

------
#### [ Asynchronous client ]

**Imports**

```
import software.amazon.awssdk.http.crt.AwsCrtAsyncHttpClient;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import java.time.Duration;
```

**Code**

```
// Singleton: Use the s3AsyncClient for all requests.
S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
    .httpClientBuilder(AwsCrtAsyncHttpClient
        .builder()
        .connectionHealthConfiguration(builder -> builder
            .minimumThroughputInBps(32000L)
            .minimumThroughputTimeout(Duration.ofSeconds(3)))
        .connectionMaxIdleTime(Duration.ofSeconds(5)))
    .build();

// Perform work with s3AsyncClient.

// Requests complete: Close the service client.
s3AsyncClient.close();
```

------

## Proxy configuration example
<a name="http-config-crt-proxy-ex"></a>

The following code snippet shows the use of the [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/ProxyConfiguration.Builder.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/ProxyConfiguration.Builder.html) that you use to configure proxy setting in code.

------
#### [ Synchronous client ]

**Imports**

```
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.crt.AwsCrtHttpClient;
import software.amazon.awssdk.http.crt.ProxyConfiguration;
```

**Code**

```
SdkHttpClient crtHttpClient = AwsCrtHttpClient.builder()
    .proxyConfiguration(ProxyConfiguration.builder()
        .scheme("https")
        .host("myproxy")
        .port(1234)
        .username("username")
        .password("password")
        .nonProxyHosts(Set.of("localhost", "host.example.com"))
        .build())
    .build();
```

------
#### [ Asynchronous client ]

**Imports**

```
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
import software.amazon.awssdk.http.crt.AwsCrtAsyncHttpClient;
import software.amazon.awssdk.http.crt.ProxyConfiguration;
```

**Code**

```
SdkAsyncHttpClient crtAsyncHttpClient = AwsCrtAsyncHttpClient.builder()
    .proxyConfiguration(ProxyConfiguration.builder()
        .scheme("https")
        .host("myproxy")
        .port(1234)
        .username("username")
        .password("password")
        .nonProxyHosts(Set.of("localhost", "host.example.com"))
        .build())
    .build();
```

------

The equivalent Java system properties for the proxy configuration are shown in the following command line snippet.

```
$ java -Dhttps.proxyHost=myproxy -Dhttps.proxyPort=1234 -Dhttps.proxyUser=username \
-Dhttps.proxyPassword=password -Dhttp.nonProxyHosts=localhost|host.example.com -cp ... App
```

**Important**  
To use any of the HTTPS proxy system properties, the `scheme` property must be set in code to `https`. If the scheme property is not set in code, the scheme defaults to HTTP and the SDK looks only for `http.*` system properties.

The equivalent setup that uses environment variables is:

```
// Set the following environment variables.
// $ export HTTPS_PROXY="https://username:password@myproxy:1234"
// $ export NO_PROXY="localhost|host.example.com"

// Set the 'useSystemPropertyValues' to false on the proxy configuration.
SdkAsyncHttpClient crtAsyncHttpClient = AwsCrtAsyncHttpClient.builder()
    .proxyConfiguration(ProxyConfiguration.builder()
        .scheme("https")
        .useSystemPropertyValues(Boolean.FALSE)
        .build())
    .build();

// Run the application.
// $ java -cp ... App
```

# Configure HTTP proxies
<a name="http-config-proxy-support"></a>

You can configure HTTP proxies by using code, by setting Java system properties, or by setting environment variables.

## Configure in code
<a name="http-config-proxy-support-in-code"></a>

You configure proxies in code with a client-specific `ProxyConfiguration` builder when you build the service client. The following code shows an example proxy configuration for an Apache-based HTTP client that is used by an Amazon S3 service client.

```
SdkHttpClient httpClient1 = ApacheHttpClient.builder()
    .proxyConfiguration(ProxyConfiguration.builder()
        .endpoint(URI.create("http://proxy.example.com"))
        .username("username")
        .password("password")
        .addNonProxyHost("localhost")
        .build())
    .build();

S3Client s3Client = S3Client.builder()
    .httpClient(httpClient)
    .build();
```

The section for each HTTP client in this topic shows a proxy configuration example.
+ [Apache HTTP client](http-configuration-apache.md#http-configuration-apache-proxy-conf-ex)
+ [URLConnection-based HTTP client](http-configuration-url.md#http-configuration-url-proxy-conf-ex)
+ [Netty-based HTTP client](http-configuration-netty.md#http-config-netty-proxy-ex)
+ [AWS CRT-based HTTP client](http-configuration-crt.md#http-config-crt-proxy-ex)

## Configure HTTP proxies with external settings
<a name="http-config-proxy-support-external"></a>

Even if you don't explicitly use a `ProxyConfiguration` builder in code, the SDK looks for external settings to configure a default proxy configuration. 

By default, the SDK first searches for JVM system properties. If even one property is found, the SDK uses the value and any other system property values. If no system properties are available, the SDK looks for proxy environment variables.

The SDK can use the following Java system properties and environment variables.


**Java system properties**  

| System property | Description | HTTP client support | 
| --- | --- | --- | 
|  http.proxyHost  |  Host name of the HTTP proxy server  |  All  | 
|  http.proxyPort  |  Port number of the HTTP proxy server  |  All  | 
| http.proxyUser |  Username for HTTP proxy authentication  |  All  | 
|  http.proxyPassword  | Password for HTTP proxy authentication |  All  | 
| http.nonProxyHosts |  List of hosts that should be reached directly, bypassing the proxy. [This list is also valid when HTTPS is used](https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html).  |  All  | 
| https.proxyHost |  Host name of the HTTPS proxy server  |  Netty, CRT  | 
|  https.proxyPort  |  Port number of the HTTPS proxy server  |  Netty, CRT  | 
| https.proxyUser |  Username for HTTPS proxy authentication  | Netty, CRT | 
| https.proxyPassword | Password for HTTPS proxy authentication | Netty, CRT | 


**Environment variables**  

| Environment variable | Description | HTTP client support | 
| --- | --- | --- | 
| HTTP\$1PROXY1 |  A valid URL with a scheme of HTTP  |  All  | 
|  HTTPS\$1PROXY1  |  A valid URL with a scheme of HTTPS  |  Netty, CRT  | 
| NO\$1PROXY2 |  List of hosts that should be reached directly, bypassing the proxy. The list is valid for both HTTP and HTTPS.  |  All  | 

### View key and footnotes
<a name="http-config-proxy-support-ext-key-footnote"></a>

**All** - All HTTP clients offered by the SDK–`UrlConnectionHttpClient`, `ApacheHttpClient`, `NettyNioAsyncHttpClient`, `AwsCrtAsyncHttpClient`.

**Netty** - The Netty-based HTTP client (`NettyNioAsyncHttpClient`).

**CRT** - The AWS CRT-based HTTP clients, (`AwsCrtHttpClient` and `AwsCrtAsyncHttpClient`).

1The environment variable queried, whether `HTTP_PROXY` or `HTTPS_PROXY`, depends on the scheme setting in the client's `ProxyConfiguration`. The default scheme is HTTP. The following snippet shows how to change the scheme to HTTPS used for environment variable resolution.

```
SdkHttpClient httpClient = ApacheHttpClient.builder()
    .proxyConfiguration(ProxyConfiguration.builder()
        .scheme("https")
        .build())
    .build();
```

2The `NO_PROXY` environment variable supports a mix of "\$1" and "," separators between host names. Host names may include the "\$1" wildcard.

## Use a combination of settings
<a name="http-config-proxy-support-combo"></a>

You can use a combination of HTTP proxy settings in code, system properties, and environment variables. 

**Example – configuration provided by a system property and by code**  

```
// Command line with the proxy password set as a system property.
$ java -Dhttp.proxyPassword=SYS_PROP_password -cp ... App

// Since the 'useSystemPropertyValues' setting is 'true' (the default), the SDK will supplement 
// the proxy configuration in code with the 'http.proxyPassword' value from the system property.
SdkHttpClient apacheHttpClient = ApacheHttpClient.builder()
            .proxyConfiguration(ProxyConfiguration.builder()
                    .endpoint(URI.create("http://localhost:1234"))
                    .username("username")
                    .build())
            .build();

// Use the apache HTTP client with proxy configuration.
DynamoDbClient dynamoDbClient = DynamoDbClient.builder()
                    .httpClient(apacheHttpClient)
                    .build();
```
The SDK resolves the following proxy settings.  

```
Host = localhost
Port = 1234
Password = SYS_PROP_password
UserName = username
Non ProxyHost = null
```

**Example – both system properties and environment variables are available**  
Each HTTP client's `ProxyConfiguration` builder offers settings named `useSystemPropertyValues` and `useEnvironmentVariablesValues`. By default, both setting are `true`. When `true`, the SDK automatically uses values from system properties or environment variables for options that are not provided by the `ProxyConfiguration` builder.  
System properties take precedence over environment variables. If an HTTP proxy system property is found, the SDK retrieves ***all*** values from system properties and none from environment variables. If you want to prioritize environment variables over system properties, set `useSystemPropertyValues` to `false`.
For this example, the following settings are available a runtime:  

```
// System properties 
http.proxyHost=SYS_PROP_HOST.com
http.proxyPort=2222
http.password=SYS_PROP_PASSWORD
http.user=SYS_PROP_USER

// Environment variables 
HTTP_PROXY="http://EnvironmentUser:EnvironmentPassword@ENV_VAR_HOST:3333"
NO_PROXY="environmentnonproxy.host,environmentnonproxy2.host:1234"
```
The service client is created with one of the following statements. None of the statements explicitly set a proxy setting.  

```
DynamoDbClient client = DynamoDbClient.create();
DynamoDbClient client = DynamoDbClient.builder().build();
DynamoDbClient client = DynamoDbClient.builder()
    .httpClient(ApacheHttpClient.builder()
        .proxyConfiguration(ProxyConfiguration.builder()
            .build())
        .build())
    .build();
```
The following proxy settings are resolved by the SDK:  

```
Host = SYS_PROP_HOST.com
Port = 2222
Password = SYS_PROP_PASSWORD
UserName = SYS_PROP_USER
Non ProxyHost = null
```
Because the service client has default proxy settings, the SDK searches for system properties and then environment variables. Since system properties settings take precedence over environment variables, the SDK uses only system properties.  
If the use of system properties is changed to `false` as shown in the following code, the SDK resolves only the environment variables.  

```
DynamoDbClient client = DynamoDbClient.builder()
    .httpClient(ApacheHttpClient.builder()
        .proxyConfiguration(ProxyConfiguration.builder()
            .useSystemPropertyValues(Boolean.FALSE)
            .build())
        .build())
    .build();
```
The resolved proxy settings using HTTP are:  

```
Host = ENV_VAR_HOST
Port = 3333
Password = EnvironmentPassword
UserName = EnvironmentUser
Non ProxyHost = environmentnonproxy.host, environmentnonproxy2.host:1234
```

# Configure the Apache 5.x based HTTP client
<a name="http-configuration-apache5"></a>

## Access the Apache5HttpClient
<a name="http-apache-5-dependency"></a>

In order to use the `Apache5HttpClient` you must add a dependency on **apache5-client** and explicitly configure `Apache5HttpClient` on your service clients.

```
<dependencyManagement>
   <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.41.0*</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
    </dependency>
    
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>apache5-client</artifactId>
    </dependency>
</dependencies>
```

\$1Replace the version shown in red with the version of the Java SDK that you want to use. Find the latest on [Maven Central](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

### Use and configure the `Apache5HttpClient`
<a name="http-config-apache-5-config"></a>

You can configure an instance of `Apache5HttpClient` along with building a service client, or you can configure a single instance to share across multiple service clients. 

With either approach, you use the [Apache5HttpClient.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache5/Apache5HttpClient.Builder.html) to configure the properties for the Apache 5 based HTTP client.

#### Best practice: dedicate an Apache5HttpClient instance to a service client
<a name="http-apache5-dedicated-instance"></a>

If you need to configure an instance of the `Apache5HttpClient`, we recommend that you build the dedicated `Apache5HttpClient` instance. You can do so by using the httpClientBuilder method of the service client's builder. This way, the lifecycle of the HTTP client is managed by the SDK, which helps avoid potential memory leaks if the `Apache5HttpClient` instance is not closed down when it's no longer needed.

The following example creates an S3Client and configures the embedded instance of `Apache5HttpClient` with maxConnections and connectionTimeout values. The HTTP instance is created using the `httpClientBuilder` method of `S3Client.Builder`.

**Imports**

```
import software.amazon.awssdk.http.apache5.Apache5HttpClient;
import software.amazon.awssdk.services.s3.S3Client;
import java.time.Duration;
```

**Code**

```
S3Client s3Client = S3Client   // Singleton: Use the s3Client for all requests.
    .builder()
    .httpClientBuilder(Apache5HttpClient.builder()
        .maxConnections(100)
        .connectionTimeout(Duration.ofSeconds(5))
    )
    .build();

// Perform work with the s3Client.

s3Client.close();   // Requests completed: Close all service clients.
```

#### Alternative approach: share an `Apache5HttpClient` instance
<a name="http-apache5-shared-instance"></a>

To help keep resource and memory usage lower for your application, you can configure an `Apache5HttpClient` and share it across multiple service clients. The HTTP connection pool will be shared, which lowers resource usage.

**Note**  
When an `Apache5HttpClient` instance is shared, you must close it when it is ready to be disposed. The SDK will not close the instance when the service client is closed.

The following example configures an Apache-based HTTP client that is used by two service clients. The configured `ApacheHttpClient` instance is passed to the httpClient method of each builder. When the service clients and the HTTP client are no longer needed, the code explicitly closes them. The code closes the HTTP client last.

**Imports**

```
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.apache5.Apache5HttpClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.s3.S3Client;
```

**Code**

```
SdkHttpClient apache5HttpClient = Apache5HttpClient.builder()
        .maxConnections(100).build();

// Singletons: Use the s3Client and dynamoDbClient for all requests.
S3Client s3Client = 
    S3Client.builder()
            .httpClient(apache5HttpClient).build();

DynamoDbClient dynamoDbClient = 
    DynamoDbClient.builder()
                  .httpClient(apache5HttpClient).build();

// Perform work with the s3Client and dynamoDbClient.

// Requests completed: Close all service clients.
s3Client.close();
dynamoDbClient.close();
apache5HttpClient.close();  // Explicitly close apache5HttpClient.
```

# Use execution interceptors in the AWS SDK for Java 2.x
<a name="interceptors"></a>

Execution interceptors in the AWS SDK for Java 2.x hook into the request and response lifecycle to perform custom logic at various stages of API call execution. Use interceptors to implement cross-cutting concerns such as logging, metrics collection, request modification, debugging, and error handling.

Interceptors implement the [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/interceptor/ExecutionInterceptor.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/interceptor/ExecutionInterceptor.html) interface, which provides hooks for different phases of request execution.

## Interceptor lifecycle
<a name="interceptor-lifecycle"></a>

The `ExecutionInterceptor` interface provides methods that are called at specific points during request execution:
+ `beforeExecution` - Called before the request executes
+ `modifyRequest` - Modifies the SDK request object
+ `beforeMarshalling` - Called before the request marshals to HTTP
+ `afterMarshalling` - Called after the request marshals to HTTP
+ `modifyHttpRequest` - Modifies the HTTP request
+ `beforeTransmission` - Called before the HTTP request sends
+ `afterTransmission` - Called after the HTTP response is received
+ `modifyHttpResponse` - Modifies the HTTP response
+ `beforeUnmarshalling` - Called before the HTTP response unmarshals
+ `afterUnmarshalling` - Called after the HTTP response unmarshals
+ `modifyResponse` - Modifies the SDK response object
+ `afterExecution` - Called after successful request execution
+ `onExecutionFailure` - Called when request execution fails

## Register interceptors
<a name="registering-interceptors"></a>

Register interceptors when you build a service client using the `overrideConfiguration` method. You can register multiple interceptors, and they execute in the order you register them.

```
// Register a single interceptor.
SqsClient client = SqsClient.builder()
    .overrideConfiguration(c -> c.addExecutionInterceptor(new LoggingInterceptor()))
    .build();

// Register multiple interceptors.
S3Client s3Client = S3Client.builder()
    .overrideConfiguration(config -> config
        .addExecutionInterceptor(new TimingInterceptor())
        .addExecutionInterceptor(new LoggingInterceptor())
        .addExecutionInterceptor(new RequestModificationInterceptor()))
    .build();
```

## Interceptor example
<a name="interceptor-examples"></a>

The following class demonstrates how to use execution interceptors to add cross-cutting concerns like logging, performance monitoring, and request modification to your S3 operations without changing your core business logic.

This example shows you how to register multiple interceptors on an S3 client and see them in action during real AWS API calls.

### Imports
<a name="interceptor-example-imports"></a>

```
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.awscore.exception.AwsServiceException;
import software.amazon.awssdk.core.ApiName;
import software.amazon.awssdk.core.SdkRequest;
import software.amazon.awssdk.core.interceptor.Context;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.SdkHttpResponse;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.ListBucketsResponse;

import java.time.Duration;
import java.time.Instant;
```

```
public class S3InterceptorsDemo {
    private static final Logger logger = LoggerFactory.getLogger(S3InterceptorsDemo.class);

    public static void main(String[] args) {
        logger.info("=== AWS SDK for Java v2 - S3 Interceptors Demo ===");

        // Create an S3 client with multiple interceptors.
        S3Client s3Client = S3Client.builder()
            .overrideConfiguration(config -> config
                .addExecutionInterceptor(new TimingInterceptor())
                .addExecutionInterceptor(new LoggingInterceptor())
                .addExecutionInterceptor(new RequestModificationInterceptor()))
            .build();

        try {
            logger.info("Starting S3 operations with interceptors...");

            // Operation 1: List buckets.
            logger.info("Operation 1: Listing S3 buckets");
            logger.info("----------------------------------------");
            ListBucketsResponse listBucketsResponse = s3Client.listBuckets();
            logger.info("Found {} buckets", listBucketsResponse.buckets().size());

            // Operation 2: Try to access a bucket that likely doesn't exist.
            logger.info("Operation 2: Checking non-existent bucket (demonstrating error interceptor)");
            logger.info("----------------------------------------");
            try {
                s3Client.headBucket(HeadBucketRequest.builder()
                    .bucket("amzn-s3-demo-bucket-that-does-not-exist-1234")
                    .build());
            } catch (Exception e) {
                logger.info("Expected error occurred (interceptor should have logged it)");
            }

        } catch (Exception e) {
            logger.error(" Error during S3 operations: {}", e.getMessage(), e);
        } finally {
            s3Client.close();
            logger.info("Demo completed - S3 client closed");
        }
    }

    // Logging interceptor.
    private static class LoggingInterceptor implements ExecutionInterceptor {
        private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);

        @Override
        public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
            logger.info("[LOGGING] Starting request: {}", context.request().getClass().getSimpleName());
        }

        @Override
        public void afterExecution(Context.AfterExecution context, ExecutionAttributes executionAttributes) {
            logger.info("[LOGGING] Completed request: {}", context.request().getClass().getSimpleName());
        }

        @Override
        public void onExecutionFailure(Context.FailedExecution context, ExecutionAttributes executionAttributes) {
            logger.error("[LOGGING] Request failed: {}", context.request().getClass().getSimpleName());
            if (context.exception() instanceof AwsServiceException) {
                AwsServiceException ase = (AwsServiceException) context.exception();
                if (ase.awsErrorDetails().errorCode() != null) {
                    SdkHttpResponse httpResponse = ase.awsErrorDetails().sdkHttpResponse();
                    logger.error("   HTTP Status: {}", httpResponse.statusCode());
                    logger.error("   Error Code: {}", ase.awsErrorDetails().errorCode());
                    logger.error("   Error Message: {}", ase.awsErrorDetails().errorMessage());
                }
            }
        }
    }

    // Performance timing interceptor.
    private static class TimingInterceptor implements ExecutionInterceptor {
        private static final Logger logger = LoggerFactory.getLogger(TimingInterceptor.class);
        private Instant startTime;

        @Override
        public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
            startTime = Instant.now();
            logger.info("⏱️  [TIMING] Request started at: {}", startTime);
        }

        @Override
        public void afterExecution(Context.AfterExecution context, ExecutionAttributes executionAttributes) {
            if (startTime != null) {
                Duration duration = Duration.between(startTime, Instant.now());
                logger.info("⏱️  [TIMING] Request completed in: {}ms", duration.toMillis());
            }
        }

        @Override
        public void onExecutionFailure(Context.FailedExecution context, ExecutionAttributes executionAttributes) {
            if (startTime != null) {
                Duration duration = Duration.between(startTime, Instant.now());
                logger.warn("⏱️  [TIMING] Request failed after: {}ms", duration.toMillis());
            }
        }
    }

    // Request modification interceptor
    private static class RequestModificationInterceptor implements ExecutionInterceptor {
        private static final Logger logger = LoggerFactory.getLogger(RequestModificationInterceptor.class);

        @Override
        public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
            SdkRequest originalRequest = context.request();
            logger.info("[MODIFY] Modifying request: {}", originalRequest.getClass().getSimpleName());

            // For ListBucketsRequest, we can't modify much since it has no settable properties
            // For HeadBucketRequest, we can demonstrate modifying the request
            if (originalRequest instanceof HeadBucketRequest) {
                HeadBucketRequest headRequest = (HeadBucketRequest) originalRequest;

                // Create a new request with an API name added.
                return HeadBucketRequest.builder()
                        .bucket(headRequest.bucket())
                        .overrideConfiguration(b -> b.addApiName(ApiName.builder()
                                .name("My-API")
                                .version("1.0")
                                .build()))
                        .build();
            }
            logger.info("Not a HeadBucketRequest, returning original request");
            return originalRequest;
        }

        @Override
        public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
            logger.info("[MODIFY] Adding custom HTTP headers");
            return context.httpRequest().toBuilder()
                .putHeader("X-Custom-Header", "S3InterceptorDemo")
                .putHeader("X-Request-ID", java.util.UUID.randomUUID().toString())
                .build();
        }
    }
}
```

### Maven pom file
<a name="interceptor-example-pom"></a>

```
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>org.example</groupId>
    <artifactId>interceptors-examples</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <name>interceptors-examples</name>
    <description>Demonstration of execution interceptors in AWS SDK for Java v2</description>
    
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <aws.java.sdk.version>2.31.62</aws.java.sdk.version>
        <exec.mainClass>org.example.S3InterceptorsDemo</exec.mainClass>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>${aws.java.sdk.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-bom</artifactId>
                <version>2.23.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.13</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-1.2-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <!-- Compiler Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>
            
            <!-- Surefire Plugin for running tests -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>
            
            <!-- Exec Plugin for running the main class -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <mainClass>${exec.mainClass}</mainClass>
                </configuration>
            </plugin>
            
            <!-- Shade Plugin to create executable JAR -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.4.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>${exec.mainClass}</mainClass>
                                </transformer>
                            </transformers>
                            <createDependencyReducedPom>false</createDependencyReducedPom>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
```

## Best practices
<a name="interceptor-best-practices"></a>
+ **Keep interceptors lightweight** - Interceptors execute for every request, so avoid heavy computations or blocking operations that could impact performance.
+ **Handle exceptions gracefully** - If your interceptor throws an exception, it causes the entire request to fail. Always use try-catch blocks for potentially failing operations.
+ **Order matters** - Interceptors execute in the order you register them. Consider the dependencies between your interceptors when you register them.
+ **Use ExecutionAttributes for state** - If you need to pass data between different interceptor methods, use `ExecutionAttributes` rather than instance variables to ensure thread safety.
+ **Be mindful of sensitive data** - When you log requests and responses, be careful not to log sensitive information such as credentials or personal data.

## Context objects
<a name="interceptor-context-objects"></a>

Each interceptor method receives a context object that provides access to request and response information at different stages of execution:
+ `Context.BeforeExecution` - Provides access to the original SDK request
+ `Context.ModifyRequest` - Modifies the SDK request
+ `Context.ModifyHttpRequest` - Modifies the HTTP request
+ `Context.AfterExecution` - Provides access to both request and response
+ `Context.FailedExecution` - Provides access to the request and the exception that occurred