3232#include " Poco/PatternFormatter.h"
3333#include " Poco/AsyncChannel.h"
3434#include " Poco/SplitterChannel.h"
35+ #include " Poco/EventChannel.h"
3536#include " Poco/File.h"
3637#include " Poco/TemporaryFile.h"
3738#include " Poco/FileStream.h"
@@ -53,6 +54,7 @@ using Poco::FormattingChannel;
5354using Poco::PatternFormatter;
5455using Poco::AsyncChannel;
5556using Poco::SplitterChannel;
57+ using Poco::EventChannel;
5658using Poco::Channel;
5759using Poco::Message;
5860using Poco::AutoPtr;
@@ -281,21 +283,82 @@ void FastLoggerChannelsTest::testAsyncChannel()
281283
282284void FastLoggerChannelsTest::testSplitterChannel ()
283285{
284- // Test SplitterChannel handling
285- // Note: SplitterChannel's internal channels are private, so FastLogger
286- // falls back to console output. Use NullChannel for test.
287- AutoPtr<NullChannel> pNullChannel (new NullChannel);
286+ // A SplitterChannel must fan out to ALL its children. Previously FastLogger
287+ // could not see inside a SplitterChannel and fell back to a single console
288+ // sink, losing file output and per-child patterns. Verify both children of
289+ // the splitter receive the (formatted) output.
290+ std::string file1 = TemporaryFile::tempName () + " _split1.log" ;
291+ std::string file2 = TemporaryFile::tempName () + " _split2.log" ;
292+
293+ AutoPtr<FileChannel> pFile1 (new FileChannel (file1));
294+ // Wrap the second file in a FormattingChannel so we also exercise pattern
295+ // extraction through the splitter.
296+ AutoPtr<FileChannel> pFile2 (new FileChannel (file2));
297+ AutoPtr<PatternFormatter> pFormatter (new PatternFormatter (" [%p] %t" ));
298+ AutoPtr<FormattingChannel> pFmt2 (new FormattingChannel (pFormatter, pFile2));
299+
300+ AutoPtr<SplitterChannel> pSplitter (new SplitterChannel);
301+ pSplitter->addChannel (pFile1);
302+ pSplitter->addChannel (pFmt2);
303+
304+ // SplitterChannel introspection API (used by FastLogger to map a splitter
305+ // onto multiple sinks).
306+ assertTrue (pSplitter->count () == 2 );
307+ assertTrue (pSplitter->getChannel (0 ).get () == pFile1.get ());
308+ assertTrue (pSplitter->getChannel (1 ).get () == pFmt2.get ());
309+ assertTrue (pSplitter->getChannel (2 ).isNull ());
310+ assertTrue (pSplitter->getChannel (-1 ).isNull ());
288311
289312 FastLogger& logger = FastLogger::get (" TestAdapters.SplitterChannel" );
290- logger.setChannel (pNullChannel); // Use null to avoid console spam
313+ logger.setChannel (pSplitter);
291314 logger.setLevel (Message::PRIO_TRACE);
315+ logger.information (" splitter routed message" );
316+ logger.flush ();
317+
318+ // Both children received output - not just a single console fallback.
319+ File f1 (file1);
320+ File f2 (file2);
321+ assertTrue (f1.exists () && f1.getSize () > 0 );
322+ assertTrue (f2.exists () && f2.getSize () > 0 );
323+
324+ // The message reached the file sinks (pattern was extracted via the splitter).
325+ Poco::FileInputStream fis (file2);
326+ std::string content;
327+ std::getline (fis, content);
328+ fis.close ();
329+ assertTrue (content.find (" splitter routed message" ) != std::string::npos);
330+
331+ try { f1.remove (); } catch (...) {}
332+ try { f2.remove (); } catch (...) {}
333+ }
292334
293- // Log messages
294- logger.information (" Test message to splitter channel (falls back to console)" );
295335
336+ void FastLoggerChannelsTest::testEventChannelSkipped ()
337+ {
338+ // EventChannel cannot be mapped to a Quill sink (FastLogger bypasses Poco's
339+ // Message/Channel pipeline). FastLogger must skip it gracefully - no crash,
340+ // no spurious duplicate console sink - while still serving the splitter's
341+ // other children. (A warning is printed to stderr; that is expected.)
342+ std::string tempFile = TemporaryFile::tempName () + " _evt.log" ;
343+
344+ AutoPtr<FileChannel> pFile (new FileChannel (tempFile));
345+ AutoPtr<EventChannel> pEvent (new EventChannel);
346+
347+ AutoPtr<SplitterChannel> pSplitter (new SplitterChannel);
348+ pSplitter->addChannel (pEvent);
349+ pSplitter->addChannel (pFile);
350+
351+ FastLogger& logger = FastLogger::get (" TestAdapters.SplitterEventChannel" );
352+ logger.setChannel (pSplitter);
353+ logger.setLevel (Message::PRIO_TRACE);
354+ logger.information (" message with an EventChannel sibling" );
296355 logger.flush ();
297356
298- // Test passes if no crash occurs
357+ // The FileChannel sibling still works despite the unsupported EventChannel.
358+ File file (tempFile);
359+ assertTrue (file.exists () && file.getSize () > 0 );
360+
361+ try { file.remove (); } catch (...) {}
299362}
300363
301364
@@ -346,6 +409,7 @@ CppUnit::Test* FastLoggerChannelsTest::suite()
346409 CppUnit_addTest (pSuite, FastLoggerChannelsTest, testFormattingChannel);
347410 CppUnit_addTest (pSuite, FastLoggerChannelsTest, testAsyncChannel);
348411 CppUnit_addTest (pSuite, FastLoggerChannelsTest, testSplitterChannel);
412+ CppUnit_addTest (pSuite, FastLoggerChannelsTest, testEventChannelSkipped);
349413#if defined(POCO_OS_FAMILY_UNIX) && !defined(POCO_NO_SYSLOG_CHANNEL)
350414 CppUnit_addTest (pSuite, FastLoggerChannelsTest, testSyslogChannel);
351415#endif
@@ -426,6 +490,12 @@ void FastLoggerChannelsTest::testSplitterChannel()
426490}
427491
428492
493+ void FastLoggerChannelsTest::testEventChannelSkipped ()
494+ {
495+ // FastLogger not enabled
496+ }
497+
498+
429499#if defined(POCO_OS_FAMILY_UNIX) && !defined(POCO_NO_SYSLOG_CHANNEL)
430500void FastLoggerChannelsTest::testSyslogChannel ()
431501{
0 commit comments