FileChannel: added "none" to the PURGE_AGE and PURGE_COUNT

This commit is contained in:
Marian Krivos
2012-04-29 10:58:27 +00:00
parent 53fe184bfa
commit c816693153
3 changed files with 409 additions and 372 deletions

View File

@@ -140,7 +140,7 @@ class Foundation_API FileChannel: public Channel
/// * local: Rotation strategy is based on local time. /// * local: Rotation strategy is based on local time.
/// ///
/// Archived log files can be compressed using the gzip compression /// Archived log files can be compressed using the gzip compression
/// method. Compressing can be controlled with the "compress" /// method. Compressing can be controlled with the "compression"
/// property. The following values for the "compress" property /// property. The following values for the "compress" property
/// are supported: /// are supported:
/// ///
@@ -154,6 +154,7 @@ class Foundation_API FileChannel: public Channel
/// ///
/// The purgeAge property can have the following values: /// The purgeAge property can have the following values:
/// ///
/// * "none" or "" no purging
/// * <n> [seconds] the maximum age is <n> seconds. /// * <n> [seconds] the maximum age is <n> seconds.
/// * <n> minutes: the maximum age is <n> minutes. /// * <n> minutes: the maximum age is <n> minutes.
/// * <n> hours: the maximum age is <n> hours. /// * <n> hours: the maximum age is <n> hours.
@@ -161,10 +162,10 @@ class Foundation_API FileChannel: public Channel
/// * <n> weeks: the maximum age is <n> weeks. /// * <n> weeks: the maximum age is <n> weeks.
/// * <n> months: the maximum age is <n> months, where a month has 30 days. /// * <n> months: the maximum age is <n> months, where a month has 30 days.
/// ///
/// The purgeCount property has an integer value that /// The purgeCount property has an integer value that specifies the maximum number
/// specifies the maximum number of archived log files. /// of archived log files. If the number is exceeded, archived log files are
/// If the number is exceeded, archived log files are /// deleted, starting with the oldest. When "none" or empty string are
/// deleted, starting with the oldest. /// supplied, they reset purgeCount to none (no purging).
/// ///
/// For a more lightweight file channel class, see SimpleFileChannel. /// For a more lightweight file channel class, see SimpleFileChannel.
{ {

View File

@@ -1,364 +1,395 @@
// //
// FileChannel.cpp // FileChannel.cpp
// //
// $Id: //poco/1.4/Foundation/src/FileChannel.cpp#1 $ // $Id: //poco/1.4/Foundation/src/FileChannel.cpp#1 $
// //
// Library: Foundation // Library: Foundation
// Package: Logging // Package: Logging
// Module: FileChannel // Module: FileChannel
// //
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors. // and Contributors.
// //
// Permission is hereby granted, free of charge, to any person or organization // Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by // obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute, // this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the // execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to // Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following: // do so, all subject to the following:
// //
// The copyright notices in the Software and this entire statement, including // The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer, // the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and // must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative // all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by // works are solely in the form of machine-executable object code generated by
// a source language processor. // a source language processor.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
#include "Poco/FileChannel.h" #include "Poco/FileChannel.h"
#include "Poco/ArchiveStrategy.h" #include "Poco/ArchiveStrategy.h"
#include "Poco/RotateStrategy.h" #include "Poco/RotateStrategy.h"
#include "Poco/PurgeStrategy.h" #include "Poco/PurgeStrategy.h"
#include "Poco/Message.h" #include "Poco/Message.h"
#include "Poco/NumberParser.h" #include "Poco/NumberParser.h"
#include "Poco/DateTimeFormatter.h" #include "Poco/DateTimeFormatter.h"
#include "Poco/DateTime.h" #include "Poco/DateTime.h"
#include "Poco/LocalDateTime.h" #include "Poco/LocalDateTime.h"
#include "Poco/String.h" #include "Poco/String.h"
#include "Poco/Timespan.h" #include "Poco/Timespan.h"
#include "Poco/Exception.h" #include "Poco/Exception.h"
#include "Poco/Ascii.h" #include "Poco/Ascii.h"
namespace Poco { namespace Poco {
const std::string FileChannel::PROP_PATH = "path"; const std::string FileChannel::PROP_PATH = "path";
const std::string FileChannel::PROP_ROTATION = "rotation"; const std::string FileChannel::PROP_ROTATION = "rotation";
const std::string FileChannel::PROP_ARCHIVE = "archive"; const std::string FileChannel::PROP_ARCHIVE = "archive";
const std::string FileChannel::PROP_TIMES = "times"; const std::string FileChannel::PROP_TIMES = "times";
const std::string FileChannel::PROP_COMPRESS = "compress"; const std::string FileChannel::PROP_COMPRESS = "compress";
const std::string FileChannel::PROP_PURGEAGE = "purgeAge"; const std::string FileChannel::PROP_PURGEAGE = "purgeAge";
const std::string FileChannel::PROP_PURGECOUNT = "purgeCount"; const std::string FileChannel::PROP_PURGECOUNT = "purgeCount";
FileChannel::FileChannel(): FileChannel::FileChannel():
_times("utc"), _times("utc"),
_compress(false), _compress(false),
_pFile(0), _pFile(0),
_pRotateStrategy(0), _pRotateStrategy(0),
_pArchiveStrategy(new ArchiveByNumberStrategy), _pArchiveStrategy(new ArchiveByNumberStrategy),
_pPurgeStrategy(0) _pPurgeStrategy(0)
{ {
} }
FileChannel::FileChannel(const std::string& path): FileChannel::FileChannel(const std::string& path):
_path(path), _path(path),
_times("utc"), _times("utc"),
_compress(false), _compress(false),
_pFile(0), _pFile(0),
_pRotateStrategy(0), _pRotateStrategy(0),
_pArchiveStrategy(new ArchiveByNumberStrategy), _pArchiveStrategy(new ArchiveByNumberStrategy),
_pPurgeStrategy(0) _pPurgeStrategy(0)
{ {
} }
FileChannel::~FileChannel() FileChannel::~FileChannel()
{ {
close(); close();
delete _pRotateStrategy; delete _pRotateStrategy;
delete _pArchiveStrategy; delete _pArchiveStrategy;
delete _pPurgeStrategy; delete _pPurgeStrategy;
} }
void FileChannel::open() void FileChannel::open()
{ {
FastMutex::ScopedLock lock(_mutex); FastMutex::ScopedLock lock(_mutex);
if (!_pFile) if (!_pFile)
{ {
_pFile = new LogFile(_path); _pFile = new LogFile(_path);
} }
} }
void FileChannel::close() void FileChannel::close()
{ {
FastMutex::ScopedLock lock(_mutex); FastMutex::ScopedLock lock(_mutex);
delete _pFile; delete _pFile;
_pFile = 0; _pFile = 0;
} }
void FileChannel::log(const Message& msg) void FileChannel::log(const Message& msg)
{ {
open(); open();
FastMutex::ScopedLock lock(_mutex); FastMutex::ScopedLock lock(_mutex);
if (_pRotateStrategy && _pArchiveStrategy && _pRotateStrategy->mustRotate(_pFile)) if (_pRotateStrategy && _pArchiveStrategy && _pRotateStrategy->mustRotate(_pFile))
{ {
try try
{ {
_pFile = _pArchiveStrategy->archive(_pFile); _pFile = _pArchiveStrategy->archive(_pFile);
purge(); purge();
} }
catch (...) catch (...)
{ {
_pFile = new LogFile(_path); _pFile = new LogFile(_path);
} }
// we must call mustRotate() again to give the // we must call mustRotate() again to give the
// RotateByIntervalStrategy a chance to write its timestamp // RotateByIntervalStrategy a chance to write its timestamp
// to the new file. // to the new file.
_pRotateStrategy->mustRotate(_pFile); _pRotateStrategy->mustRotate(_pFile);
} }
_pFile->write(msg.getText()); _pFile->write(msg.getText());
} }
void FileChannel::setProperty(const std::string& name, const std::string& value) void FileChannel::setProperty(const std::string& name, const std::string& value)
{ {
FastMutex::ScopedLock lock(_mutex); FastMutex::ScopedLock lock(_mutex);
if (name == PROP_TIMES) if (name == PROP_TIMES)
{ {
_times = value; _times = value;
if (!_rotation.empty()) if (!_rotation.empty())
setRotation(_rotation); setRotation(_rotation);
if (!_archive.empty()) if (!_archive.empty())
setArchive(_archive); setArchive(_archive);
} }
else if (name == PROP_PATH) else if (name == PROP_PATH)
_path = value; _path = value;
else if (name == PROP_ROTATION) else if (name == PROP_ROTATION)
setRotation(value); setRotation(value);
else if (name == PROP_ARCHIVE) else if (name == PROP_ARCHIVE)
setArchive(value); setArchive(value);
else if (name == PROP_COMPRESS) else if (name == PROP_COMPRESS)
setCompress(value); setCompress(value);
else if (name == PROP_PURGEAGE) else if (name == PROP_PURGEAGE)
setPurgeAge(value); setPurgeAge(value);
else if (name == PROP_PURGECOUNT) else if (name == PROP_PURGECOUNT)
setPurgeCount(value); setPurgeCount(value);
else else
Channel::setProperty(name, value); Channel::setProperty(name, value);
} }
std::string FileChannel::getProperty(const std::string& name) const std::string FileChannel::getProperty(const std::string& name) const
{ {
if (name == PROP_TIMES) if (name == PROP_TIMES)
return _times; return _times;
else if (name == PROP_PATH) else if (name == PROP_PATH)
return _path; return _path;
else if (name == PROP_ROTATION) else if (name == PROP_ROTATION)
return _rotation; return _rotation;
else if (name == PROP_ARCHIVE) else if (name == PROP_ARCHIVE)
return _archive; return _archive;
else if (name == PROP_COMPRESS) else if (name == PROP_COMPRESS)
return std::string(_compress ? "true" : "false"); return std::string(_compress ? "true" : "false");
else if (name == PROP_PURGEAGE) else if (name == PROP_PURGEAGE)
return _purgeAge; return _purgeAge;
else if (name == PROP_PURGECOUNT) else if (name == PROP_PURGECOUNT)
return _purgeCount; return _purgeCount;
else else
return Channel::getProperty(name); return Channel::getProperty(name);
} }
Timestamp FileChannel::creationDate() const Timestamp FileChannel::creationDate() const
{ {
if (_pFile) if (_pFile)
return _pFile->creationDate(); return _pFile->creationDate();
else else
return 0; return 0;
} }
UInt64 FileChannel::size() const UInt64 FileChannel::size() const
{ {
if (_pFile) if (_pFile)
return _pFile->size(); return _pFile->size();
else else
return 0; return 0;
} }
const std::string& FileChannel::path() const const std::string& FileChannel::path() const
{ {
return _path; return _path;
} }
void FileChannel::setRotation(const std::string& rotation) void FileChannel::setRotation(const std::string& rotation)
{ {
std::string::const_iterator it = rotation.begin(); std::string::const_iterator it = rotation.begin();
std::string::const_iterator end = rotation.end(); std::string::const_iterator end = rotation.end();
int n = 0; int n = 0;
while (it != end && Ascii::isSpace(*it)) ++it; while (it != end && Ascii::isSpace(*it)) ++it;
while (it != end && Ascii::isDigit(*it)) { n *= 10; n += *it++ - '0'; } while (it != end && Ascii::isDigit(*it)) { n *= 10; n += *it++ - '0'; }
while (it != end && Ascii::isSpace(*it)) ++it; while (it != end && Ascii::isSpace(*it)) ++it;
std::string unit; std::string unit;
while (it != end && Ascii::isAlpha(*it)) unit += *it++; while (it != end && Ascii::isAlpha(*it)) unit += *it++;
RotateStrategy* pStrategy = 0; RotateStrategy* pStrategy = 0;
if ((rotation.find(',') != std::string::npos) || (rotation.find(':') != std::string::npos)) if ((rotation.find(',') != std::string::npos) || (rotation.find(':') != std::string::npos))
{ {
if (_times == "utc") if (_times == "utc")
pStrategy = new RotateAtTimeStrategy<DateTime>(rotation); pStrategy = new RotateAtTimeStrategy<DateTime>(rotation);
else if (_times == "local") else if (_times == "local")
pStrategy = new RotateAtTimeStrategy<LocalDateTime>(rotation); pStrategy = new RotateAtTimeStrategy<LocalDateTime>(rotation);
else else
throw PropertyNotSupportedException("times", _times); throw PropertyNotSupportedException("times", _times);
} }
else if (unit == "daily") else if (unit == "daily")
pStrategy = new RotateByIntervalStrategy(Timespan(1*Timespan::DAYS)); pStrategy = new RotateByIntervalStrategy(Timespan(1*Timespan::DAYS));
else if (unit == "weekly") else if (unit == "weekly")
pStrategy = new RotateByIntervalStrategy(Timespan(7*Timespan::DAYS)); pStrategy = new RotateByIntervalStrategy(Timespan(7*Timespan::DAYS));
else if (unit == "monthly") else if (unit == "monthly")
pStrategy = new RotateByIntervalStrategy(Timespan(30*Timespan::DAYS)); pStrategy = new RotateByIntervalStrategy(Timespan(30*Timespan::DAYS));
else if (unit == "seconds") // for testing only else if (unit == "seconds") // for testing only
pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::SECONDS)); pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::SECONDS));
else if (unit == "minutes") else if (unit == "minutes")
pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::MINUTES)); pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::MINUTES));
else if (unit == "hours") else if (unit == "hours")
pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::HOURS)); pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::HOURS));
else if (unit == "days") else if (unit == "days")
pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::DAYS)); pStrategy = new RotateByIntervalStrategy(Timespan(n*Timespan::DAYS));
else if (unit == "weeks") else if (unit == "weeks")
pStrategy = new RotateByIntervalStrategy(Timespan(n*7*Timespan::DAYS)); pStrategy = new RotateByIntervalStrategy(Timespan(n*7*Timespan::DAYS));
else if (unit == "months") else if (unit == "months")
pStrategy = new RotateByIntervalStrategy(Timespan(n*30*Timespan::DAYS)); pStrategy = new RotateByIntervalStrategy(Timespan(n*30*Timespan::DAYS));
else if (unit == "K") else if (unit == "K")
pStrategy = new RotateBySizeStrategy(n*1024); pStrategy = new RotateBySizeStrategy(n*1024);
else if (unit == "M") else if (unit == "M")
pStrategy = new RotateBySizeStrategy(n*1024*1024); pStrategy = new RotateBySizeStrategy(n*1024*1024);
else if (unit.empty()) else if (unit.empty())
pStrategy = new RotateBySizeStrategy(n); pStrategy = new RotateBySizeStrategy(n);
else if (unit != "never") else if (unit != "never")
throw InvalidArgumentException("rotation", rotation); throw InvalidArgumentException("rotation", rotation);
delete _pRotateStrategy; delete _pRotateStrategy;
_pRotateStrategy = pStrategy; _pRotateStrategy = pStrategy;
_rotation = rotation; _rotation = rotation;
} }
void FileChannel::setArchive(const std::string& archive) void FileChannel::setArchive(const std::string& archive)
{ {
ArchiveStrategy* pStrategy = 0; ArchiveStrategy* pStrategy = 0;
if (archive == "number") if (archive == "number")
{ {
pStrategy = new ArchiveByNumberStrategy; pStrategy = new ArchiveByNumberStrategy;
} }
else if (archive == "timestamp") else if (archive == "timestamp")
{ {
if (_times == "utc") if (_times == "utc")
pStrategy = new ArchiveByTimestampStrategy<DateTime>; pStrategy = new ArchiveByTimestampStrategy<DateTime>;
else if (_times == "local") else if (_times == "local")
pStrategy = new ArchiveByTimestampStrategy<LocalDateTime>; pStrategy = new ArchiveByTimestampStrategy<LocalDateTime>;
else else
throw PropertyNotSupportedException("times", _times); throw PropertyNotSupportedException("times", _times);
} }
else throw InvalidArgumentException("archive", archive); else throw InvalidArgumentException("archive", archive);
delete _pArchiveStrategy; delete _pArchiveStrategy;
pStrategy->compress(_compress); pStrategy->compress(_compress);
_pArchiveStrategy = pStrategy; _pArchiveStrategy = pStrategy;
_archive = archive; _archive = archive;
} }
void FileChannel::setCompress(const std::string& compress) void FileChannel::setCompress(const std::string& compress)
{ {
_compress = icompare(compress, "true") == 0; _compress = icompare(compress, "true") == 0;
if (_pArchiveStrategy) if (_pArchiveStrategy)
_pArchiveStrategy->compress(_compress); _pArchiveStrategy->compress(_compress);
} }
void FileChannel::setPurgeAge(const std::string& age) void FileChannel::setPurgeAge(const std::string& age)
{ {
std::string::const_iterator it = age.begin(); delete _pPurgeStrategy;
std::string::const_iterator end = age.end(); _pPurgeStrategy = 0;
int n = 0; _purgeAge = "none";
while (it != end && Ascii::isSpace(*it)) ++it; if (age.empty() || 0 == icompare(age, "none"))
while (it != end && Ascii::isDigit(*it)) { n *= 10; n += *it++ - '0'; } return;
while (it != end && Ascii::isSpace(*it)) ++it;
std::string unit; std::string::const_iterator it = age.begin();
while (it != end && Ascii::isAlpha(*it)) unit += *it++; std::string::const_iterator end = age.end();
Timespan::TimeDiff factor = Timespan::SECONDS; int n = 0;
if (unit == "minutes") while (it != end && Ascii::isSpace(*it))
factor = Timespan::MINUTES; ++it;
else if (unit == "hours") while (it != end && Ascii::isDigit(*it))
factor = Timespan::HOURS; {
else if (unit == "days") n *= 10;
factor = Timespan::DAYS; n += *it++ - '0';
else if (unit == "weeks") }
factor = 7*Timespan::DAYS; while (it != end && Ascii::isSpace(*it))
else if (unit == "months") ++it;
factor = 30*Timespan::DAYS; std::string unit;
else if (unit != "seconds") while (it != end && Ascii::isAlpha(*it))
throw InvalidArgumentException("purgeAge", age); unit += *it++;
delete _pPurgeStrategy; Timespan::TimeDiff factor = Timespan::SECONDS;
_pPurgeStrategy = new PurgeByAgeStrategy(Timespan(factor*n)); if (unit == "minutes")
_purgeAge = age; factor = Timespan::MINUTES;
} else if (unit == "hours")
factor = Timespan::HOURS;
else if (unit == "days")
void FileChannel::setPurgeCount(const std::string& count) factor = Timespan::DAYS;
{ else if (unit == "weeks")
std::string::const_iterator it = count.begin(); factor = 7*Timespan::DAYS;
std::string::const_iterator end = count.end(); else if (unit == "months")
int n = 0; factor = 30 * Timespan::DAYS;
while (it != end && Ascii::isSpace(*it)) ++it; else if (unit != "seconds")
while (it != end && Ascii::isDigit(*it)) { n *= 10; n += *it++ - '0'; } throw InvalidArgumentException("purgeAge", age);
while (it != end && Ascii::isSpace(*it)) ++it;
if (0 == n)
delete _pPurgeStrategy; throw InvalidArgumentException("Zero is not valid purge age.");
_pPurgeStrategy = new PurgeByCountStrategy(n);
_purgeCount = count; _pPurgeStrategy = new PurgeByAgeStrategy(Timespan(factor * n));
} _purgeAge = age;
}
void FileChannel::purge()
{ void FileChannel::setPurgeCount(const std::string& count)
if (_pPurgeStrategy) {
{ delete _pPurgeStrategy;
try _pPurgeStrategy = 0;
{ _purgeAge = "none";
_pPurgeStrategy->purge(_path); if (count.empty() || 0 == icompare(count, "none"))
} return;
catch (...)
{ int n = 0;
} std::string::const_iterator it = count.begin();
} std::string::const_iterator end = count.end();
}
while (it != end && Ascii::isSpace(*it))
++it;
} // namespace Poco while (it != end && Ascii::isDigit(*it))
{
n *= 10;
n += *it++ - '0';
}
while (it != end && Ascii::isSpace(*it))
++it;
if (0 == n)
throw InvalidArgumentException("Zero is not valid purge count.");
_pPurgeStrategy = new PurgeByCountStrategy(n);
_purgeCount = count;
}
void FileChannel::purge()
{
if (_pPurgeStrategy)
{
try
{
_pPurgeStrategy->purge(_path);
}
catch (...)
{
}
}
}
} // namespace Poco

View File

@@ -72,9 +72,14 @@ public:
static CppUnit::Test* suite(); static CppUnit::Test* suite();
private: private:
template <class D> std::string rotation(TimeRotation rtype) const; template <class D> std::string rotation(TimeRotation rtype) const;
void remove(const std::string& baseName); void remove(const std::string& baseName);
std::string filename() const; std::string filename() const;
void purgeAge(const std::string& purgeAge);
void noPurgeAge(const std::string& purgeAge);
void purgeCount(const std::string& pc);
void noPurgeCount(const std::string& pc);
}; };