diff --git a/log-aggregation/README.md b/log-aggregation/README.md new file mode 100644 index 000000000..f6d979517 --- /dev/null +++ b/log-aggregation/README.md @@ -0,0 +1,59 @@ +--- +title: Log aggregation +category: Architectural +language: en +tag: + - Microservices + - Extensibility +--- + +## Intent + +Centralize, streamline, and optimize the process of log management so that insights can be quickly +derived, problems can be swiftly identified and resolved, and the system's overall health can be +monitored efficiently. + +## Explanation + +Real-world example + +> AWS CloudWatch aggregates logs from various AWS services for monitoring and alerting. + + +In plain words + +> The primary goal is to consolidate logs from different sources, making them more accessible and +> actionable. Various tools and platforms, such as Elasticsearch-Logstash-Kibana (ELK) stack, +> Splunk, +> Graylog, and others, are employed in these real-world scenarios to facilitate log aggregation. + +Wikipedia says + +> You have applied the Microservice architecture pattern. The application consists of multiple +> services and service instances that are running on multiple machines. Requests often span multiple +> service instances. Each service instance generates writes information about what it is doing to a +> log file in a standardized format. The log file contains errors, warnings, information and debug +> messages. + + +## Class diagram + +![class diagram](./etc/log-aggregation.png) + +## Applicability + +1. Distributed Systems and Microservices + - In modern architectures where systems are split into smaller, independent microservices running across multiple servers or even data centers, aggregating logs from all these services is crucial for a holistic view of system health and activity. + +2. Troubleshooting and Debugging + - When system failures or unexpected behaviors occur, engineers need consolidated logs to trace and diagnose issues. Log aggregation makes this process efficient by collecting all relevant logs in one place. + +3. Security and Compliance Monitoring + - Many industries have regulatory requirements for log retention and analysis. Log aggregation helps in collecting, retaining, and analyzing logs for unauthorized access, potential breaches, and other security threats. + +4. Performance Monitoring + - Aggregated logs can be used to identify performance bottlenecks, slow database queries, or service endpoints experiencing high latencies. + +## Credits + +* [Pattern: Log aggregation](https://microservices.io/patterns/observability/application-logging.html) diff --git a/log-aggregation/etc/log-aggregation.png b/log-aggregation/etc/log-aggregation.png new file mode 100644 index 000000000..4ce56be70 Binary files /dev/null and b/log-aggregation/etc/log-aggregation.png differ diff --git a/log-aggregation/etc/log-aggregation.puml b/log-aggregation/etc/log-aggregation.puml new file mode 100644 index 000000000..b35873e17 --- /dev/null +++ b/log-aggregation/etc/log-aggregation.puml @@ -0,0 +1,51 @@ +@startuml + +package com.iluwatar.logaggregation { + + class App { + + main(args: String[]) {static} + } + + class CentralLogStore { + - logs: ConcurrentLinkedQueue + + storeLog(logEntry: LogEntry) + + displayLogs() + } + + class LogAggregator { + - BUFFER_THRESHOLD: int {static} + - centralLogStore: CentralLogStore + - buffer: ConcurrentLinkedQueue + - minLogLevel: LogLevel + - executorService: ExecutorService + - logCount: AtomicInteger + + collectLog(logEntry: LogEntry) + + stop() + } + + class LogEntry { + - serviceName: String + - level: LogLevel + - message: String + - timestamp: LocalDateTime + } + + enum LogLevel { + DEBUG + INFO + ERROR + } + + class LogProducer { + - serviceName: String + - aggregator: LogAggregator + + generateLog(level: LogLevel, message: String) + } +} + +LogProducer --> "-aggregator" LogAggregator +LogAggregator --> "-centralLogStore" CentralLogStore +LogAggregator --> "-buffer" LogEntry +CentralLogStore --> "-logs" LogEntry + +@enduml diff --git a/log-aggregation/pom.xml b/log-aggregation/pom.xml new file mode 100644 index 000000000..886d712ff --- /dev/null +++ b/log-aggregation/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + log-aggregation + + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-junit-jupiter + test + + + + 17 + 17 + UTF-8 + + + diff --git a/log-aggregation/src/main/java/com/iluwatar/logaggregation/App.java b/log-aggregation/src/main/java/com/iluwatar/logaggregation/App.java new file mode 100644 index 000000000..ef9ca0a7b --- /dev/null +++ b/log-aggregation/src/main/java/com/iluwatar/logaggregation/App.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-2023 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.logaggregation; + +/** + * The main application class responsible for demonstrating the log aggregation mechanism. Creates + * services, generates logs, aggregates, and finally displays the logs. + */ +public class App { + + /** + * The entry point of the application. + * + * @param args Command line arguments. + * @throws InterruptedException If any thread has interrupted the current thread. + */ + public static void main(String[] args) throws InterruptedException { + final CentralLogStore centralLogStore = new CentralLogStore(); + final LogAggregator aggregator = new LogAggregator(centralLogStore, LogLevel.INFO); + + final LogProducer serviceA = new LogProducer("ServiceA", aggregator); + final LogProducer serviceB = new LogProducer("ServiceB", aggregator); + + serviceA.generateLog(LogLevel.INFO, "This is an INFO log from ServiceA"); + serviceB.generateLog(LogLevel.ERROR, "This is an ERROR log from ServiceB"); + serviceA.generateLog(LogLevel.DEBUG, "This is a DEBUG log from ServiceA"); + + aggregator.stop(); + centralLogStore.displayLogs(); + } +} diff --git a/log-aggregation/src/main/java/com/iluwatar/logaggregation/CentralLogStore.java b/log-aggregation/src/main/java/com/iluwatar/logaggregation/CentralLogStore.java new file mode 100644 index 000000000..f7226638c --- /dev/null +++ b/log-aggregation/src/main/java/com/iluwatar/logaggregation/CentralLogStore.java @@ -0,0 +1,63 @@ +/* + * 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-2023 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.logaggregation; + +import java.util.concurrent.ConcurrentLinkedQueue; +import lombok.extern.slf4j.Slf4j; + +/** + * A centralized store for logs. It collects logs from various services and stores them. + * This class is thread-safe, ensuring that logs from different services are safely stored + * concurrently without data races. + */ +@Slf4j +public class CentralLogStore { + + private final ConcurrentLinkedQueue logs = new ConcurrentLinkedQueue<>(); + + /** + * Stores the given log entry into the central log store. + * + * @param logEntry The log entry to store. + */ + public void storeLog(LogEntry logEntry) { + if (logEntry == null) { + LOGGER.error("Received null log entry. Skipping."); + return; + } + logs.offer(logEntry); + } + + /** + * Displays all logs currently stored in the central log store. + */ + public void displayLogs() { + LOGGER.info("----- Centralized Logs -----"); + for (LogEntry logEntry : logs) { + LOGGER.info( + logEntry.getTimestamp() + " [" + logEntry.getLevel() + "] " + logEntry.getMessage()); + } + } +} diff --git a/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogAggregator.java b/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogAggregator.java new file mode 100644 index 000000000..406ce144a --- /dev/null +++ b/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogAggregator.java @@ -0,0 +1,120 @@ +/* + * 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-2023 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.logaggregation; + +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import lombok.extern.slf4j.Slf4j; + +/** + * Responsible for collecting and buffering logs from different services. + * Once the logs reach a certain threshold or after a certain time interval, + * they are flushed to the central log store. This class ensures logs are collected + * and processed asynchronously and efficiently, providing both an immediate collection + * and periodic flushing. + */ +@Slf4j +public class LogAggregator { + + private static final int BUFFER_THRESHOLD = 3; + private final CentralLogStore centralLogStore; + private final ConcurrentLinkedQueue buffer = new ConcurrentLinkedQueue<>(); + private final LogLevel minLogLevel; + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + private final AtomicInteger logCount = new AtomicInteger(0); + + /** + * constructor of LogAggregator. + * + * @param centralLogStore central log store implement + * @param minLogLevel min log level to store log + */ + public LogAggregator(CentralLogStore centralLogStore, LogLevel minLogLevel) { + this.centralLogStore = centralLogStore; + this.minLogLevel = minLogLevel; + startBufferFlusher(); + } + + /** + * Collects a given log entry, and filters it by the defined log level. + * + * @param logEntry The log entry to collect. + */ + public void collectLog(LogEntry logEntry) { + if (logEntry.getLevel() == null || minLogLevel == null) { + LOGGER.warn("Log level or threshold level is null. Skipping."); + return; + } + + if (logEntry.getLevel().compareTo(minLogLevel) < 0) { + LOGGER.debug("Log level below threshold. Skipping."); + return; + } + + buffer.offer(logEntry); + + if (logCount.incrementAndGet() >= BUFFER_THRESHOLD) { + flushBuffer(); + } + } + + /** + * Stops the log aggregator service and flushes any remaining logs to + * the central log store. + * + * @throws InterruptedException If any thread has interrupted the current thread. + */ + public void stop() throws InterruptedException { + executorService.shutdownNow(); + if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) { + LOGGER.error("Log aggregator did not terminate."); + } + flushBuffer(); + } + + private void flushBuffer() { + LogEntry logEntry; + while ((logEntry = buffer.poll()) != null) { + centralLogStore.storeLog(logEntry); + logCount.decrementAndGet(); + } + } + + private void startBufferFlusher() { + executorService.execute(() -> { + while (!Thread.currentThread().isInterrupted()) { + try { + Thread.sleep(5000); // Flush every 5 seconds. + flushBuffer(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + }); + } +} diff --git a/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogEntry.java b/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogEntry.java new file mode 100644 index 000000000..bece65c64 --- /dev/null +++ b/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogEntry.java @@ -0,0 +1,42 @@ +/* + * 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-2023 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.logaggregation; + +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * Represents a single log entry, capturing essential details like the service name, + * log level, message, and the timestamp when the log was generated. + */ +@Data +@AllArgsConstructor +public class LogEntry { + private String serviceName; + private LogLevel level; + private String message; + private LocalDateTime timestamp; +} diff --git a/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogLevel.java b/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogLevel.java new file mode 100644 index 000000000..ed9258649 --- /dev/null +++ b/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogLevel.java @@ -0,0 +1,38 @@ +/* + * 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-2023 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.logaggregation; + +/** + * Enum representing different log levels. + * Defines the severity of a log message, helping in filtering and prioritization. + *
    + *
  • DEBUG: Detailed information, typically of interest only when diagnosing problems.
  • + *
  • INFO: Confirmation that things are working as expected.
  • + *
  • ERROR: Indicates a problem that needs attention.
  • + *
