From 78d0dc3b2d7f09ad7d6aa20a080cb028f82109d0 Mon Sep 17 00:00:00 2001 From: Christopher Grote Date: Thu, 5 Dec 2024 22:57:28 +0000 Subject: [PATCH] Adds logging of underlying causes for back-end errors Signed-off-by: Christopher Grote --- .../java/com/atlan/exception/ErrorCode.java | 14 +++--- .../java/com/atlan/model/core/AtlanError.java | 43 +++++++++++++++++++ .../atlan/net/LiveAtlanResponseGetter.java | 27 +++++++----- 3 files changed, 67 insertions(+), 17 deletions(-) diff --git a/sdk/src/main/java/com/atlan/exception/ErrorCode.java b/sdk/src/main/java/com/atlan/exception/ErrorCode.java index 0333a7a369..32e3ea850f 100644 --- a/sdk/src/main/java/com/atlan/exception/ErrorCode.java +++ b/sdk/src/main/java/com/atlan/exception/ErrorCode.java @@ -25,7 +25,7 @@ public enum ErrorCode implements ExceptionMessageSet { INVALID_REQUEST_PASSTHROUGH( 400, "ATLAN-JAVA-400-000", - "Server responded with an invalid request -- {0}: {1}", + "Server responded with an invalid request -- {0}: {1} -- caused by: {2}", "Check the details of the server's message to correct your request."), MISSING_GROUP_ID( 400, @@ -281,7 +281,7 @@ public enum ErrorCode implements ExceptionMessageSet { AUTHENTICATION_PASSTHROUGH( 401, "ATLAN-JAVA-401-000", - "Server responded with an authentication error -- {0}: {1}", + "Server responded with an authentication error -- {0}: {1} -- caused by: {2}", "Your API or bearer token is either invalid or has expired, or you are attempting to access a URL you are not authorized to access. Ensure you are using a valid token, that there is no service outage for the underlying authorization component, or try obtaining a new token and try again."), NO_API_TOKEN( 401, @@ -315,7 +315,7 @@ public enum ErrorCode implements ExceptionMessageSet { PERMISSION_PASSTHROUGH( 403, "ATLAN-JAVA-403-000", - "Server responded with a permission error -- {0}: {1}", + "Server responded with a permission error -- {0}: {1} -- caused by: {2}", "Check the details of the server's message to correct your request."), UNABLE_TO_IMPERSONATE( 403, @@ -331,7 +331,7 @@ public enum ErrorCode implements ExceptionMessageSet { NOT_FOUND_PASSTHROUGH( 404, "ATLAN-JAVA-404-000", - "Server responded with a not found error -- {0}: {1}", + "Server responded with a not found error -- {0}: {1} -- caused by: {2}", "Check the details of the server's message to correct your request."), ASSET_NOT_FOUND_BY_GUID( @@ -503,7 +503,7 @@ public enum ErrorCode implements ExceptionMessageSet { CONFLICT_PASSTHROUGH( 409, "ATLAN-JAVA-409-000", - "Server responded with a conflict -- {0}: {1}", + "Server responded with a conflict -- {0}: {1} -- caused by: {2}", "Check the details of the server's message to correct your request."), RESERVED_SERVICE_TYPE( 409, @@ -514,13 +514,13 @@ public enum ErrorCode implements ExceptionMessageSet { RATE_LIMIT_PASSTHROUGH( 429, "ATLAN-JAVA-429-000", - "Server responded with a rate limit violation -- {0}: {1}", + "Server responded with a rate limit violation -- {0}: {1} -- caused by: {2}", "Check the details of the server's message to correct your request."), ERROR_PASSTHROUGH( 500, "ATLAN-JAVA-500-000", - "Server responded with an error -- {0}: {1}", + "Server responded with an error -- {0}: {1} -- caused by: {2}", "Check the details of the server's message to correct your request."), DUPLICATE_CUSTOM_ATTRIBUTES( diff --git a/sdk/src/main/java/com/atlan/model/core/AtlanError.java b/sdk/src/main/java/com/atlan/model/core/AtlanError.java index b97aeac427..0a731943e2 100644 --- a/sdk/src/main/java/com/atlan/model/core/AtlanError.java +++ b/sdk/src/main/java/com/atlan/model/core/AtlanError.java @@ -2,7 +2,10 @@ Copyright 2022 Atlan Pte. Ltd. */ package com.atlan.model.core; +import com.atlan.serde.Serde; import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.IOException; +import java.util.List; import java.util.Map; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -30,6 +33,9 @@ public class AtlanError extends AtlanObject { @JsonProperty("error_description") String errorDescription; + /** Unique ID for the error (from the back-end). */ + String errorId; + /** A human-readable message providing more details about the error. */ String message; @@ -57,6 +63,9 @@ public class AtlanError extends AtlanObject { /** Path attempted to access for an unauthorized call. */ String url; + /** Underlying causes noted for the error, if any. */ + List causes; + /** * Find the code within the error. * @@ -97,4 +106,38 @@ public String findMessage() { return ""; } } + + /** + * Retrieve the underlying causes as a JSON string. + * + * @return the underlying causes of the error as a JSON string. + */ + public String renderCauses() { + if (causes != null && !causes.isEmpty()) { + try { + return Serde.allInclusiveMapper.writeValueAsString(causes); + } catch (IOException e) { + return "[{\"errorMessage\":\"Unable to render causes.\"}]"; + } + } else { + return "[]"; + } + } + + /** Details about an underlying cause for an error. */ + @Getter + @EqualsAndHashCode(callSuper = false) + @ToString(callSuper = true) + public static final class Cause extends AtlanObject { + private static final long serialVersionUID = 2L; + + /** Back-end component or class that was an underlying cause for the error. */ + String errorType; + + /** Message from the back-end component or class about the cause of the error. */ + String errorMessage; + + /** Specific location in the back-end code for the cause of the error. */ + String location; + } } diff --git a/sdk/src/main/java/com/atlan/net/LiveAtlanResponseGetter.java b/sdk/src/main/java/com/atlan/net/LiveAtlanResponseGetter.java index 72a2f243b2..041d6cd6a4 100644 --- a/sdk/src/main/java/com/atlan/net/LiveAtlanResponseGetter.java +++ b/sdk/src/main/java/com/atlan/net/LiveAtlanResponseGetter.java @@ -361,30 +361,37 @@ private static void raiseError(int code, AtlanError error) throws AtlanException switch (code) { case 400: exception = new InvalidRequestException( - ErrorCode.INVALID_REQUEST_PASSTHROUGH, error.findCode(), error.findMessage()); + ErrorCode.INVALID_REQUEST_PASSTHROUGH, + error.findCode(), + error.findMessage(), + error.renderCauses()); break; case 404: - exception = - new NotFoundException(ErrorCode.NOT_FOUND_PASSTHROUGH, error.findCode(), error.findMessage()); + exception = new NotFoundException( + ErrorCode.NOT_FOUND_PASSTHROUGH, error.findCode(), error.findMessage(), error.renderCauses()); break; case 401: exception = new AuthenticationException( - ErrorCode.AUTHENTICATION_PASSTHROUGH, error.findCode(), error.findMessage()); + ErrorCode.AUTHENTICATION_PASSTHROUGH, + error.findCode(), + error.findMessage(), + error.renderCauses()); break; case 403: exception = new PermissionException( - ErrorCode.PERMISSION_PASSTHROUGH, error.findCode(), error.findMessage()); + ErrorCode.PERMISSION_PASSTHROUGH, error.findCode(), error.findMessage(), error.renderCauses()); break; case 409: - exception = - new ConflictException(ErrorCode.CONFLICT_PASSTHROUGH, error.findCode(), error.findMessage()); + exception = new ConflictException( + ErrorCode.CONFLICT_PASSTHROUGH, error.findCode(), error.findMessage(), error.renderCauses()); break; case 429: - exception = - new RateLimitException(ErrorCode.RATE_LIMIT_PASSTHROUGH, error.findCode(), error.findMessage()); + exception = new RateLimitException( + ErrorCode.RATE_LIMIT_PASSTHROUGH, error.findCode(), error.findMessage(), error.renderCauses()); break; default: - exception = new ApiException(ErrorCode.ERROR_PASSTHROUGH, null, error.findCode(), error.findMessage()); + exception = new ApiException( + ErrorCode.ERROR_PASSTHROUGH, null, error.findCode(), error.findMessage(), error.renderCauses()); break; }