From 848e2b450cad2ed781bb6787ed12a8ab573fa53c Mon Sep 17 00:00:00 2001 From: Ronja Quensel <72978761+ronjaquensel@users.noreply.github.com> Date: Mon, 28 Jun 2021 13:37:19 +0200 Subject: [PATCH] feat: log route errors to config manager (#43) * feat: add dead letter channel for sending error information to the ConfigManager * chore: log error if sending error logs to ConfigManager fails * refactor: rename ErrorDto to RouteError * fix: set HTTP method to POST for sending error logs to ConfigManager * docs: update CHANGELOG.md * docs: increase version in POM --- CHANGELOG.md | 6 ++- pom.xml | 2 +- .../config/context/ErrorHandlerConfig.java | 28 ++++++++++++ .../errorhandling/DeadLetterChannel.java | 44 +++++++++++++++++++ .../DeadLetterChannelProcessor.java | 42 ++++++++++++++++++ .../camel/errorhandling/RouteError.java | 32 ++++++++++++++ src/main/resources/application.properties | 3 ++ 7 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/config/context/ErrorHandlerConfig.java create mode 100644 src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/DeadLetterChannel.java create mode 100644 src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/DeadLetterChannelProcessor.java create mode 100644 src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/RouteError.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bfdab6..cc5e581 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ All notable changes to this project will be documented in this file. -## [1.1.2] - +## [1.2.0] - 2021-06-28 + +### Added + +- Log errors during route execution to the Configuration Manager. ### Changed diff --git a/pom.xml b/pom.xml index 39a479e..18bef57 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ - 1.1.2 + 1.2.0 info@dataspace-connector.de diff --git a/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/config/context/ErrorHandlerConfig.java b/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/config/context/ErrorHandlerConfig.java new file mode 100644 index 0000000..153a4fb --- /dev/null +++ b/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/config/context/ErrorHandlerConfig.java @@ -0,0 +1,28 @@ +package de.fraunhofer.isst.dataspaceconnector.camel.config.context; + +import org.apache.camel.builder.DeadLetterChannelBuilder; +import org.apache.camel.processor.errorhandler.RedeliveryPolicy; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Defines beans required for error handling. + */ +@Configuration +public class ErrorHandlerConfig { + + /** + * Returns a DeadLetterChannelBuilder instance that routes all failed exchanges to the + * designated error handler route. + * + * @return the DeadLetterChannelBuilder + */ + @Bean + public DeadLetterChannelBuilder errorHandler() { + final var dlcBuilder = new DeadLetterChannelBuilder(); + dlcBuilder.setDeadLetterUri("direct:deadLetterChannel"); + dlcBuilder.setRedeliveryPolicy(new RedeliveryPolicy().disableRedelivery()); + return dlcBuilder; + } + +} diff --git a/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/DeadLetterChannel.java b/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/DeadLetterChannel.java new file mode 100644 index 0000000..88d12be --- /dev/null +++ b/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/DeadLetterChannel.java @@ -0,0 +1,44 @@ +package de.fraunhofer.isst.dataspaceconnector.camel.errorhandling; + +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Defines the route used for handling errors, which will send an error description to the + * Configuration Manager endpoint defined in application.properties. + */ +@Component +public class DeadLetterChannel extends RouteBuilder { + + /** + * The Configuration Manager endpoint for logging errors. + */ + @Value("${config-manager.error-api.url}") + private String errorLogEndpoint; + + /** + * Configures the error route. The error route uses a processor to create an {@link RouteError} + * and then sends this to the Configuration Manager. + * + * @throws Exception if an error occurs writing the ErrorDto as JSON. + */ + @Override + public void configure() throws Exception { + onException(Exception.class) + .process(exchange -> { + final var cause = exchange + .getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + log.warn("Failed to send error logs to Configuration Manager: {}", + cause.getMessage()); + }) + .handled(true); + + from("direct:deadLetterChannel") + .process("dlcProcessor") + .setHeader(Exchange.HTTP_METHOD, constant("POST")) + .to(errorLogEndpoint); + } + +} diff --git a/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/DeadLetterChannelProcessor.java b/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/DeadLetterChannelProcessor.java new file mode 100644 index 0000000..21a4be4 --- /dev/null +++ b/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/DeadLetterChannelProcessor.java @@ -0,0 +1,42 @@ +package de.fraunhofer.isst.dataspaceconnector.camel.errorhandling; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.log4j.Log4j2; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.springframework.stereotype.Component; + +/** + * Prepares an {@link RouteError} for a failed exchange. + */ +@Component("dlcProcessor") +@Log4j2 +public class DeadLetterChannelProcessor implements Processor { + + /** + * Writes the ErrorDto as JSON. + */ + private final ObjectMapper objectMapper = new ObjectMapper(); + + /** + * Reads the route's ID, the endpoint where the exchange failed and the exception that caused + * the failure from an Exchange object and creates an {@link RouteError}. The ErrorDto is set as + * the body of the exchange's message. + * + * @param exchange the failed exchange. + * @throws Exception if an error occurs writing the error DTO as JSON. + */ + @Override + public void process(final Exchange exchange) throws Exception { + final var routeId = exchange.getProperty("CamelFailureRouteId", String.class); + final var failureEndpoint = exchange.getProperty("CamelFailureEndpoint", String.class); + final var cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + + final var errorDto = new RouteError(routeId, failureEndpoint, cause.getMessage()); + + log.warn("Caught an exception during route execution: {}", errorDto); + + exchange.getIn().setBody(objectMapper.writeValueAsString(errorDto)); + } + +} diff --git a/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/RouteError.java b/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/RouteError.java new file mode 100644 index 0000000..4fd2b1d --- /dev/null +++ b/src/main/java/de/fraunhofer/isst/dataspaceconnector/camel/errorhandling/RouteError.java @@ -0,0 +1,32 @@ +package de.fraunhofer.isst.dataspaceconnector.camel.errorhandling; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * DTO for sending error information to the Configuration Manager. + */ +@Getter +@Setter +@AllArgsConstructor +@ToString +public class RouteError { + + /** + * ID of the route where an error occurred. + */ + private String routeId; + + /** + * The endpoint where the error occurred. + */ + private String endpoint; + + /** + * The exception message. + */ + private String message; + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 4cf5fa9..5d2df72 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -18,3 +18,6 @@ server.ssl.key-alias=1 # HTTP component truststore http.truststore.path=classpath:truststore.p12 http.truststore.password=password + +# Configuration Manager +config-manager.error-api.url=http://localhost:8081/api/ui/route/error