diff --git a/Foundation/src/LogFile_STD.cpp b/Foundation/src/LogFile_STD.cpp index bfe1c292a..e5c658742 100644 --- a/Foundation/src/LogFile_STD.cpp +++ b/Foundation/src/LogFile_STD.cpp @@ -16,6 +16,7 @@ #include "Poco/File.h" #include "Poco/Exception.h" +#include namespace Poco { @@ -40,17 +41,26 @@ LogFileImpl::~LogFileImpl() void LogFileImpl::writeImpl(const std::string& text, bool flush) { std::streampos pos = _str.tellp(); - _str << text; - if (flush) - _str << std::endl; - else - _str << "\n"; + + _str << text << '\n'; + + // Flush the stream buffer to file to match the implementation on Windows + _str.flush(); + if (!_str.good()) { _str.clear(); _str.seekp(pos); throw WriteFileException(_path); } + + if (flush) + { + // Sync the file to disk as it is done on Windows + if (fsync(_str.nativeHandle()) != 0) + throw WriteFileException(_path); + } + _size = static_cast(_str.tellp()); } diff --git a/Foundation/src/LogFile_WIN32U.cpp b/Foundation/src/LogFile_WIN32U.cpp index 055e9c585..293031072 100644 --- a/Foundation/src/LogFile_WIN32U.cpp +++ b/Foundation/src/LogFile_WIN32U.cpp @@ -17,6 +17,8 @@ #include "Poco/Exception.h" #include "Poco/UnicodeConverter.h" +// TODO: LogStream shall use FileOutputStream for all implementations (see LogStream_STD) +// TODO: Implement flushToDisk function in FileOutputStream. namespace Poco { diff --git a/Foundation/testsuite/src/FileChannelTest.cpp b/Foundation/testsuite/src/FileChannelTest.cpp index 8d0554ec2..3cf23228f 100644 --- a/Foundation/testsuite/src/FileChannelTest.cpp +++ b/Foundation/testsuite/src/FileChannelTest.cpp @@ -86,6 +86,59 @@ void FileChannelTest::testRotateNever() } +void FileChannelTest::testFlushing() +{ + std::string name = filename(); + try + { + AutoPtr pChannel = new FileChannel(name); + pChannel->setProperty(FileChannel::PROP_FLUSH, "false"); + pChannel->open(); + Message msg("source", "01234567890123456789", Message::PRIO_INFORMATION); + pChannel->log(msg); + + // File shall be there and have content after writing first message. + File f(name); + assertTrue (f.exists()); + assertTrue (f.getSize() >= 20); + + Timestamp::TimeDiff noFlushTime; + { + Timestamp start; + for (int i = 0; i < 2000; ++i) + { + pChannel->log(msg); + } + pChannel->close(); + Timestamp end; + noFlushTime = end-start; + } + Timestamp::TimeDiff flushTime; + { + pChannel->setProperty(FileChannel::PROP_FLUSH, "true"); + pChannel->open(); + Timestamp start; + for (int i = 0; i < 2000; ++i) + { + pChannel->log(msg); + } + pChannel->close(); + Timestamp end; + flushTime = end-start; + } + + // Writing to channel with flushing is expected to be slower. + assertTrue(flushTime > noFlushTime); + } + catch (...) + { + remove(name); + throw; + } + remove(name); +} + + void FileChannelTest::testRotateBySize() { std::string name = filename(); @@ -832,6 +885,7 @@ CppUnit::Test* FileChannelTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FileChannelTest"); CppUnit_addTest(pSuite, FileChannelTest, testRotateNever); + CppUnit_addTest(pSuite, FileChannelTest, testFlushing); CppUnit_addTest(pSuite, FileChannelTest, testRotateBySize); CppUnit_addTest(pSuite, FileChannelTest, testRotateByAge); CppUnit_addLongTest(pSuite, FileChannelTest, testRotateAtTimeDayUTC); diff --git a/Foundation/testsuite/src/FileChannelTest.h b/Foundation/testsuite/src/FileChannelTest.h index 8ed56764b..327659dcf 100644 --- a/Foundation/testsuite/src/FileChannelTest.h +++ b/Foundation/testsuite/src/FileChannelTest.h @@ -32,6 +32,7 @@ public: ~FileChannelTest(); void testRotateNever(); + void testFlushing(); void testRotateBySize(); void testRotateByAge(); void testRotateAtTimeDayUTC();