From 9c43d85f3698e6d5210e860760856b92cfa39450 Mon Sep 17 00:00:00 2001 From: Walyson Moises <125759796+244Walyson@users.noreply.github.com> Date: Sat, 20 Jul 2024 07:42:12 -0300 Subject: [PATCH] feat: Distributed tracing (#3006) * added microservices distributed tracing pattern * feat: Implement Microservice pattern: Distributed tracing #2693 --- microservices-distributed-tracing/README.md | 201 ++++++++++++++++++ .../etc/microservices-distributed-tracing.png | Bin 0 -> 27706 bytes .../microservices-distributed-tracing.puml | 31 +++ ...microservices-distributed-tracing.urm.puml | 31 +++ .../etc/order-microservice.png | Bin 0 -> 13152 bytes .../etc/order-microservice.puml | 15 ++ .../etc/order-microservice.urm.puml | 15 ++ .../order-microservice/pom.xml | 63 ++++++ .../com/iluwatar/order/microservice/Main.java | 80 +++++++ .../order/microservice/OrderController.java | 64 ++++++ .../order/microservice/OrderService.java | 103 +++++++++ .../src/main/resources/application.properties | 33 +++ .../iluwatar/order/microservice/MainTest.java | 39 ++++ .../microservice/OrderControllerTest.java | 76 +++++++ .../order/microservice/OrderServiceTest.java | 192 +++++++++++++++++ .../etc/payment-microservice.png | Bin 0 -> 10777 bytes .../etc/payment-microservice.puml | 11 + .../etc/payment-microservice.urm.puml | 11 + .../payment-microservice/pom.xml | 56 +++++ .../iluwatar/payment/microservice/Main.java | 79 +++++++ .../microservice/PaymentController.java | 53 +++++ .../src/main/resources/application.properties | 32 +++ .../payment/microservice/MainTest.java | 39 ++++ .../microservice/ProductControllerTest.java | 68 ++++++ microservices-distributed-tracing/pom.xml | 82 +++++++ .../etc/product-microservice.png | Bin 0 -> 10246 bytes .../etc/product-microservice.puml | 10 + .../etc/product-microservice.urm.puml | 10 + .../product-microservice/pom.xml | 56 +++++ .../microservice/microservice/Main.java | 79 +++++++ .../microservice/ProductController.java | 53 +++++ .../src/main/resources/application.properties | 33 +++ .../product/microservice/MainTest.java | 40 ++++ .../microservice/ProductControllerTest.java | 68 ++++++ pom.xml | 1 + 35 files changed, 1724 insertions(+) create mode 100644 microservices-distributed-tracing/README.md create mode 100644 microservices-distributed-tracing/etc/microservices-distributed-tracing.png create mode 100644 microservices-distributed-tracing/etc/microservices-distributed-tracing.puml create mode 100644 microservices-distributed-tracing/etc/microservices-distributed-tracing.urm.puml create mode 100644 microservices-distributed-tracing/order-microservice/etc/order-microservice.png create mode 100644 microservices-distributed-tracing/order-microservice/etc/order-microservice.puml create mode 100644 microservices-distributed-tracing/order-microservice/etc/order-microservice.urm.puml create mode 100644 microservices-distributed-tracing/order-microservice/pom.xml create mode 100644 microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/Main.java create mode 100644 microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/OrderController.java create mode 100644 microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/OrderService.java create mode 100644 microservices-distributed-tracing/order-microservice/src/main/resources/application.properties create mode 100644 microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/MainTest.java create mode 100644 microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/OrderControllerTest.java create mode 100644 microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/OrderServiceTest.java create mode 100644 microservices-distributed-tracing/payment-microservice/etc/payment-microservice.png create mode 100644 microservices-distributed-tracing/payment-microservice/etc/payment-microservice.puml create mode 100644 microservices-distributed-tracing/payment-microservice/etc/payment-microservice.urm.puml create mode 100644 microservices-distributed-tracing/payment-microservice/pom.xml create mode 100644 microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/Main.java create mode 100644 microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/PaymentController.java create mode 100644 microservices-distributed-tracing/payment-microservice/src/main/resources/application.properties create mode 100644 microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/MainTest.java create mode 100644 microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/ProductControllerTest.java create mode 100644 microservices-distributed-tracing/pom.xml create mode 100644 microservices-distributed-tracing/product-microservice/etc/product-microservice.png create mode 100644 microservices-distributed-tracing/product-microservice/etc/product-microservice.puml create mode 100644 microservices-distributed-tracing/product-microservice/etc/product-microservice.urm.puml create mode 100644 microservices-distributed-tracing/product-microservice/pom.xml create mode 100644 microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/Main.java create mode 100644 microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/ProductController.java create mode 100644 microservices-distributed-tracing/product-microservice/src/main/resources/application.properties create mode 100644 microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/MainTest.java create mode 100644 microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/ProductControllerTest.java diff --git a/microservices-distributed-tracing/README.md b/microservices-distributed-tracing/README.md new file mode 100644 index 000000000..14b34726f --- /dev/null +++ b/microservices-distributed-tracing/README.md @@ -0,0 +1,201 @@ +--- +title: "Microservices Distributed Tracing Pattern: Enhancing Visibility in Service Communication" +shortTitle: Distributed Tracing in Microservices +description: "Learn how the Distributed Tracing pattern enhances visibility into service communication across microservices. Discover its benefits, implementation examples, and best practices." +category: Integration +language: en +tag: + - Distributed tracing + - Microservices architecture + - Service communication + - Performance monitoring + - Scalability + - Observability +--- + +## Intent of Microservices Distributed Tracing Design Pattern + +Distributed tracing aims to monitor and track requests as they flow through different services in a microservices architecture, providing insights into performance, dependencies, and failures. + +## Also known as + +* Distributed Request Tracing +* End-to-End Tracing + +## Detailed Explanation of Microservices Distributed Tracing Pattern with Real-World Examples + +Real-world example + +> In an e-commerce platform, distributed tracing is used to track a customer's request from the moment they add an item to the cart until the order is processed and shipped. This helps in identifying bottlenecks, errors, and latency issues across different services. + +In plain words + +> Distributed tracing allows you to follow a request's journey through all the services it interacts with, providing insights into system performance and aiding in debugging. + +Wikipedia says + +> Tracing in software engineering refers to the process of capturing and recording information about the execution of a software program. This information is typically used by programmers for debugging purposes, and additionally, depending on the type and detail of information contained in a trace log, by experienced system administrators or technical-support personnel and by software monitoring tools to diagnose common problems with software. + +## Programmatic Example of Microservices Distributed Tracing in Java + + +This implementation shows how an e-commerce platform's `OrderService` interacts with both `PaymentService` and `ProductService`. When a customer places an order, the `OrderService` calls the `PaymentService` to process the payment and the `ProductService` to check the product inventory. Distributed tracing logs are generated for each of these interactions and can be viewed in the Zipkin interface to monitor the flow and performance of requests across these services. + +Here's the `Order microservice` implementation. + +```java +@Slf4j +@RestController +public class OrderController { + + private final OrderService orderService; + + public OrderController(final OrderService orderService) { + this.orderService = orderService; + } + + @PostMapping("/order") + public ResponseEntity processOrder(@RequestBody(required = false) String request) { + LOGGER.info("Received order request: {}", request); + var result = orderService.processOrder(); + LOGGER.info("Order processed result: {}", result); + return ResponseEntity.ok(result); + } +} +``` +```java +@Slf4j +@Service +public class OrderService { + + private final RestTemplateBuilder restTemplateBuilder; + + public OrderService(final RestTemplateBuilder restTemplateBuilder) { + this.restTemplateBuilder = restTemplateBuilder; + } + + public String processOrder() { + if (validateProduct() && processPayment()) { + return "Order processed successfully"; + } + return "Order processing failed"; + } + + Boolean validateProduct() { + try { + ResponseEntity productValidationResult = restTemplateBuilder + .build() + .postForEntity("http://localhost:30302/product/validate", "validating product", + Boolean.class); + LOGGER.info("Product validation result: {}", productValidationResult.getBody()); + return productValidationResult.getBody(); + } catch (ResourceAccessException | HttpClientErrorException e) { + LOGGER.error("Error communicating with product service: {}", e.getMessage()); + return false; + } + } + + Boolean processPayment() { + try { + ResponseEntity paymentProcessResult = restTemplateBuilder + .build() + .postForEntity("http://localhost:30301/payment/process", "processing payment", + Boolean.class); + LOGGER.info("Payment processing result: {}", paymentProcessResult.getBody()); + return paymentProcessResult.getBody(); + } catch (ResourceAccessException | HttpClientErrorException e) { + LOGGER.error("Error communicating with payment service: {}", e.getMessage()); + return false; + } + } +} +``` + +Here's the `Payment microservice` implementation. + +```java + +@Slf4j +@RestController +public class PaymentController { + + @PostMapping("/payment/process") + public ResponseEntity payment(@RequestBody(required = false) String request) { + LOGGER.info("Received payment request: {}", request); + boolean result = true; + LOGGER.info("Payment result: {}", result); + return ResponseEntity.ok(result); + } +} +``` + +Here's the `Product microservice` implementation. + +```java +/** + * Controller for handling product validation requests. + */ +@Slf4j +@RestController +public class ProductController { + + /** + * Validates the product based on the request. + * + * @param request the request body containing product information (can be null) + * @return ResponseEntity containing the validation result (true) + */ + @PostMapping("/product/validate") + public ResponseEntity validateProduct(@RequestBody(required = false) String request) { + LOGGER.info("Received product validation request: {}", request); + boolean result = true; + LOGGER.info("Product validation result: {}", result); + return ResponseEntity.ok(result); + } +} +``` + +## When to Use the Microservices Distributed Tracing Pattern in Java + +* When you have a microservices architecture and need to monitor the flow of requests across multiple services. +* When troubleshooting performance issues or errors in a distributed system. +* When you need to gain insights into system bottlenecks and optimize overall performance. + + +## Microservices Distributed Tracing Pattern Java Tutorials + +* [Spring Boot - Tracing (Spring)](https://docs.spring.io/spring-boot/reference/actuator/tracing.html) +* [Reactive Observability (Spring Academy)](https://spring.academy/guides/microservices-observability-reactive-spring-boot-3) +* [Spring Cloud – Tracing Services with Zipkin (Baeldung)](https://dzone.com/articles/getting-started-with-spring-cloud-gateway) + +## Benefits and Trade-offs of Microservices Distributed Tracing Pattern + +Benefits: + +* Provides end-to-end visibility into requests. +* Helps in identifying performance bottlenecks. +* Aids in debugging and troubleshooting complex systems. + +Trade-offs: + +* Adds overhead to each request due to tracing data. +* Requires additional infrastructure (e.g., Zipkin, Jaeger) for collecting and visualizing traces. +* Can become complex to manage in large-scale systems. + +## Real-World Applications of Microservices Distributed Tracing Pattern in Java + +* Monitoring and troubleshooting e-commerce platforms. +* Performance monitoring in financial transaction systems. +* Observability in large-scale SaaS applications. + +## Related Java Design Patterns + +* [Log Aggregation Microservice](https://java-design-patterns.com/patterns/microservices-log-aggregation/) - Distributed tracing works well in conjunction with log aggregation to provide comprehensive observability and troubleshooting capabilities. +* [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/) - Distributed tracing can be used alongside the Circuit Breaker pattern to monitor and handle failures gracefully, preventing cascading failures in microservices. +* [API Gateway Microservice](https://java-design-patterns.com/patterns/microservices-api-gateway/) - The API Gateway pattern can be integrated with distributed tracing to provide a single entry point for tracing requests across multiple microservices. + +## References and Credits + +* [Building Microservices](https://amzn.to/3UACtrU) +* [OpenTelemetry Documentation](https://opentelemetry.io/docs/) +* [Distributed tracing (microservices.io)](https://microservices.io/patterns/observability/distributed-tracing.html) diff --git a/microservices-distributed-tracing/etc/microservices-distributed-tracing.png b/microservices-distributed-tracing/etc/microservices-distributed-tracing.png new file mode 100644 index 0000000000000000000000000000000000000000..00f06108b60a675425703ff65416060e93fe7820 GIT binary patch literal 27706 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 OrderService +OrderService --> PaymentController : processPayment() +OrderService --> ProductController : validateProduct() +} +@enduml \ No newline at end of file diff --git a/microservices-distributed-tracing/etc/microservices-distributed-tracing.urm.puml b/microservices-distributed-tracing/etc/microservices-distributed-tracing.urm.puml new file mode 100644 index 000000000..9c303f0dc --- /dev/null +++ b/microservices-distributed-tracing/etc/microservices-distributed-tracing.urm.puml @@ -0,0 +1,31 @@ +@startuml +!theme vibrant +package com.iluwatar.microservices-distributed-tracing { +package "Order Microservice" { + class OrderController { + +processOrder() + } + + class OrderService { + +validateProduct() + +processPayment() + } +} + +package "Payment Microservice" { + class PaymentController { + +processPayment() + } +} + +package "Product Microservice" { + class ProductController { + +validateProduct() + } +} + +OrderController --> OrderService +OrderService --> PaymentController : processPayment() +OrderService --> ProductController : validateProduct() +} +@enduml \ No newline at end of file diff --git a/microservices-distributed-tracing/order-microservice/etc/order-microservice.png b/microservices-distributed-tracing/order-microservice/etc/order-microservice.png new file mode 100644 index 0000000000000000000000000000000000000000..d2951e1ad8dbb27ca2c7fb6301faadc2d729c2fd GIT binary patch literal 13152 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 Kc+nFBpZ@~ke3kJ4 literal 0 HcmV?d00001 diff --git a/microservices-distributed-tracing/order-microservice/etc/order-microservice.puml b/microservices-distributed-tracing/order-microservice/etc/order-microservice.puml new file mode 100644 index 000000000..013138441 --- /dev/null +++ b/microservices-distributed-tracing/order-microservice/etc/order-microservice.puml @@ -0,0 +1,15 @@ +@startuml +!theme vibrant +package com.iluwatar.microservices-distributed-tracing { +package "Order Microservice" { + class OrderController { + +processOrder() + } + + class OrderService { + +validateProduct() + +processPayment() + } +} +} +@enduml \ No newline at end of file diff --git a/microservices-distributed-tracing/order-microservice/etc/order-microservice.urm.puml b/microservices-distributed-tracing/order-microservice/etc/order-microservice.urm.puml new file mode 100644 index 000000000..013138441 --- /dev/null +++ b/microservices-distributed-tracing/order-microservice/etc/order-microservice.urm.puml @@ -0,0 +1,15 @@ +@startuml +!theme vibrant +package com.iluwatar.microservices-distributed-tracing { +package "Order Microservice" { + class OrderController { + +processOrder() + } + + class OrderService { + +validateProduct() + +processPayment() + } +} +} +@enduml \ No newline at end of file diff --git a/microservices-distributed-tracing/order-microservice/pom.xml b/microservices-distributed-tracing/order-microservice/pom.xml new file mode 100644 index 000000000..f55c175b9 --- /dev/null +++ b/microservices-distributed-tracing/order-microservice/pom.xml @@ -0,0 +1,63 @@ + + + + + microservices-distributed-tracing + com.iluwatar + 1.26.0-SNAPSHOT + + 4.0.0 + order-microservice + jar + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.order.microservice.com.iluwatar.product.microservice.Main + + + + + + + + + + + central + Maven Central Repository + https://repo.maven.apache.org/maven2 + + + diff --git a/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/Main.java b/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/Main.java new file mode 100644 index 000000000..2b4d3f41f --- /dev/null +++ b/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/Main.java @@ -0,0 +1,80 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.order.microservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * With the Microservices pattern, a request often travels through multiple different microservices. + * Tracking the entire request flow across these services can be challenging, especially when trying + * to diagnose performance issues or failures. Distributed tracing addresses this challenge by + * providing end-to-end visibility into the lifecycle of a request as it passes through various + * microservices. + * + *

The intent of the Distributed Tracing pattern is to trace a request across different + * microservices, collecting detailed timing data and logs that help in understanding the flow, + * performance bottlenecks, and failure points in a distributed system. Each microservice involved + * in the request contributes to the tracing data, creating a comprehensive view of the request's + * journey. + * + *

This implementation demonstrates distributed tracing in a microservices architecture for an + * e-commerce platform. When a customer places an order, the {@link OrderService} interacts with + * both the payment-microservice to process the payment and the product-microservice to check the + * product inventory. Tracing logs are generated for each interaction, and these logs can be + * visualized using Zipkin. + * + *

To run Zipkin and view the tracing logs, you can use the following Docker command: + * + *

+ * {@code docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin }
+ * 
+ * + *

Start Zipkin with the command above. Once Zipkin is running, you can + * access the Zipkin UI at `...` + * to view the tracing logs and analyze the request flows across your microservices. + * + * + *

To place an order and generate tracing data, you can use the following curl command: + * + *

+ * {@code curl -X POST http://localhost:30300/order -H "Content-Type: application/json" -d '{"orderId": "123"}' }
+ * 
+ * + *

This command sends a POST request to create an order, which will trigger interactions with the + * payment and product microservices, generating tracing logs that can be viewed in Zipkin. + * + */ +@SpringBootApplication +public class Main { + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} diff --git a/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/OrderController.java b/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/OrderController.java new file mode 100644 index 000000000..5f50e1f25 --- /dev/null +++ b/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/OrderController.java @@ -0,0 +1,64 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.order.microservice; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * This controller handles order processing by calling necessary microservices. + */ +@Slf4j +@RestController +public class OrderController { + + private final OrderService orderService; + + /** + * Constructor to inject OrderService. + * + * @param orderService the service to process orders + */ + public OrderController(final OrderService orderService) { + this.orderService = orderService; + } + + /** + * Endpoint to process an order. + * + * @param request the order request body (can be null) + * @return ResponseEntity with a status message + */ + @PostMapping("/order") + public ResponseEntity processOrder(@RequestBody(required = false) String request) { + LOGGER.info("Received order request: {}", request); + var result = orderService.processOrder(); + LOGGER.info("Order processed result: {}", result); + return ResponseEntity.ok(result); + } +} diff --git a/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/OrderService.java b/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/OrderService.java new file mode 100644 index 000000000..046fc9fff --- /dev/null +++ b/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/OrderService.java @@ -0,0 +1,103 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.order.microservice; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.ResourceAccessException; + +/** + * Service to handle order processing logic. + */ +@Slf4j +@Service +public class OrderService { + + private final RestTemplateBuilder restTemplateBuilder; + + /** + * Constructor to inject RestTemplateBuilder. + * + * @param restTemplateBuilder the RestTemplateBuilder to build RestTemplate instances + */ + public OrderService(final RestTemplateBuilder restTemplateBuilder) { + this.restTemplateBuilder = restTemplateBuilder; + } + + /** + * Processes an order by calling + * {@link OrderService#validateProduct()} and + * {@link OrderService#processPayment()}. + * + * @return A string indicating whether the order was processed successfully or failed. + */ + public String processOrder() { + if (validateProduct() && processPayment()) { + return "Order processed successfully"; + } + return "Order processing failed"; + } + + /** + * Validates the product by calling the respective microservice. + * + * @return true if the product is valid, false otherwise. + */ + Boolean validateProduct() { + try { + ResponseEntity productValidationResult = restTemplateBuilder + .build() + .postForEntity("http://localhost:30302/product/validate", "validating product", + Boolean.class); + LOGGER.info("Product validation result: {}", productValidationResult.getBody()); + return productValidationResult.getBody(); + } catch (ResourceAccessException | HttpClientErrorException e) { + LOGGER.error("Error communicating with product service: {}", e.getMessage()); + return false; + } + } + + /** + * Validates the product by calling the respective microservice. + * + * @return true if the product is valid, false otherwise. + */ + Boolean processPayment() { + try { + ResponseEntity paymentProcessResult = restTemplateBuilder + .build() + .postForEntity("http://localhost:30301/payment/process", "processing payment", + Boolean.class); + LOGGER.info("Payment processing result: {}", paymentProcessResult.getBody()); + return paymentProcessResult.getBody(); + } catch (ResourceAccessException | HttpClientErrorException e) { + LOGGER.error("Error communicating with payment service: {}", e.getMessage()); + return false; + } + } +} diff --git a/microservices-distributed-tracing/order-microservice/src/main/resources/application.properties b/microservices-distributed-tracing/order-microservice/src/main/resources/application.properties new file mode 100644 index 000000000..fd183251d --- /dev/null +++ b/microservices-distributed-tracing/order-microservice/src/main/resources/application.properties @@ -0,0 +1,33 @@ +# +# The MIT License +# Copyright © 2014-2021 Ilkka Seppälä +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +spring.application.name=order-microservice +server.port=30300 + +management.tracing.sampling.probability=1 +logging.pattern.level=%5p [${spring.zipkin.service.name:${spring.application.name:}},%X{traceId:-},%X{spanId:-}] +management.tracing.propagation.type=w3c +management.tracing.baggage.enabled=true +management.tracing.enabled=true +management.zipkin.tracing.endpoint=http://localhost:9411/api/v2/spans + diff --git a/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/MainTest.java b/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/MainTest.java new file mode 100644 index 000000000..369690947 --- /dev/null +++ b/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/MainTest.java @@ -0,0 +1,39 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.order.microservice; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +/** + * Application test + */ +class MainTest { + @Test + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> Main.main(new String[]{})); + } +} diff --git a/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/OrderControllerTest.java b/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/OrderControllerTest.java new file mode 100644 index 000000000..f6a593943 --- /dev/null +++ b/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/OrderControllerTest.java @@ -0,0 +1,76 @@ +package com.iluwatar.order.microservice;/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.ResponseEntity; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +/** + * OrderControllerTest class to test the OrderController. + */ +class OrderControllerTest { + + @InjectMocks + private OrderController orderController; + + @Mock + private OrderService orderService; + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + /** + * Test to process the order successfully. + */ + @Test + void processOrderShouldReturnSuccessStatus() { + // Arrange + when(orderService.processOrder()).thenReturn("Order processed successfully"); + // Act + ResponseEntity response = orderController.processOrder("test order"); + // Assert + assertEquals("Order processed successfully", response.getBody()); + } + + /** + * Test to process the order with failure. + */ + @Test + void ProcessOrderShouldReturnFailureStatusWhen() { + // Arrange + when(orderService.processOrder()).thenReturn("Order processing failed"); + // Act + ResponseEntity response = orderController.processOrder("test order"); + // Assert + assertEquals("Order processing failed", response.getBody()); + } +} diff --git a/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/OrderServiceTest.java b/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/OrderServiceTest.java new file mode 100644 index 000000000..c331c5abb --- /dev/null +++ b/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/OrderServiceTest.java @@ -0,0 +1,192 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.order.microservice; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.ResourceAccessException; + +/** + * OrderServiceTest class to test the OrderService. + */ +class OrderServiceTest { + + @InjectMocks + private OrderService orderService; + + @Mock + private RestTemplateBuilder restTemplateBuilder; + + @Mock + private RestTemplate restTemplate; + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + when(restTemplateBuilder.build()).thenReturn(restTemplate); + } + + /** + * Test to process the order successfully. + */ + @Test + void testProcessOrder_Success() { + // Arrange + when(restTemplate.postForEntity(eq("http://localhost:30302/product/validate"), anyString(), eq(Boolean.class))) + .thenReturn(ResponseEntity.ok(true)); + when(restTemplate.postForEntity(eq("http://localhost:30301/payment/process"), anyString(), eq(Boolean.class))) + .thenReturn(ResponseEntity.ok(true)); + // Act + String result = orderService.processOrder(); + // Assert + assertEquals("Order processed successfully", result); + } + + /** + * Test to process the order with failure caused by product validation failure. + */ + @Test + void testProcessOrder_FailureWithProductValidationFailure() { + // Arrange + when(restTemplate.postForEntity(eq("http://localhost:30302/product/validate"), anyString(), eq(Boolean.class))) + .thenReturn(ResponseEntity.ok(false)); + // Act + String result = orderService.processOrder(); + // Assert + assertEquals("Order processing failed", result); + } + + /** + * Test to process the order with failure caused by payment processing failure. + */ + @Test + void testProcessOrder_FailureWithPaymentProcessingFailure() { + // Arrange + when(restTemplate.postForEntity(eq("http://localhost:30302/product/validate"), anyString(), eq(Boolean.class))) + .thenReturn(ResponseEntity.ok(true)); + when(restTemplate.postForEntity(eq("http://localhost:30301/payment/process"), anyString(), eq(Boolean.class))) + .thenReturn(ResponseEntity.ok(false)); + // Act + String result = orderService.processOrder(); + // Assert + assertEquals("Order processing failed", result); + } + + /** + * Test to validate the product. + */ + @Test + void testValidateProduct() { + // Arrange + when(restTemplate.postForEntity(eq("http://localhost:30302/product/validate"), anyString(), eq(Boolean.class))) + .thenReturn(ResponseEntity.ok(true)); + // Act + Boolean result = orderService.validateProduct(); + // Assert + assertEquals(true, result); + } + + /** + * Test to process the payment. + */ + @Test + void testProcessPayment() { + // Arrange + when(restTemplate.postForEntity(eq("http://localhost:30301/payment/process"), anyString(), eq(Boolean.class))) + .thenReturn(ResponseEntity.ok(true)); + // Act + Boolean result = orderService.processPayment(); + // Assert + assertEquals(true, result); + } + + /** + * Test to validate the product with ResourceAccessException. + */ + @Test + void testValidateProduct_ResourceAccessException() { + // Arrange + when(restTemplate.postForEntity(eq("http://localhost:30302/product/validate"), anyString(), eq(Boolean.class))) + .thenThrow(new ResourceAccessException("Service unavailable")); + // Act + Boolean result = orderService.validateProduct(); + // Assert + assertEquals(false, result); + } + + /** + * Test to validate the product with HttpClientErrorException. + */ + @Test + void testValidateProduct_HttpClientErrorException() { + // Arrange + when(restTemplate.postForEntity(eq("http://localhost:30302/product/validate"), anyString(), eq(Boolean.class))) + .thenThrow(new HttpClientErrorException(org.springframework.http.HttpStatus.BAD_REQUEST, "Bad request")); + // Act + Boolean result = orderService.validateProduct(); + // Assert + assertEquals(false, result); + } + + /** + * Test to process the payment with ResourceAccessException. + */ + @Test + void testProcessPayment_ResourceAccessException() { + // Arrange + when(restTemplate.postForEntity(eq("http://localhost:30301/payment/process"), anyString(), eq(Boolean.class))) + .thenThrow(new ResourceAccessException("Service unavailable")); + // Act + Boolean result = orderService.processPayment(); + // Assert + assertEquals(false, result); + } + + /** + * Test to process the payment with HttpClientErrorException. + */ + @Test + void testProcessPayment_HttpClientErrorException() { + // Arrange + when(restTemplate.postForEntity(eq("http://localhost:30301/payment/process"), anyString(), eq(Boolean.class))) + .thenThrow(new HttpClientErrorException(org.springframework.http.HttpStatus.BAD_REQUEST, "Bad request")); + // Act + Boolean result = orderService.processPayment(); + // Assert + assertEquals(false, result); + } +} diff --git a/microservices-distributed-tracing/payment-microservice/etc/payment-microservice.png b/microservices-distributed-tracing/payment-microservice/etc/payment-microservice.png new file mode 100644 index 0000000000000000000000000000000000000000..991fcf462e46d658ef6bebbf12f5c5c9f66cd12d GIT binary patch literal 10777 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 + + + + microservices-distributed-tracing + com.iluwatar + 1.26.0-SNAPSHOT + + 4.0.0 + payment-microservice + jar + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.payment.microservice.com.iluwatar.product.microservice.Main + + + + + + + + + diff --git a/microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/Main.java b/microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/Main.java new file mode 100644 index 000000000..e41f1c01b --- /dev/null +++ b/microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/Main.java @@ -0,0 +1,79 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.payment.microservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * With the Microservices pattern, a request often travels through multiple different microservices. + * Tracking the entire request flow across these services can be challenging, especially when trying + * to diagnose performance issues or failures. Distributed tracing addresses this challenge by + * providing end-to-end visibility into the lifecycle of a request as it passes through various + * microservices. + * + *

The intent of the Distributed Tracing pattern is to trace a request across different + * microservices, collecting detailed timing data and logs that help in understanding the flow, + * performance bottlenecks, and failure points in a distributed system. Each microservice involved + * in the request contributes to the tracing data, creating a comprehensive view of the request's + * journey. + * + *

This implementation demonstrates distributed tracing in a microservices architecture for an + * e-commerce platform. When a customer places an order, the OrderService interacts with + * both the PaymentService to process the payment and the ProductService to check the + * product inventory. Tracing logs are generated for each interaction, and these logs can be + * visualized using Zipkin. + * + *

To run Zipkin and view the tracing logs, you can use the following Docker command: + * + *

+ * {@code docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin }
+ * 
+ * + *

Start Zipkin with the command above. Once Zipkin is running, you can + * access the Zipkin UI at http://localhost:9411 + * to view the tracing logs and analyze the request flows across your microservices. + * + *

To place an order and generate tracing data, you can use the following curl command: + * + *

+ * {@code curl -X POST http://localhost:30300/order -H "Content-Type: application/json" -d '{"orderId": "123"}' }
+ * 
+ * + *

This command sends a POST request to create an order, which will trigger interactions with the + * payment and product microservices, generating tracing logs that can be viewed in Zipkin. + * + */ +@SpringBootApplication +public class Main { + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} diff --git a/microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/PaymentController.java b/microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/PaymentController.java new file mode 100644 index 000000000..2662589a0 --- /dev/null +++ b/microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/PaymentController.java @@ -0,0 +1,53 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.payment.microservice; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * Controller for handling payment processing requests. + */ +@Slf4j +@RestController +public class PaymentController { + + /** + * Processes the payment based on the request. + * + * @param request the request body containing payment information (can be null) + * @return ResponseEntity containing the payment processing result (true) + */ + @PostMapping("/payment/process") + public ResponseEntity payment(@RequestBody(required = false) String request) { + LOGGER.info("Received payment request: {}", request); + boolean result = true; + LOGGER.info("Payment result: {}", result); + return ResponseEntity.ok(result); + } +} diff --git a/microservices-distributed-tracing/payment-microservice/src/main/resources/application.properties b/microservices-distributed-tracing/payment-microservice/src/main/resources/application.properties new file mode 100644 index 000000000..5f24f5b60 --- /dev/null +++ b/microservices-distributed-tracing/payment-microservice/src/main/resources/application.properties @@ -0,0 +1,32 @@ +# +# The MIT License +# Copyright © 2014-2021 Ilkka Seppälä +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +spring.application.name=payment-microservice +server.port=30301 + +management.tracing.sampling.probability=1 +logging.pattern.level=%5p [${spring.zipkin.service.name:${spring.application.name:}},%X{traceId:-},%X{spanId:-}] +management.tracing.propagation.type=w3c +management.tracing.baggage.enabled=true +management.tracing.enabled=true +management.zipkin.tracing.endpoint=http://localhost:9411/api/v2/spans diff --git a/microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/MainTest.java b/microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/MainTest.java new file mode 100644 index 000000000..b8b3b6e56 --- /dev/null +++ b/microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/MainTest.java @@ -0,0 +1,39 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.payment.microservice; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +/** + * Application Context loads test + */ +class MainTest { + @Test + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> Main.main(new String[]{})); + } +} diff --git a/microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/ProductControllerTest.java b/microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/ProductControllerTest.java new file mode 100644 index 000000000..4b32d7662 --- /dev/null +++ b/microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/ProductControllerTest.java @@ -0,0 +1,68 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.payment.microservice; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.http.ResponseEntity; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Payment controller test. + */ +class ProductControllerTest { + + private PaymentController paymentController; + + @BeforeEach + void setUp() { + paymentController = new PaymentController(); + } + /** + * Test to process the payment. + */ + @Test + void testValidateProduct() { + // Arrange + String request = "Sample payment process request"; + // Act + ResponseEntity response = paymentController.payment(request); + // Assert + assertEquals(ResponseEntity.ok(true), response); + } + + /** + * Test to process the payment with null request. + */ + @Test + void testValidateProductWithNullRequest() { + // Arrange + // Act + ResponseEntity response = paymentController.payment(null); + // Assert + assertEquals(ResponseEntity.ok(true), response); + } +} diff --git a/microservices-distributed-tracing/pom.xml b/microservices-distributed-tracing/pom.xml new file mode 100644 index 000000000..72eded678 --- /dev/null +++ b/microservices-distributed-tracing/pom.xml @@ -0,0 +1,82 @@ + + + + + java-design-patterns + com.iluwatar + 1.26.0-SNAPSHOT + + 4.0.0 + microservices-distributed-tracing + pom + + + + org.springframework.boot + spring-boot-dependencies + pom + 3.3.1 + import + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + io.micrometer + micrometer-tracing-bridge-brave + compile + + + io.zipkin.reporter2 + zipkin-reporter-brave + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-core + test + + + + order-microservice + payment-microservice + product-microservice + + diff --git a/microservices-distributed-tracing/product-microservice/etc/product-microservice.png b/microservices-distributed-tracing/product-microservice/etc/product-microservice.png new file mode 100644 index 0000000000000000000000000000000000000000..23410f3cd5716c52cacf3712e7aa8929f006948e GIT binary patch literal 10246 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 Uuj5|eg*=FgqNYNr+`Y&D1rCK*UjP6A literal 0 HcmV?d00001 diff --git a/microservices-distributed-tracing/product-microservice/etc/product-microservice.puml b/microservices-distributed-tracing/product-microservice/etc/product-microservice.puml new file mode 100644 index 000000000..25a1805ff --- /dev/null +++ b/microservices-distributed-tracing/product-microservice/etc/product-microservice.puml @@ -0,0 +1,10 @@ +@startuml +!theme vibrant +package com.iluwatar.microservices-distributed-tracing { +package "Product Microservice" { + class ProductController { + +validateProduct() + } +} +} +@enduml \ No newline at end of file diff --git a/microservices-distributed-tracing/product-microservice/etc/product-microservice.urm.puml b/microservices-distributed-tracing/product-microservice/etc/product-microservice.urm.puml new file mode 100644 index 000000000..25a1805ff --- /dev/null +++ b/microservices-distributed-tracing/product-microservice/etc/product-microservice.urm.puml @@ -0,0 +1,10 @@ +@startuml +!theme vibrant +package com.iluwatar.microservices-distributed-tracing { +package "Product Microservice" { + class ProductController { + +validateProduct() + } +} +} +@enduml \ No newline at end of file diff --git a/microservices-distributed-tracing/product-microservice/pom.xml b/microservices-distributed-tracing/product-microservice/pom.xml new file mode 100644 index 000000000..987e0fca8 --- /dev/null +++ b/microservices-distributed-tracing/product-microservice/pom.xml @@ -0,0 +1,56 @@ + + + + + microservices-distributed-tracing + com.iluwatar + 1.26.0-SNAPSHOT + + 4.0.0 + product-microservice + jar + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.product.com.iluwatar.product.microservice.microservice.Main + + + + + + + + + diff --git a/microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/Main.java b/microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/Main.java new file mode 100644 index 000000000..93b2a8383 --- /dev/null +++ b/microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/Main.java @@ -0,0 +1,79 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.product.microservice.microservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * With the Microservices pattern, a request often travels through multiple different microservices. + * Tracking the entire request flow across these services can be challenging, especially when trying + * to diagnose performance issues or failures. Distributed tracing addresses this challenge by + * providing end-to-end visibility into the lifecycle of a request as it passes through various + * microservices. + * + *

The intent of the Distributed Tracing pattern is to trace a request across different + * microservices, collecting detailed timing data and logs that help in understanding the flow, + * performance bottlenecks, and failure points in a distributed system. Each microservice involved + * in the request contributes to the tracing data, creating a comprehensive view of the request's + * journey. + * + *

This implementation demonstrates distributed tracing in a microservices architecture for an + * e-commerce platform. When a customer places an order, the OrderService interacts with + * both the PaymentService to process the payment and the ProductService to check the + * product inventory. Tracing logs are generated for each interaction, and these logs can be + * visualized using Zipkin. + * + *

To run Zipkin and view the tracing logs, you can use the following Docker command: + * + *

+ * {@code docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin }
+ * 
+ * + *

Start Zipkin with the command above. Once Zipkin is running, you can + * access the Zipkin UI at http://localhost:9411 + * to view the tracing logs and analyze the request flows across your microservices. + * + *

To place an order and generate tracing data, you can use the following curl command: + * + *

+ * {@code curl -X POST http://localhost:30300/order -H "Content-Type: application/json" -d '{"orderId": "123"}' }
+ * 
+ * + *

This command sends a POST request to create an order, which will trigger interactions with the + * payment and product microservices, generating tracing logs that can be viewed in Zipkin. + * + */ +@SpringBootApplication +public class Main { + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} diff --git a/microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/ProductController.java b/microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/ProductController.java new file mode 100644 index 000000000..c9972e5b2 --- /dev/null +++ b/microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/ProductController.java @@ -0,0 +1,53 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.product.microservice.microservice; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * Controller for handling product validation requests. + */ +@Slf4j +@RestController +public class ProductController { + + /** + * Validates the product based on the request. + * + * @param request the request body containing product information (can be null) + * @return ResponseEntity containing the validation result (true) + */ + @PostMapping("/product/validate") + public ResponseEntity validateProduct(@RequestBody(required = false) String request) { + LOGGER.info("Received product validation request: {}", request); + boolean result = true; + LOGGER.info("Product validation result: {}", result); + return ResponseEntity.ok(result); + } +} diff --git a/microservices-distributed-tracing/product-microservice/src/main/resources/application.properties b/microservices-distributed-tracing/product-microservice/src/main/resources/application.properties new file mode 100644 index 000000000..72c7b3ed2 --- /dev/null +++ b/microservices-distributed-tracing/product-microservice/src/main/resources/application.properties @@ -0,0 +1,33 @@ +# +# The MIT License +# Copyright © 2014-2021 Ilkka Seppälä +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +spring.application.name=product-microservice +server.port=30302 + +management.tracing.sampling.probability=1 +logging.pattern.level=%5p [${spring.zipkin.service.name:${spring.application.name:}},%X{traceId:-},%X{spanId:-}] +management.tracing.propagation.type=w3c +management.tracing.baggage.enabled=true +management.tracing.enabled=true +management.zipkin.tracing.endpoint=http://localhost:9411/api/v2/spans + diff --git a/microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/MainTest.java b/microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/MainTest.java new file mode 100644 index 000000000..f7c6b8800 --- /dev/null +++ b/microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/MainTest.java @@ -0,0 +1,40 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.product.microservice; + +import com.iluwatar.product.microservice.microservice.Main; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +/** + * Application test + */ +class MainTest { + @Test + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> Main.main(new String[]{})); + } +} diff --git a/microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/ProductControllerTest.java b/microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/ProductControllerTest.java new file mode 100644 index 000000000..139cae40b --- /dev/null +++ b/microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/ProductControllerTest.java @@ -0,0 +1,68 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.product.microservice; + +import com.iluwatar.product.microservice.microservice.ProductController; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.http.ResponseEntity; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +class ProductControllerTest { + + private ProductController productController; + + @BeforeEach + public void setUp() { + productController = new ProductController(); + } + + /** + * Test to validate the product. + */ + @Test + void testValidateProduct() { + // Arrange + String request = "Sample product validation request"; + // Act + ResponseEntity response = productController.validateProduct(request); + // Assert + assertEquals(ResponseEntity.ok(true), response); + } + + /** + * Test to validate the product with null request. + */ + @Test + void testValidateProductWithNullRequest() { + // Arrange + // Act + ResponseEntity response = productController.validateProduct(null); + // Assert + assertEquals(ResponseEntity.ok(true), response); + } +} diff --git a/pom.xml b/pom.xml index 8a34f73cf..9fbe4f7bb 100644 --- a/pom.xml +++ b/pom.xml @@ -216,6 +216,7 @@ server-session virtual-proxy function-composition + microservices-distributed-tracing