+ */ +public enum LogLevel { + DEBUG, INFO, ERROR +} diff --git a/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogProducer.java b/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogProducer.java new file mode 100644 index 000000000..f6ca7f0de --- /dev/null +++ b/log-aggregation/src/main/java/com/iluwatar/logaggregation/LogProducer.java @@ -0,0 +1,54 @@ +/* + * 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-2023 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.logaggregation; + +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * Represents a service that produces logs. + * The logs are generated based on certain activities or events within the service. + * Once a log is generated, it's passed on to the aggregator for further processing. + */ +@AllArgsConstructor +@Slf4j +public class LogProducer { + + private String serviceName; + private LogAggregator aggregator; + + /** + * Generates a log entry with the given log level and message. + * + * @param level The level of the log. + * @param message The message of the log. + */ + public void generateLog(LogLevel level, String message) { + final LogEntry logEntry = new LogEntry(serviceName, level, message, LocalDateTime.now()); + LOGGER.info("Producing log: " + logEntry.getMessage()); + aggregator.collectLog(logEntry); + } +} diff --git a/log-aggregation/src/test/java/com/iluwatar/logaggregation/LogAggregatorTest.java b/log-aggregation/src/test/java/com/iluwatar/logaggregation/LogAggregatorTest.java new file mode 100644 index 000000000..182e72527 --- /dev/null +++ b/log-aggregation/src/test/java/com/iluwatar/logaggregation/LogAggregatorTest.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-2023 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.logaggregation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.time.LocalDateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class LogAggregatorTest { + + @Mock + private CentralLogStore centralLogStore; + private LogAggregator logAggregator; + + @BeforeEach + void setUp() { + logAggregator = new LogAggregator(centralLogStore, LogLevel.INFO); + } + + @Test + void whenThreeInfoLogsAreCollected_thenCentralLogStoreShouldStoreAllOfThem() { + logAggregator.collectLog(createLogEntry(LogLevel.INFO, "Sample log message 1")); + logAggregator.collectLog(createLogEntry(LogLevel.INFO, "Sample log message 2")); + + verifyNoInteractionsWithCentralLogStore(); + + logAggregator.collectLog(createLogEntry(LogLevel.INFO, "Sample log message 3")); + + verifyCentralLogStoreInvokedTimes(3); + } + + @Test + void whenDebugLogIsCollected_thenNoLogsShouldBeStored() { + logAggregator.collectLog(createLogEntry(LogLevel.DEBUG, "Sample debug log message")); + + verifyNoInteractionsWithCentralLogStore(); + } + + private static LogEntry createLogEntry(LogLevel logLevel, String message) { + return new LogEntry("ServiceA", logLevel, message, LocalDateTime.now()); + } + + private void verifyNoInteractionsWithCentralLogStore() { + verify(centralLogStore, times(0)).storeLog(any()); + } + + private void verifyCentralLogStoreInvokedTimes(int times) { + verify(centralLogStore, times(times)).storeLog(any()); + } +} diff --git a/pom.xml b/pom.xml index 133e8565d..48e725a4f 100644 --- a/pom.xml +++ b/pom.xml @@ -208,6 +208,7 @@ thread-local-storage optimistic-offline-lock crtp + log-aggregation health-check