@@ -36,12 +36,24 @@ Writer::ThreadLocalBuffer::~ThreadLocalBuffer()
3636Writer::~Writer ()
3737{
3838 auto & instance = GetInstance ();
39- instance.shutdown .store (true );
39+
40+ // Signal all background threads to stop
41+ {
42+ std::lock_guard<std::mutex> lock (instance.shutdownMutex );
43+ instance.shutdown .store (true );
44+ }
45+ instance.cv_shutdown .notify_all ();
46+
47+ if (instance.flushTimerThread .joinable ())
48+ {
49+ instance.flushTimerThread .join ();
50+ }
51+
4052 this ->Close ();
4153}
4254
4355void Writer::Initialize (WriterType type, const std::string& param, int port,
44- unsigned int bufferSize)
56+ unsigned int bufferSize, unsigned int flushIntervalMs )
4557{
4658 auto & instance = GetInstance ();
4759
@@ -66,20 +78,37 @@ void Writer::Initialize(WriterType type, const std::string& param, int port,
6678 }
6779
6880 instance.m_currentType = type;
69- instance.shutdown .store (false );
70- instance.bufferingEnabled = false ;
7181
72- // Clear thread-local buffer registry from any previous init
82+ // Stop any pre-existing timer thread before re-initialising
83+ {
84+ std::lock_guard<std::mutex> lock (instance.shutdownMutex );
85+ instance.shutdown .store (true );
86+ }
87+ instance.cv_shutdown .notify_all ();
88+ if (instance.flushTimerThread .joinable ())
89+ {
90+ instance.flushTimerThread .join ();
91+ }
92+ // Clear the thread-local buffer registry from any previous init
7393 {
7494 std::lock_guard<std::mutex> regLock (instance.registryMutex );
7595 instance.threadBufferRegistry .clear ();
7696 }
97+ instance.shutdown .store (false );
98+ instance.bufferingEnabled = false ;
7799
78- if (bufferSize > 0 )
100+ if (bufferSize > 0 || flushIntervalMs > 0 )
79101 {
80102 instance.bufferingEnabled = true ;
81103 instance.bufferSize = bufferSize;
82104 instance.writeImpl = &Writer::ThreadLocalBufferedWrite;
105+
106+ if (flushIntervalMs > 0 )
107+ {
108+ instance.flushInterval = std::chrono::milliseconds (flushIntervalMs);
109+ instance.flushTimerThread = std::thread (&Writer::FlushTimerThread, &instance);
110+ Logger::info (" Writer interval flush enabled: {}ms" , flushIntervalMs);
111+ }
83112 }
84113 else
85114 {
@@ -99,6 +128,63 @@ void Writer::TryToSend(const std::string& message)
99128 instance.m_impl ->Write (message);
100129}
101130
131+ void Writer::FlushTimerThread ()
132+ {
133+ auto & instance = GetInstance ();
134+
135+ while (true )
136+ {
137+ // Sleep for the flush interval, or wake early on shutdown
138+ {
139+ std::unique_lock<std::mutex> lock (instance.shutdownMutex );
140+ instance.cv_shutdown .wait_for (lock, instance.flushInterval ,
141+ [&instance] { return instance.shutdown .load (); });
142+ }
143+
144+ if (instance.shutdown .load ())
145+ {
146+ break ;
147+ }
148+
149+ // Collect live buffers (clean up expired weak_ptrs in the same pass)
150+ std::vector<std::shared_ptr<ThreadLocalBuffer>> buffersToFlush;
151+ {
152+ std::lock_guard<std::mutex> regLock (instance.registryMutex );
153+ for (auto it = instance.threadBufferRegistry .begin ();
154+ it != instance.threadBufferRegistry .end ();)
155+ {
156+ if (auto buf = it->lock ())
157+ {
158+ buffersToFlush.push_back (std::move (buf));
159+ ++it;
160+ }
161+ else
162+ {
163+ it = instance.threadBufferRegistry .erase (it);
164+ }
165+ }
166+ }
167+
168+ // Drain each thread-local buffer
169+ for (auto & buf : buffersToFlush)
170+ {
171+ std::string toSend;
172+ {
173+ std::lock_guard<std::mutex> lock (buf->mutex );
174+ if (!buf->data .empty ())
175+ {
176+ toSend = std::move (buf->data );
177+ buf->data .clear ();
178+ }
179+ }
180+ if (!toSend.empty ())
181+ {
182+ instance.TryToSend (toSend);
183+ }
184+ }
185+ }
186+ }
187+
102188void Writer::ThreadLocalBufferedWrite (const std::string& message)
103189{
104190 auto & instance = GetInstance ();
@@ -118,7 +204,7 @@ void Writer::ThreadLocalBufferedWrite(const std::string& message)
118204 tl_buffer->data .push_back (NEW_LINE );
119205
120206 // Capacity-based flush: drain when the thread-local buffer is full
121- if (tl_buffer->data .size () >= instance.bufferSize )
207+ if (instance. bufferSize > 0 && tl_buffer->data .size () >= instance.bufferSize )
122208 {
123209 toSend = std::move (tl_buffer->data );
124210 tl_buffer->data .clear ();
0 commit comments