diff --git a/Foundation/include/Poco/FileChannel.h b/Foundation/include/Poco/FileChannel.h index aa31d9095..9eb36320d 100644 --- a/Foundation/include/Poco/FileChannel.h +++ b/Foundation/include/Poco/FileChannel.h @@ -1,7 +1,7 @@ // // FileChannel.h // -// $Id: //poco/svn/Foundation/include/Poco/FileChannel.h#2 $ +// $Id: //poco/1.3/Foundation/include/Poco/FileChannel.h#2 $ // // Library: Foundation // Package: Logging @@ -87,6 +87,8 @@ class Foundation_API FileChannel: public Channel /// * daily: the file is rotated daily /// * weekly: the file is rotated every seven days /// * monthly: the file is rotated every 30 days + /// * minutes: the file is rotated every minutes, + /// where is an integer greater than zero. /// * hours: the file is rotated every hours, where /// is an integer greater than zero. /// * days: the file is rotated every days, where @@ -103,6 +105,14 @@ class Foundation_API FileChannel: public Channel /// * M: the file is rotated when its size exceeds /// Megabytes. /// + /// NOTE: For periodic log file rotation (daily, weekly, monthly, etc.), + /// the date and time of log file creation or last rotation is + /// written into the first line of the log file. This is because + /// there is no reliable way to find out the real creation date of + /// a file on many platforms (e.g., most Unix platforms do not + /// provide the creation date, and Windows has its own issues + /// with its "File System Tunneling Capabilities"). + /// /// Using the "archive" property it is possible to specify /// how archived log files are named. The following values /// for the "archive" property are supported: @@ -151,14 +161,10 @@ class Foundation_API FileChannel: public Channel /// * weeks: the maximum age is weeks. /// * months: the maximum age is months, where a month has 30 days. /// - /// Both empty string ("") and n == 0 indicate no purging. - /// /// The purgeCount property has an integer value that /// specifies the maximum number of archived log files. /// If the number is exceeded, archived log files are /// deleted, starting with the oldest. - /// - /// Both empty string ("") and "0" for indicate no purging. /// /// For a more lightweight file channel class, see SimpleFileChannel. { diff --git a/Foundation/include/Poco/RotateStrategy.h b/Foundation/include/Poco/RotateStrategy.h index 12a5f3176..2afd6c2c1 100644 --- a/Foundation/include/Poco/RotateStrategy.h +++ b/Foundation/include/Poco/RotateStrategy.h @@ -1,7 +1,7 @@ // // RotateStrategy.h // -// $Id: //poco/svn/Foundation/include/Poco/RotateStrategy.h#2 $ +// $Id: //poco/1.3/Foundation/include/Poco/RotateStrategy.h#3 $ // // Library: Foundation // Package: Logging @@ -114,7 +114,7 @@ public: { } - bool mustRotate(LogFile* pFile = 0) + bool mustRotate(LogFile* pFile) { if (DT() >= _threshold) { @@ -149,6 +149,11 @@ private: class Foundation_API RotateByIntervalStrategy: public RotateStrategy /// The file is rotated when the log file /// exceeds a given age. + /// + /// For this to work reliably across all platforms and file systems + /// (there are severe issues on most platforms finding out the real + /// creation date of a file), the creation date of the file is + /// written into the log file as the first entry. { public: RotateByIntervalStrategy(const Timespan& span); @@ -157,6 +162,8 @@ public: private: Timespan _span; + Timestamp _lastRotate; + static const std::string ROTATE_TEXT; }; diff --git a/Foundation/include/Poco/Unicode.h b/Foundation/include/Poco/Unicode.h index 7ba640061..797d1edd0 100644 --- a/Foundation/include/Poco/Unicode.h +++ b/Foundation/include/Poco/Unicode.h @@ -1,7 +1,7 @@ // // Unicode.h // -// $Id: //poco/1.3/Foundation/include/Poco/Unicode.h#1 $ +// $Id: //poco/1.3/Foundation/include/Poco/Unicode.h#2 $ // // Library: Foundation // Package: Text diff --git a/Foundation/src/FileChannel.cpp b/Foundation/src/FileChannel.cpp index 03a2d2842..979aca984 100644 --- a/Foundation/src/FileChannel.cpp +++ b/Foundation/src/FileChannel.cpp @@ -1,7 +1,7 @@ // // FileChannel.cpp // -// $Id: //poco/svn/Foundation/src/FileChannel.cpp#2 $ +// $Id: //poco/1.3/Foundation/src/FileChannel.cpp#3 $ // // Library: Foundation // Package: Logging @@ -130,6 +130,10 @@ void FileChannel::log(const Message& msg) { _pFile = new LogFile(_path); } + // we must call mustRotate() again to give the + // RotateByIntervalStrategy a chance to write its timestamp + // to the new file. + _pRotateStrategy->mustRotate(_pFile); } _pFile->write(msg.getText()); } @@ -240,6 +244,8 @@ void FileChannel::setRotation(const std::string& rotation) pStrategy = new RotateByIntervalStrategy(Timespan(30*Timespan::DAYS)); else if (unit == "seconds") // for testing only pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::SECONDS)); + else if (unit == "minutes") + pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::MINUTES)); else if (unit == "hours") pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::HOURS)); else if (unit == "days") @@ -296,14 +302,6 @@ void FileChannel::setCompress(const std::string& compress) void FileChannel::setPurgeAge(const std::string& age) { - if (age.empty()) - { - delete _pPurgeStrategy; - _pPurgeStrategy = 0; - _purgeAge.clear(); - return; - } - std::string::const_iterator it = age.begin(); std::string::const_iterator end = age.end(); int n = 0; @@ -328,12 +326,7 @@ void FileChannel::setPurgeAge(const std::string& age) throw InvalidArgumentException("purgeAge", age); delete _pPurgeStrategy; - - if (0 == n || age.empty()) - _pPurgeStrategy = 0; - else - _pPurgeStrategy = new PurgeByAgeStrategy(Timespan(factor*n)); - + _pPurgeStrategy = new PurgeByAgeStrategy(Timespan(factor*n)); _purgeAge = age; } @@ -348,12 +341,7 @@ void FileChannel::setPurgeCount(const std::string& count) while (it != end && std::isspace(*it)) ++it; delete _pPurgeStrategy; - - if (0 == n || count.empty()) - _pPurgeStrategy = 0; - else - _pPurgeStrategy = new PurgeByCountStrategy(n); - + _pPurgeStrategy = new PurgeByCountStrategy(n); _purgeCount = count; } diff --git a/Foundation/src/RotateStrategy.cpp b/Foundation/src/RotateStrategy.cpp index 6580b37ae..b394d2584 100644 --- a/Foundation/src/RotateStrategy.cpp +++ b/Foundation/src/RotateStrategy.cpp @@ -1,7 +1,7 @@ // // RotateStrategy.cpp // -// $Id: //poco/svn/Foundation/src/RotateStrategy.cpp#2 $ +// $Id: //poco/1.3/Foundation/src/RotateStrategy.cpp#2 $ // // Library: Foundation // Package: Logging @@ -35,6 +35,10 @@ #include "Poco/RotateStrategy.h" +#include "Poco/FileStream.h" +#include "Poco/DateTimeParser.h" +#include "Poco/DateTimeFormatter.h" +#include "Poco/DateTimeFormat.h" namespace Poco { @@ -60,7 +64,12 @@ RotateStrategy::~RotateStrategy() // -RotateByIntervalStrategy::RotateByIntervalStrategy(const Timespan& span): _span(span) +const std::string RotateByIntervalStrategy::ROTATE_TEXT("# Log file created/rotated "); + + +RotateByIntervalStrategy::RotateByIntervalStrategy(const Timespan& span): + _span(span), + _lastRotate(0) { if (span.totalMicroseconds() <= 0) throw InvalidArgumentException("time span must be greater than zero"); } @@ -73,8 +82,31 @@ RotateByIntervalStrategy::~RotateByIntervalStrategy() bool RotateByIntervalStrategy::mustRotate(LogFile* pFile) { + if (_lastRotate == 0 || pFile->size() == 0) + { + if (pFile->size() != 0) + { + Poco::FileInputStream istr(pFile->path()); + std::string tag; + std::getline(istr, tag); + if (tag.compare(0, ROTATE_TEXT.size(), ROTATE_TEXT) == 0) + { + std::string timestamp(tag, ROTATE_TEXT.size()); + int tzd; + _lastRotate = DateTimeParser::parse(DateTimeFormat::RFC1036_FORMAT, timestamp, tzd).timestamp(); + } + else _lastRotate = pFile->creationDate(); + } + else + { + _lastRotate.update(); + std::string tag(ROTATE_TEXT); + tag += DateTimeFormatter::format(_lastRotate, DateTimeFormat::RFC1036_FORMAT); + pFile->write(tag); + } + } Timestamp now; - return _span <= now - pFile->creationDate(); + return _span <= now - _lastRotate; }