1+ /*
2+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
3+ *
4+ * The MIT License
5+ * Copyright © 2014-2022 Ilkka Seppälä
6+ *
7+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8+ * of this software and associated documentation files (the "Software"), to deal
9+ * in the Software without restriction, including without limitation the rights
10+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+ * copies of the Software, and to permit persons to whom the Software is
12+ * furnished to do so, subject to the following conditions:
13+ *
14+ * The above copyright notice and this permission notice shall be included in
15+ * all copies or substantial portions of the Software.
16+ *
17+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+ * THE SOFTWARE.
24+ */
125package com .iluwatar .logaggregation ;
226
327import java .util .concurrent .ConcurrentLinkedQueue ;
28+ import java .util .concurrent .ExecutorService ;
429import java .util .concurrent .Executors ;
5- import java .util .concurrent .ScheduledExecutorService ;
630import java .util .concurrent .TimeUnit ;
731import java .util .concurrent .atomic .AtomicInteger ;
832import lombok .extern .slf4j .Slf4j ;
933
1034/**
11- * Collects and buffers logs from different services, periodically flushing them
12- * to a central log store based on a time interval or buffer threshold.
35+ * Responsible for collecting and buffering logs from different services.
36+ * Once the logs reach a certain threshold or after a certain time interval,
37+ * they are flushed to the central log store. This class ensures logs are collected
38+ * and processed asynchronously and efficiently, providing both an immediate collection
39+ * and periodic flushing.
1340 */
1441@ Slf4j
1542public class LogAggregator {
1643
1744 private static final int BUFFER_THRESHOLD = 3 ;
18- private static final int FLUSH_INTERVAL = 5 ; // Interval in seconds for periodic flushing
19-
2045 private final CentralLogStore centralLogStore ;
2146 private final ConcurrentLinkedQueue <LogEntry > buffer = new ConcurrentLinkedQueue <>();
2247 private final LogLevel minLogLevel ;
48+ private final ExecutorService executorService = Executors .newSingleThreadExecutor ();
49+ private final Object bufferWait = new Object ();
2350 private final AtomicInteger logCount = new AtomicInteger (0 );
2451
25- private final ScheduledExecutorService scheduler = Executors .newScheduledThreadPool (1 );
26-
2752 /**
28- * Constructor of LogAggregator.
53+ * constructor of LogAggregator.
2954 *
30- * @param centralLogStore central log store implementation
31- * @param minLogLevel minimum log level to store log
55+ * @param centralLogStore central log store implement
56+ * @param minLogLevel min log level to store log
3257 */
3358 public LogAggregator (CentralLogStore centralLogStore , LogLevel minLogLevel ) {
3459 this .centralLogStore = centralLogStore ;
@@ -37,8 +62,7 @@ public LogAggregator(CentralLogStore centralLogStore, LogLevel minLogLevel) {
3762 }
3863
3964 /**
40- * Collects a log entry and buffers it for eventual flushing to the central log store.
41- * Filters logs based on the configured minimum log level.
65+ * Collects a given log entry, and filters it by the defined log level.
4266 *
4367 * @param logEntry The log entry to collect.
4468 */
@@ -54,6 +78,7 @@ public void collectLog(LogEntry logEntry) {
5478 }
5579
5680 buffer .offer (logEntry );
81+ bufferWake ();
5782
5883 if (logCount .incrementAndGet () >= BUFFER_THRESHOLD ) {
5984 flushBuffer ();
@@ -64,41 +89,48 @@ public void collectLog(LogEntry logEntry) {
6489 * Stops the log aggregator service and flushes any remaining logs to
6590 * the central log store.
6691 *
67- * @throws InterruptedException If interrupted while shutting down .
92+ * @throws InterruptedException If any thread has interrupted the current thread .
6893 */
6994 public void stop () throws InterruptedException {
70- LOGGER .info ("Stopping log aggregator..." );
71- scheduler .shutdown ();
72- if (!scheduler .awaitTermination (10 , TimeUnit .SECONDS )) {
73- LOGGER .error ("Log aggregator did not terminate cleanly." );
95+ executorService .shutdownNow ();
96+ if (!executorService .awaitTermination (10 , TimeUnit .SECONDS )) {
97+ LOGGER .error ("Log aggregator did not terminate." );
7498 }
7599 flushBuffer ();
76100 }
77101
78- /**
79- * Flushes the buffered logs to the central log store.
80- */
81102 private void flushBuffer () {
82- LOGGER .info ("Flushing buffer..." );
83103 LogEntry logEntry ;
84104 while ((logEntry = buffer .poll ()) != null ) {
85105 centralLogStore .storeLog (logEntry );
86106 logCount .decrementAndGet ();
87107 }
88- LOGGER .info ("Buffer flushed." );
89108 }
90109
91- /**
92- * Starts the periodic buffer flusher task using a scheduled executor service.
93- */
94110 private void startBufferFlusher () {
95- scheduler .scheduleAtFixedRate (() -> {
96- try {
97- LOGGER .info ("Periodic buffer flush initiated..." );
98- flushBuffer ();
99- } catch (Exception e ) {
100- LOGGER .error ("Error during buffer flush" , e );
111+ executorService .execute (() -> {
112+ while (!Thread .currentThread ().isInterrupted ()) {
113+ try {
114+ synchronized (bufferWait ) {
115+ if (buffer .isEmpty ()) {
116+ bufferWait .wait ();
117+ }
118+ }
119+ Thread .sleep (5000 ); // Flush every 5 seconds.
120+ flushBuffer ();
121+ } catch (InterruptedException e ) {
122+ Thread .currentThread ().interrupt ();
123+ }
101124 }
102- }, FLUSH_INTERVAL , FLUSH_INTERVAL , TimeUnit .SECONDS );
125+ });
126+ }
127+
128+ /**
129+ * Wakes up buffer.
130+ */
131+ public void bufferWake () {
132+ synchronized (bufferWait ) {
133+ bufferWait .notifyAll ();
134+ }
103135 }
104136}
0 commit comments