# Java SDK logging and error handling Configure logging and handle errors and exceptions in the Java SDK. For best observability, use an Application Performance Monitoring (APM) service. For server-side logs, integrate [Platform Insights](/api/platform-insights.md) with your APM provider. ## Exceptions The Java SDK uses exceptions from the Java Development Kit (such as [IllegalArgumentException](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalArgumentException.html)) and provides its own exceptions which inherit from [BaseException](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/error/BaseException.html). - Problems related to the [ApiHttpClient](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/ApiHttpClient.html) result in an [ApiHttpException](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/ApiHttpException.html), which is the base exception for all error responses (HTTP status codes `4xx` and `5xx`). - [ApiClientException](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/error/ApiClientException.html) indicates recoverable client-side errors (HTTP status codes `4xx`). - [ApiServerException](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/error/ApiServerException.html) represents server errors (HTTP status codes `5xx`). - JSON serializing and deserializing problems result in a [JsonException](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/utils/json/JsonException.html). ## Errors If a command cannot run due to unfulfilled preconditions, one error response with multiple errors can be returned (for more information, see [HTTP API Errors](/api/errors.md)). The Java SDK then adds a [BadRequestException](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/error/BadRequestException.html) into a [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html). ## Custom HttpExceptionFactory The Java SDK treats responses with HTTP status codes `4xx` and `5xx` as errors and raises exceptions. The [DefaultHttpExceptionFactory](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/error/DefaultHttpExceptionFactory.html) creates these exceptions. To customize the handling, you must implement this interface and override its default methods as needed. ```java title="Implement a custom HttpExceptionFactory" public class HttpExceptionFactoryTest { static class CustomExceptionFactory implements HttpExceptionFactory { @Override public ApiHttpException create( ApiHttpRequest request, ApiHttpResponse response ) { return new ApiHttpException( response.getStatusCode(), request.getSecuredBody(), response.getHeaders(), "something bad happened", response, request ); } @Override public ResponseSerializer getResponseSerializer() { return ResponseSerializer.of(); } } @Test public void customFactory() { ProjectApiRoot client = ApiRootBuilder .of() .defaultClient(ServiceRegion.GCP_EUROPE_WEST1.getApiUrl()) .withHttpExceptionFactory(CustomExceptionFactory::new) .build("my-project-key"); assertThatExceptionOfType(ApiHttpException.class) .isThrownBy(() -> client.get().executeBlocking()) .withMessageStartingWith("detailMessage: something bad happened"); } } ``` ## Logging Internal logging used by the commercetools client itself uses a [SLF4J](https://github.com/qos-ch/slf4j) logger named `commercetools`. The default logger middleware logs the following information per level: - **Error**: logs HTTP method, URI, and response status code for [ApiHttpException](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/ApiHttpException.html), and cause and exceptions for all other exceptions. - **Information**: logs HTTP method, URI, response status code, and any deprecation notices. You can configure the log level when instantiating the [InternalLoggerMiddleware](/dev-tooling/java-sdk-middleware.md#internalloggermiddleware). - **Debug**: logs string representations of the request and the response, including headers and body, with sensitive data like auth tokens and passwords, redacted. - **Trace**: Logs request and response with pretty-printed output, with sensitive information redacted. ## Logger hierarchy The loggers form a hierarchy separated by a period. The root logger is `commercetools`. The child loggers of commercetools are the endpoints. For example `commercetools.categories` for Categories and `commercetools.product-types` for Product Types. The grandchild loggers refer to the action. `commercetools.categories.request` refers to performing requests per HTTPS to commercetools for Categories, `commercetools.categories.response` refers to the responses. The logger makes use of different log levels, so for example `commercetools.categories.response` logs the HTTP response on debug level: ```java title="Example debug log output" [OkHttp https://api.europe-west1.gcp.commercetools.com/...] DEBUG commercetools.categories.response - io.vrap.rmf.base.client.ApiHttpResponse@33e37acd[statusCode=200,headers=...,textInterpretedBody={"limit":20,"offset":0,"count":4,"total":4,"results":[{"id":"ca7f64dc-ab41-4e7f-b65b-bfc25bf01111","version":1,"createdAt":"2021-01-06T09:21:55.445Z","lastModifiedAt":"2021-01-06T09:21:55.445Z","key":"random-key-15aab6ee-9a48-4fdc-a8c3-8ff9ff390d60","name":{"key-6bc3cc62-1995-43f4":"value-random-string-c3ff7f1a-6371-4c0c-a3b9-5060eca08b8a"},"slug":{"key-6bc3cc62-1995-43f4":"value-random-string-c3ff7f1a-6371-4c0c-a3b9-5060eca08b8a"},"description":{"key-6bc3cc62-1995-43f4":"value-random-string-c3ff7f1a-6371-4c0c-a3b9-5060eca08b8a"},"ancestors":[],"orderHint":"random-string-a99e6941-3225-4766-923a-4a654652532f","externalId":"random-id-100b3851-29b4-47c1-aef3-860b4cd28f54"}]}] ``` Additionally, `commercetools.categories.response` logs the formatted HTTP response on trace level: ```java title="Example trace log output" [OkHttp https://api.europe-west1.gcp.commercetools.com/...] TRACE commercetools.categories.response - 200 { "limit" : 20, "offset" : 0, "count" : 4, "total" : 4, "results" : [ { "id" : "bcb15128-b69e-47b6-81c4-1ea5f9a63b83", "version" : 1, "createdAt" : "2021-01-06T09:21:50.485Z", "lastModifiedAt" : "2021-01-06T09:21:50.485Z", "createdBy" : { "clientId" : "h-QvaF3NpsjPBWeXa6TUOnq0", "isPlatformClient" : false }, "key" : "random-key-f45535f5-1111-4bfb-98ac-164234ac2c73", "name" : { "key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a" }, "slug" : { "key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a" }, "description" : { "key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a" }, "ancestors" : [ ], "orderHint" : "random-string-6b88f299-d4ca-491a-9d7c-3463e718c8d2", "externalId" : "random-id-b98a5ab4-5413-40b3-8119-eb5ac2b5afbb", "metaTitle" : { "key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a" }, "metaKeywords" : { "key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a" }, "metaDescription" : { "key-b7d87008-9526-47b3-8b80" : "value-random-string-baf1a1ae-3726-4573-bec5-2c53c7d1114a" } }, { ... } ] } ``` `commercetools.products.responses.queries` only logs HTTP GET requests and `commercetools.products.responses.commands` only logs HTTP POST/DELETE requests. ```java title="Example log output for commands and queries" [pool-1-thread-1] DEBUG commercetools.products.request.commands - io.vrap.rmf.base.client.ApiHttpRequest@1d2c6948[method=POST,uri="https://api.europe-west1.gcp.commercetools.com/test-php-dev-integration-1/products",headers=[...],textInterpretedBody={"productType":{"id":"cda39953-23af-4e85-abb0-5b89517ec5f2","typeId":"product-type"},"name":{"random-string-b66de021-d2fa-4262-8837-94a6992a8cdc":"random-string-da28a010-e66b-49d4-a18b-f1bfc145d2f6"},...}] [pool-1-thread-1] DEBUG commercetools.products.request.queries - io.vrap.rmf.base.client.ApiHttpRequest@53667fdb[method=GET,uri="https://api.europe-west1.gcp.commercetools.com/test-php-dev-integration-1/products/ef745227-b115-4132-ba2c-4e46db80df79",headers=[...],textInterpretedBody=empty body] ``` ## Configure logging The [ClientBuilder](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/ClientBuilder.html) allows customization of the log levels used for different events. By default, responses are logged at `INFO` level and errors at `ERROR` level. Use the `withInternalLoggerFactory()` method to change these defaults: ```java title="Configure log levels" ProjectApiRoot apiRoot = ApiRootBuilder .of() .defaultClient( ClientCredentials .of() .withClientId("your-client-id") .withClientSecret("your-client-secret") .build(), ServiceRegion.GCP_EUROPE_WEST1 ) .withInternalLoggerFactory( InternalLoggerFactory.of(Level.DEBUG), Level.DEBUG, Level.WARN ) .build("my-project-key"); ``` ## Mapped Diagnostic Context (MDC) The SDK uses [CompletableFutures](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) extensively, which means futures can execute on different threads. If your application uses [SLF4J MDC](https://www.slf4j.org/api/org/slf4j/MDC.html), the context may be lost when switching threads. The SDK supports attaching a [Context](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/Context.html) to a client, requests, and responses through the [ContextAware](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/io/vrap/rmf/base/client/ContextAware.html) interface. [ProjectApiRoot](https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/com/commercetools/api/client/ProjectApiRoot.html) allows adding a `Context` to create a context-aware root from a global instance: ```java title="Create a context-aware API root for MDC propagation" Map mdcContext = MDC.getCopyOfContextMap(); MDCContext context = MDCContext.of(mdcContext); ProjectApiRoot contextAwareRoot = apiRoot.withContext(context); ``` The [InternalLoggerMiddleware](/dev-tooling/java-sdk-middleware.md#internalloggermiddleware) restores the MDC before logging and cleans up afterwards to avoid polluting threads with unrelated context data. The same applies to [ConcurrentModificationMiddleware](/dev-tooling/java-sdk-middleware.md#concurrentmodificationmiddleware). ## Related pages - [Area overview page with navigation](/dev-tooling.md) - [Previous page: Best practices](/dev-tooling/java-sdk-best-practices.md) - [Next page: Query Predicate builders](/dev-tooling/java-sdk-predicates.md) - [Search documentation and API specs](/search.md)