Author: tschoening Date: Sun Feb 9 18:26:33 2014 New Revision: 1566343 URL: http://svn.apache.org/r1566343 Log: LOGCXX-412: Log4cxx doesn't roll normally when working under multiple processes environment
Modified: incubator/log4cxx/trunk/src/changes/changes.xml incubator/log4cxx/trunk/src/main/cpp/fixedwindowrollingpolicy.cpp incubator/log4cxx/trunk/src/main/cpp/outputstream.cpp incubator/log4cxx/trunk/src/main/cpp/outputstreamwriter.cpp incubator/log4cxx/trunk/src/main/cpp/rollingfileappender.cpp incubator/log4cxx/trunk/src/main/cpp/timebasedrollingpolicy.cpp incubator/log4cxx/trunk/src/main/cpp/writer.cpp incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/fileoutputstream.h incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstream.h incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstreamwriter.h incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/writer.h incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingpolicybase.h incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/timebasedrollingpolicy.h incubator/log4cxx/trunk/src/main/include/log4cxx/writerappender.h Modified: incubator/log4cxx/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/changes/changes.xml?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/changes/changes.xml (original) +++ incubator/log4cxx/trunk/src/changes/changes.xml Sun Feb 9 18:26:33 2014 @@ -62,6 +62,7 @@ <action issue="LOGCXX-367" type="fix">Build fails on Linux with g++ 4.4</action> <action issue="LOGCXX-381" type="fix">Pkgconfig can't find dependencies properly if log4cxx built statically</action> <action issue="LOGCXX-382" type="fix">Mingw build type conversion error</action> + <action issue="LOGCXX-412" type="fix">Log4cxx doesn't roll normally when working under multiple processes environment</action> <action issue="LOGCXX-413" type="fix">log4cxx doesn't compile on openembedded (due to Alex Zbarcea)</action> <action issue="LOGCXX-414" type="fix">possibly wrong use of autotools docdir (due to Alex Zbarcea)</action> <action issue="LOGCXX-415" type="fix">Empty XML configuration file causes crash</action> Modified: incubator/log4cxx/trunk/src/main/cpp/fixedwindowrollingpolicy.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/fixedwindowrollingpolicy.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/fixedwindowrollingpolicy.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/fixedwindowrollingpolicy.cpp Sun Feb 9 18:26:33 2014 @@ -160,8 +160,13 @@ RolloverDescriptionPtr FixedWindowRollin new FileRenameAction( File().setPath(currentFileName), File().setPath(renameTo), false); +#ifdef LOG4CXX_MULTI_PROCESS + desc = new RolloverDescription( + currentFileName, true, renameAction, compressAction); +#else desc = new RolloverDescription( currentFileName, false, renameAction, compressAction); +#endif } return desc; Modified: incubator/log4cxx/trunk/src/main/cpp/outputstream.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/outputstream.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/outputstream.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/outputstream.cpp Sun Feb 9 18:26:33 2014 @@ -17,6 +17,7 @@ #include <log4cxx/logstring.h> #include <log4cxx/helpers/outputstream.h> +#include <stdexcept> using namespace log4cxx; using namespace log4cxx::helpers; @@ -28,3 +29,13 @@ OutputStream::OutputStream() { OutputStream::~OutputStream() { } + +#ifdef LOG4CXX_MULTI_PROCESS +apr_file_t* OutputStream::getFilePtr(){ + throw std::logic_error("getFilePtr must be implemented in the derived class that you are using"); +} + +OutputStream& OutputStream::getFileOutPutStreamPtr(){ + throw std::logic_error("getFileOutPutStreamPtr must be implemented in the derived class that you are using"); +} +#endif Modified: incubator/log4cxx/trunk/src/main/cpp/outputstreamwriter.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/outputstreamwriter.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/outputstreamwriter.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/outputstreamwriter.cpp Sun Feb 9 18:26:33 2014 @@ -58,9 +58,15 @@ void OutputStreamWriter::flush(Pool& p) void OutputStreamWriter::write(const LogString& str, Pool& p) { if (str.length() > 0) { +#ifdef LOG4CXX_MULTI_PROCESS + size_t bufSize = str.length() * 2; + char *rawbuf = new char[bufSize]; + ByteBuffer buf(rawbuf, (size_t) bufSize); +#else enum { BUFSIZE = 1024 }; char rawbuf[BUFSIZE]; ByteBuffer buf(rawbuf, (size_t) BUFSIZE); +#endif enc->reset(); LogString::const_iterator iter = str.begin(); while(iter != str.end()) { @@ -69,10 +75,14 @@ void OutputStreamWriter::write(const Log out->write(buf, p); buf.clear(); } + CharsetEncoder::encode(enc, str, iter, buf); enc->flush(buf); buf.flip(); out->write(buf, p); +#ifdef LOG4CXX_MULTI_PROCESS + delete []rawbuf; +#endif } } Modified: incubator/log4cxx/trunk/src/main/cpp/rollingfileappender.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/rollingfileappender.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/rollingfileappender.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/rollingfileappender.cpp Sun Feb 9 18:26:33 2014 @@ -19,6 +19,19 @@ #pragma warning ( disable: 4231 4251 4275 4786 ) #endif +#ifdef LOG4CXX_MULTI_PROCESS +#include <apr_portable.h> +#include <libgen.h> +#include <apr_file_io.h> +#include <apr_atomic.h> +#include <apr_mmap.h> +#ifndef MAX_FILE_LEN +#define MAX_FILE_LEN 2048 +#endif +#include <log4cxx/pattern/filedatepatternconverter.h> +#include <log4cxx/helpers/date.h> +#endif + #include <log4cxx/rolling/rollingfileappender.h> #include <log4cxx/helpers/loglog.h> #include <log4cxx/helpers/synchronized.h> @@ -41,7 +54,7 @@ IMPLEMENT_LOG4CXX_OBJECT(RollingFileAppe /** * Construct a new instance. */ -RollingFileAppenderSkeleton::RollingFileAppenderSkeleton() { +RollingFileAppenderSkeleton::RollingFileAppenderSkeleton() : _event(NULL){ } RollingFileAppender::RollingFileAppender() { @@ -115,9 +128,20 @@ void RollingFileAppenderSkeleton::activa + getName()); } } - } +#ifdef LOG4CXX_MULTI_PROCESS +void RollingFileAppenderSkeleton::releaseFileLock(apr_file_t* lock_file){ + if (lock_file){ + apr_status_t stat = apr_file_unlock(lock_file); + if (stat != APR_SUCCESS){ + LogLog::warn(LOG4CXX_STR("flock: unlock failed")); + } + apr_file_close(lock_file); + lock_file = NULL; + } +} +#endif /** Implements the usual roll over behaviour. @@ -134,105 +158,196 @@ void RollingFileAppenderSkeleton::activa * @return true if rollover performed. */ bool RollingFileAppenderSkeleton::rollover(Pool& p) { - // - // can't roll without a policy - // - if (rollingPolicy != NULL) { + // + // can't roll without a policy + // + if (rollingPolicy != NULL) { + + { + synchronized sync(mutex); -{ - synchronized sync(mutex); - try { - RolloverDescriptionPtr rollover1(rollingPolicy->rollover(getFile(), p)); - - if (rollover1 != NULL) { - if (rollover1->getActiveFileName() == getFile()) { - closeWriter(); - - bool success = true; - - if (rollover1->getSynchronous() != NULL) { - success = false; - - try { - success = rollover1->getSynchronous()->execute(p); - } catch (std::exception& ex) { - LogLog::warn(LOG4CXX_STR("Exception on rollover")); - } +#ifdef LOG4CXX_MULTI_PROCESS + std::string fileName(getFile()); + RollingPolicyBase *basePolicy = dynamic_cast<RollingPolicyBase* >(&(*rollingPolicy)); + apr_time_t n = apr_time_now(); + ObjectPtr obj(new Date(n)); + LogString fileNamePattern; + if (basePolicy){ + if (basePolicy->getPatternConverterList().size()){ + (*(basePolicy->getPatternConverterList().begin()))->format(obj, fileNamePattern, p); + fileName = std::string(fileNamePattern); + } } - if (success) { - if (rollover1->getAppend()) { - fileLength = File().setPath(rollover1->getActiveFileName()).length(p); - } else { - fileLength = 0; - } - - // - // async action not yet implemented - // - ActionPtr asyncAction(rollover1->getAsynchronous()); - if (asyncAction != NULL) { - asyncAction->execute(p); - } - - setFile( - rollover1->getActiveFileName(), rollover1->getAppend(), - bufferedIO, bufferSize, p); - } else { - setFile( - rollover1->getActiveFileName(), true, bufferedIO, bufferSize, p); + bool bAlreadyRolled = true; + char szDirName[MAX_FILE_LEN] = {'\0'}; + char szBaseName[MAX_FILE_LEN] = {'\0'}; + char szUid[MAX_FILE_LEN] = {'\0'}; + memcpy(szDirName, fileName.c_str(), fileName.size() > MAX_FILE_LEN ? MAX_FILE_LEN : fileName.size()); + memcpy(szBaseName, fileName.c_str(), fileName.size() > MAX_FILE_LEN ? MAX_FILE_LEN : fileName.size()); + apr_uid_t uid; + apr_gid_t groupid; + apr_status_t stat = apr_uid_current(&uid, &groupid, pool.getAPRPool()); + if (stat == APR_SUCCESS){ + snprintf(szUid, MAX_FILE_LEN, "%u", uid); } - } else { - OutputStreamPtr os(new FileOutputStream( - rollover1->getActiveFileName(), rollover1->getAppend())); - WriterPtr newWriter(createWriter(os)); - closeWriter(); - setFile(rollover1->getActiveFileName()); - setWriter(newWriter); - - bool success = true; - - if (rollover1->getSynchronous() != NULL) { - success = false; - - try { - success = rollover1->getSynchronous()->execute(p); - } catch (std::exception& ex) { - LogLog::warn(LOG4CXX_STR("Exception during rollover")); - } + + const std::string lockname = std::string(::dirname(szDirName)) + "/." + ::basename(szBaseName) + szUid + ".lock"; + apr_file_t* lock_file; + stat = apr_file_open(&lock_file, lockname.c_str(), APR_CREATE | APR_READ | APR_WRITE, APR_OS_DEFAULT, p.getAPRPool()); + if (stat != APR_SUCCESS) { + std::string err = "lockfile return error: open lockfile failed. "; + err += (strerror(errno)); + LogLog::warn(LOG4CXX_STR(err.c_str())); + bAlreadyRolled = false; + lock_file = NULL; + }else{ + stat = apr_file_lock(lock_file, APR_FLOCK_EXCLUSIVE); + if (stat != APR_SUCCESS){ + std::string err = "apr_file_lock: lock failed. "; + err += (strerror(errno)); + LogLog::warn(LOG4CXX_STR(err.c_str())); + bAlreadyRolled = false; + } + else { + if (_event) + triggeringPolicy->isTriggeringEvent(this, *_event, getFile(), getFileLength()); + } } - if (success) { - if (rollover1->getAppend()) { - fileLength = File().setPath(rollover1->getActiveFileName()).length(p); - } else { - fileLength = 0; - } - - // - // async action not yet implemented - // - ActionPtr asyncAction(rollover1->getAsynchronous()); - if (asyncAction != NULL) { - asyncAction->execute(p); - } + if (bAlreadyRolled){ + apr_finfo_t finfo1, finfo2; + apr_status_t st1, st2; + apr_file_t* _fd = getWriter()->getOutPutStreamPtr()->getFileOutPutStreamPtr().getFilePtr(); + st1 = apr_file_info_get(&finfo1, APR_FINFO_IDENT, _fd); + if (st1 != APR_SUCCESS){ + LogLog::warn(LOG4CXX_STR("apr_file_info_get failed")); + } + + st2 = apr_stat(&finfo2, std::string(getFile()).c_str(), APR_FINFO_IDENT, p.getAPRPool()); + if (st2 != APR_SUCCESS){ + LogLog::warn(LOG4CXX_STR("apr_stat failed.")); + } + + bAlreadyRolled = ((st1 == APR_SUCCESS) && (st2 == APR_SUCCESS) + && ((finfo1.device != finfo2.device) || (finfo1.inode != finfo2.inode))); } + + if (!bAlreadyRolled){ +#endif + try { + RolloverDescriptionPtr rollover1(rollingPolicy->rollover(getFile(), p)); + if (rollover1 != NULL) { + if (rollover1->getActiveFileName() == getFile()) { + closeWriter(); + + bool success = true; + if (rollover1->getSynchronous() != NULL) { + success = false; + + try { + success = rollover1->getSynchronous()->execute(p); + } catch (std::exception& ex) { + LogLog::warn(LOG4CXX_STR("Exception on rollover")); + } + } + + if (success) { + if (rollover1->getAppend()) { + fileLength = File().setPath(rollover1->getActiveFileName()).length(p); + } else { + fileLength = 0; + } + + // + // async action not yet implemented + // + ActionPtr asyncAction(rollover1->getAsynchronous()); + if (asyncAction != NULL) { + asyncAction->execute(p); + } + + setFile( + rollover1->getActiveFileName(), rollover1->getAppend(), + bufferedIO, bufferSize, p); + } else { + setFile( + rollover1->getActiveFileName(), true, bufferedIO, bufferSize, p); + } + } else { + OutputStreamPtr os(new FileOutputStream( + rollover1->getActiveFileName(), rollover1->getAppend())); + WriterPtr newWriter(createWriter(os)); + closeWriter(); + setFile(rollover1->getActiveFileName()); + setWriter(newWriter); + + bool success = true; + + if (rollover1->getSynchronous() != NULL) { + success = false; + + try { + success = rollover1->getSynchronous()->execute(p); + } catch (std::exception& ex) { + LogLog::warn(LOG4CXX_STR("Exception during rollover")); + } + } + + if (success) { + if (rollover1->getAppend()) { + fileLength = File().setPath(rollover1->getActiveFileName()).length(p); + } else { + fileLength = 0; + } + + // + // async action not yet implemented + // + ActionPtr asyncAction(rollover1->getAsynchronous()); + if (asyncAction != NULL) { + asyncAction->execute(p); + } + } - writeHeader(p); - } + writeHeader(p); + } - return true; +#ifdef LOG4CXX_MULTI_PROCESS + releaseFileLock(lock_file); +#endif + return true; + } + } catch (std::exception& ex) { + LogLog::warn(LOG4CXX_STR("Exception during rollover")); + } +#ifdef LOG4CXX_MULTI_PROCESS + }else{ + reopenLatestFile(p); + } + releaseFileLock(lock_file); +#endif } - } catch (std::exception& ex) { - LogLog::warn(LOG4CXX_STR("Exception during rollover")); - } } + return false; +} - } - - return false; +#ifdef LOG4CXX_MULTI_PROCESS +/** + * re-open current file when its own handler has been renamed + */ +void RollingFileAppenderSkeleton::reopenLatestFile(Pool& p){ + closeWriter(); + OutputStreamPtr os(new FileOutputStream(getFile(), true)); + WriterPtr newWriter(createWriter(os)); + setFile(getFile()); + setWriter(newWriter); + fileLength = File().setPath(getFile()).length(p); + writeHeader(p); } +#endif + /** * {@inheritDoc} */ @@ -248,11 +363,38 @@ void RollingFileAppenderSkeleton::subApp // is not provided. However appender should still be in good // condition and the append should still happen. try { - rollover(p); + _event = &(const_cast<LoggingEventPtr &>(event)); + rollover(p); } catch (std::exception& ex) { LogLog::warn(LOG4CXX_STR("Exception during rollover attempt.")); } } + +#ifdef LOG4CXX_MULTI_PROCESS + //do re-check before every write + // + apr_finfo_t finfo1, finfo2; + apr_status_t st1, st2; + apr_file_t* _fd = getWriter()->getOutPutStreamPtr()->getFileOutPutStreamPtr().getFilePtr(); + st1 = apr_file_info_get(&finfo1, APR_FINFO_IDENT, _fd); + if (st1 != APR_SUCCESS){ + LogLog::warn(LOG4CXX_STR("apr_file_info_get failed")); + } + + st2 = apr_stat(&finfo2, std::string(getFile()).c_str(), APR_FINFO_IDENT, p.getAPRPool()); + if (st2 != APR_SUCCESS){ + std::string err = "apr_stat failed. file:" + std::string(getFile()); + LogLog::warn(LOG4CXX_STR(err.c_str())); + } + + bool bAlreadyRolled = ((st1 == APR_SUCCESS) && (st2 == APR_SUCCESS) + && ((finfo1.device != finfo2.device) || (finfo1.inode != finfo2.inode))); + + if (bAlreadyRolled){ + reopenLatestFile(p); + } +#endif + FileAppender::subAppend(event, p); } @@ -345,10 +487,17 @@ class CountingOutputStream : public Outp void write(ByteBuffer& buf, Pool& p) { os->write(buf, p); if (rfa != 0) { +#ifndef LOG4CXX_MULTI_PROCESS rfa->incrementFileLength(buf.limit()); +#else + rfa->setFileLength(File().setPath(rfa->getFile()).length(p)); +#endif } } +#ifdef LOG4CXX_MULTI_PROCESS + OutputStream& getFileOutPutStreamPtr() { return *os;} +#endif }; } } @@ -375,6 +524,12 @@ size_t RollingFileAppenderSkeleton::getF return fileLength; } +#ifdef LOG4CXX_MULTI_PROCESS +void RollingFileAppenderSkeleton::setFileLength(size_t length){ + fileLength = length; +} +#endif + /** * Increments estimated byte length of current active log file. * @param increment additional bytes written to log file. Modified: incubator/log4cxx/trunk/src/main/cpp/timebasedrollingpolicy.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/timebasedrollingpolicy.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/timebasedrollingpolicy.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/timebasedrollingpolicy.cpp Sun Feb 9 18:26:33 2014 @@ -18,6 +18,10 @@ #pragma warning ( disable: 4231 4251 4275 4786 ) #endif +#ifdef LOG4CXX_MULTI_PROCESS +#include <libgen.h> +#endif + #include <log4cxx/logstring.h> #include <log4cxx/rolling/timebasedrollingpolicy.h> #include <log4cxx/pattern/filedatepatternconverter.h> @@ -27,6 +31,8 @@ #include <log4cxx/helpers/exception.h> #include <log4cxx/rolling/gzcompressaction.h> #include <log4cxx/rolling/zipcompressaction.h> +#include <log4cxx/rolling/rollingfileappenderskeleton.h> +#include<iostream> #ifndef INT64_C #define INT64_C(x) x ## LL @@ -34,7 +40,6 @@ #include <apr_time.h> - using namespace log4cxx; using namespace log4cxx::rolling; using namespace log4cxx::helpers; @@ -42,8 +47,110 @@ using namespace log4cxx::pattern; IMPLEMENT_LOG4CXX_OBJECT(TimeBasedRollingPolicy) -TimeBasedRollingPolicy::TimeBasedRollingPolicy() { +#ifdef LOG4CXX_MULTI_PROCESS +#define MMAP_FILE_SUFFIX ".map" +#define LOCK_FILE_SUFFIX ".maplck" +#define MAX_FILE_LEN 2048 + +bool TimeBasedRollingPolicy::isMapFileEmpty(log4cxx::helpers::Pool& pool){ + apr_finfo_t finfo; + apr_status_t st = apr_stat(&finfo, _mapFileName.c_str(), APR_FINFO_SIZE, pool.getAPRPool()); + if (st != APR_SUCCESS){ + LogLog::warn(LOG4CXX_STR("apr_stat failed.")); + } + if (st == APR_SUCCESS && !finfo.size) + return true; + return false; +} + +void TimeBasedRollingPolicy::initMMapFile(const LogString& lastFileName, log4cxx::helpers::Pool& pool){ + int iRet = 0; + if (!_mmap){ + iRet = createMMapFile(std::string(_fileNamePattern), pool); + } + if (!iRet && isMapFileEmpty(pool)) { + lockMMapFile(APR_FLOCK_EXCLUSIVE); + memset(_mmap->mm, 0, MAX_FILE_LEN); + memcpy(_mmap->mm, std::string(lastFileName).c_str(), std::string(lastFileName).size()); + unLockMMapFile(); + } +} + +const std::string TimeBasedRollingPolicy::createFile(const std::string& fileName, const std::string& suffix, log4cxx::helpers::Pool& pool) { + char szUid[MAX_FILE_LEN] = {'\0'}; + char szBaseName[MAX_FILE_LEN] = {'\0'}; + char szDirName[MAX_FILE_LEN] = {'\0'}; + memcpy(szDirName, fileName.c_str(), fileName.size() > MAX_FILE_LEN ? MAX_FILE_LEN : fileName.size()); + memcpy(szBaseName, fileName.c_str(), fileName.size() > MAX_FILE_LEN ? MAX_FILE_LEN : fileName.size()); + + apr_uid_t uid; + apr_gid_t groupid; + apr_status_t stat = apr_uid_current(&uid, &groupid, pool.getAPRPool()); + if (stat == APR_SUCCESS){ + snprintf(szUid, MAX_FILE_LEN, "%u", uid); + } + return std::string(::dirname(szDirName)) + "/." + ::basename(szBaseName) + szUid + suffix; +} + +int TimeBasedRollingPolicy::createMMapFile(const std::string& fileName, log4cxx::helpers::Pool& pool){ + _mapFileName = createFile(fileName, MMAP_FILE_SUFFIX, pool); + + apr_status_t stat = apr_file_open(&_file_map, _mapFileName.c_str(), APR_CREATE | APR_READ | APR_WRITE, APR_OS_DEFAULT, _mmapPool->getAPRPool()); + if (stat != APR_SUCCESS){ + std::string err(std::string("open mmap file failed. ") + std::string(strerror(errno)) + ". Check the privilege or try to remove " + _mapFileName + " if exist."); + LogLog::warn(LOG4CXX_STR(err.c_str())); + return -1; + } + + if (isMapFileEmpty(pool)){ + stat = apr_file_trunc(_file_map, MAX_FILE_LEN + 1); + if (stat != APR_SUCCESS){ + LogLog::warn(LOG4CXX_STR("apr_file_trunc failed.")); + apr_file_close(_file_map); + return -1; + } + } + + stat = apr_mmap_create(&_mmap, _file_map, 0, MAX_FILE_LEN, APR_MMAP_WRITE | APR_MMAP_READ, _mmapPool->getAPRPool()); + if (stat != APR_SUCCESS){ + LogLog::warn(LOG4CXX_STR("mmap failed.")); + apr_file_close(_file_map); + return -1; + } + + return 0; +} + +int TimeBasedRollingPolicy::lockMMapFile(int type) +{ + apr_status_t stat = apr_file_lock(_lock_file, type); + if (stat != APR_SUCCESS) { + LogLog::warn(LOG4CXX_STR("apr_file_lock for mmap failed.")); + } +} +int TimeBasedRollingPolicy::unLockMMapFile() +{ + apr_status_t stat = apr_file_unlock(_lock_file); + if (stat != APR_SUCCESS) { + LogLog::warn(LOG4CXX_STR("apr_file_unlock for mmap failed.")); + } +} + +#endif + +TimeBasedRollingPolicy::TimeBasedRollingPolicy() +#ifdef LOG4CXX_MULTI_PROCESS + :_mmap(NULL), _file_map(NULL), bAlreadyInitialized(false), _mmapPool(new Pool()), _lock_file(NULL), bRefreshCurFile(false) +#endif +{ +} + +#ifdef LOG4CXX_MULTI_PROCESS +TimeBasedRollingPolicy::~TimeBasedRollingPolicy() { + //no-need to delete mmap + delete _mmapPool; } +#endif void TimeBasedRollingPolicy::addRef() const { TriggeringPolicy::addRef(); @@ -75,6 +182,24 @@ void TimeBasedRollingPolicy::activateOpt formatFileName(obj, buf, pool); lastFileName = buf; +#ifdef LOG4CXX_MULTI_PROCESS + if (getPatternConverterList().size()){ + (*(getPatternConverterList().begin()))->format(obj, _fileNamePattern, pool); + }else{ + _fileNamePattern = lastFileName; + } + + if (!_lock_file) { + const std::string lockname = createFile(std::string(_fileNamePattern), LOCK_FILE_SUFFIX, *_mmapPool); + apr_status_t stat = apr_file_open(&_lock_file, lockname.c_str(), APR_CREATE | APR_READ | APR_WRITE, APR_OS_DEFAULT, (*_mmapPool).getAPRPool()); + if (stat != APR_SUCCESS) { + LogLog::warn(LOG4CXX_STR("open lock file failed.")); + } + } + + initMMapFile(lastFileName, *_mmapPool); +#endif + suffixLength = 0; if (lastFileName.length() >= 3) { @@ -120,6 +245,7 @@ RolloverDescriptionPtr TimeBasedRollingP return new RolloverDescription( currentActiveFile, append, noAction, noAction); } else { + bRefreshCurFile = true; return new RolloverDescription( lastFileName.substr(0, lastFileName.length() - suffixLength), append, noAction, noAction); @@ -140,6 +266,19 @@ RolloverDescriptionPtr TimeBasedRollingP LogString newFileName(buf); +#ifdef LOG4CXX_MULTI_PROCESS + bAlreadyInitialized = true; + if (_mmap && !isMapFileEmpty(*_mmapPool)){ + lockMMapFile(APR_FLOCK_SHARED); + LogString mapLastFile((char *)_mmap->mm); + lastFileName = mapLastFile; + unLockMMapFile(); + }else{ + _mmap = NULL; + initMMapFile(lastFileName, *_mmapPool); + } +#endif + // // if file names haven't changed, no rollover // @@ -178,18 +317,48 @@ RolloverDescriptionPtr TimeBasedRollingP File().setPath(lastBaseName), File().setPath(lastFileName), true); } +#ifdef LOG4CXX_MULTI_PROCESS + if (_mmap && !isMapFileEmpty(*_mmapPool)){ + lockMMapFile(APR_FLOCK_EXCLUSIVE); + memset(_mmap->mm, 0, MAX_FILE_LEN); + memcpy(_mmap->mm, std::string(newFileName).c_str(), std::string(newFileName).size()); + unLockMMapFile(); + }else{ + _mmap = NULL; + initMMapFile(newFileName, *_mmapPool); + } +#else lastFileName = newFileName; +#endif +#ifdef LOG4CXX_MULTI_PROCESS + return new RolloverDescription( + nextActiveFile, true, renameAction, compressAction); +#else return new RolloverDescription( nextActiveFile, false, renameAction, compressAction); +#endif } bool TimeBasedRollingPolicy::isTriggeringEvent( - Appender* /* appender */, + Appender* appender, const log4cxx::spi::LoggingEventPtr& /* event */, - const LogString& /* filename */, + const LogString& filename , size_t /* fileLength */) { +#ifdef LOG4CXX_MULTI_PROCESS + if (bRefreshCurFile && _mmap && !isMapFileEmpty(*_mmapPool)) { + lockMMapFile(APR_FLOCK_SHARED); + LogString mapCurrent((char *)_mmap->mm); + unLockMMapFile(); + LogString mapCurrentBase(mapCurrent.substr(0, mapCurrent.length() - suffixLength)); + if (!mapCurrentBase.empty() && mapCurrentBase != filename) { + dynamic_cast<FileAppender *>(appender)->setFile(mapCurrentBase); + } + } + return ((apr_time_now()) > nextCheck) || (!bAlreadyInitialized); +#else return apr_time_now() > nextCheck; +#endif } Modified: incubator/log4cxx/trunk/src/main/cpp/writer.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/writer.cpp?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/writer.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/writer.cpp Sun Feb 9 18:26:33 2014 @@ -17,6 +17,7 @@ #include <log4cxx/logstring.h> #include <log4cxx/helpers/writer.h> +#include <stdexcept> using namespace log4cxx::helpers; @@ -27,3 +28,9 @@ Writer::Writer() { Writer::~Writer() { } + +#ifdef LOG4CXX_MULTI_PROCESS +OutputStreamPtr Writer::getOutPutStreamPtr(){ + throw std::logic_error("getOutPutStreamPtr must be implemented in the derived class that you are using"); +} +#endif Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/fileoutputstream.h URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/fileoutputstream.h?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/fileoutputstream.h (original) +++ incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/fileoutputstream.h Sun Feb 9 18:26:33 2014 @@ -52,6 +52,9 @@ namespace log4cxx virtual void flush(Pool& p); virtual void write(ByteBuffer& buf, Pool& p); +#ifdef LOG4CXX_MULTI_PROCESS + apr_file_t* getFilePtr() { return fileptr; } +#endif private: FileOutputStream(const FileOutputStream&); FileOutputStream& operator=(const FileOutputStream&); Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstream.h URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstream.h?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstream.h (original) +++ incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstream.h Sun Feb 9 18:26:33 2014 @@ -19,6 +19,9 @@ #define _LOG4CXX_HELPERS_OUTPUTSTREAM_H #include <log4cxx/helpers/objectimpl.h> +#ifdef LOG4CXX_MULTI_PROCESS +#include <apr_file_io.h> +#endif namespace log4cxx { @@ -45,6 +48,10 @@ namespace log4cxx virtual void close(Pool& p) = 0; virtual void flush(Pool& p) = 0; virtual void write(ByteBuffer& buf, Pool& p) = 0; +#ifdef LOG4CXX_MULTI_PROCESS + virtual apr_file_t* getFilePtr(); + virtual OutputStream& getFileOutPutStreamPtr(); +#endif private: OutputStream(const OutputStream&); Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstreamwriter.h URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstreamwriter.h?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstreamwriter.h (original) +++ incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/outputstreamwriter.h Sun Feb 9 18:26:33 2014 @@ -52,6 +52,10 @@ namespace log4cxx virtual void write(const LogString& str, Pool& p); LogString getEncoding() const; +#ifdef LOG4CXX_MULTI_PROCESS + OutputStreamPtr getOutPutStreamPtr() { return out; } +#endif + private: OutputStreamWriter(const OutputStreamWriter&); OutputStreamWriter& operator=(const OutputStreamWriter&); Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/writer.h URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/writer.h?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/writer.h (original) +++ incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/writer.h Sun Feb 9 18:26:33 2014 @@ -19,6 +19,7 @@ #define _LOG4CXX_HELPERS_WRITER_H #include <log4cxx/helpers/objectimpl.h> +#include <log4cxx/helpers/outputstream.h> namespace log4cxx { @@ -44,6 +45,9 @@ namespace log4cxx virtual void close(Pool& p) = 0; virtual void flush(Pool& p) = 0; virtual void write(const LogString& str, Pool& p) = 0; +#ifdef LOG4CXX_MULTI_PROCESS + virtual OutputStreamPtr getOutPutStreamPtr(); +#endif private: Writer(const Writer&); Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h (original) +++ incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h Sun Feb 9 18:26:33 2014 @@ -57,6 +57,10 @@ namespace log4cxx { */ size_t fileLength; + /** + * save the loggingevent + */ + spi::LoggingEventPtr* _event; public: /** * The default constructor simply calls its {@link @@ -133,6 +137,25 @@ namespace log4cxx { * @return byte length of current active log file. */ size_t getFileLength() const; + +#ifdef LOG4CXX_MULTI_PROCESS + /** + * Set byte length of current active log file. + * @return void + */ + void setFileLength(size_t length); + + /** + * Release the file lock + * @return void + */ + void releaseFileLock(apr_file_t* lock_file); + /** + * re-open the latest file when its own handler has been renamed + * @return void + */ + void reopenLatestFile(log4cxx::helpers::Pool& p); +#endif /** * Increments estimated byte length of current active log file. Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingpolicybase.h URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingpolicybase.h?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingpolicybase.h (original) +++ incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/rollingpolicybase.h Sun Feb 9 18:26:33 2014 @@ -96,6 +96,9 @@ namespace log4cxx { LogString getFileNamePattern() const; +#ifdef LOG4CXX_MULTI_PROCESS + PatternConverterList getPatternConverterList() { return patternConverters; } +#endif protected: /** * Parse file name pattern. Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/timebasedrollingpolicy.h URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/timebasedrollingpolicy.h?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/timebasedrollingpolicy.h (original) +++ incubator/log4cxx/trunk/src/main/include/log4cxx/rolling/timebasedrollingpolicy.h Sun Feb 9 18:26:33 2014 @@ -22,6 +22,9 @@ #include <log4cxx/portability.h> #include <log4cxx/rolling/rollingpolicybase.h> #include <log4cxx/rolling/triggeringpolicy.h> +#include <log4cxx/writerappender.h> +#include <log4cxx/helpers/outputstream.h> +#include <apr_mmap.h> namespace log4cxx { @@ -157,6 +160,50 @@ namespace log4cxx { LogString lastFileName; /** + * mmap pointer + */ + apr_mmap_t* _mmap; + + /* + * pool for mmap handler + * */ + log4cxx::helpers::Pool* _mmapPool; + + /** + * mmap file descriptor + */ + apr_file_t* _file_map; + + /** + * mmap file name + */ + std::string _mapFileName; + + /* + * lock file handle + * */ + apr_file_t* _lock_file; + /** + * Check nextCheck if it has already been set + * Timebased rolling policy has an issue when working at low rps. + * Under low rps, multiple processes will not be scheduled in time for the second chance(do rolling), + * so the rolling mechanism will not be triggered even if the time period is out of date. + * This results in log entries will be accumulated for serveral minutes to be rolling. + * Adding this flag to provide rolling opportunity for a process even if it is writing the first log entry + */ + bool bAlreadyInitialized; + + /* + * If the current file name contains date information, retrieve the current writting file from mmap + * */ + bool bRefreshCurFile; + + /* + * mmap file name + * */ + LogString _fileNamePattern; + + /** * Length of any file type suffix (.gz, .zip). */ int suffixLength; @@ -166,6 +213,41 @@ namespace log4cxx { void addRef() const; void releaseRef() const; void activateOptions(log4cxx::helpers::Pool& ); + +#ifdef LOG4CXX_MULTI_PROCESS + virtual ~TimeBasedRollingPolicy(); + + /** + * Generate mmap file + */ + int createMMapFile(const std::string& lastfilename, log4cxx::helpers::Pool& pool); + + /** + * Detect if the mmap file is empty + */ + bool isMapFileEmpty(log4cxx::helpers::Pool& pool); + + /** + * init MMapFile + */ + void initMMapFile(const LogString& lastFileName, log4cxx::helpers::Pool& pool); + + /** + * lock MMapFile + */ + int lockMMapFile(int type); + + /** + * unlock MMapFile + */ + int unLockMMapFile(); + + /** + * create MMapFile/lockFile + */ + const std::string createFile(const std::string& filename, const std::string& suffix, log4cxx::helpers::Pool& pool); +#endif + /** * Initialize the policy and return any initial actions for rolling file appender. * Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/writerappender.h URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/writerappender.h?rev=1566343&r1=1566342&r2=1566343&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/include/log4cxx/writerappender.h (original) +++ incubator/log4cxx/trunk/src/main/include/log4cxx/writerappender.h Sun Feb 9 18:26:33 2014 @@ -179,6 +179,9 @@ namespace log4cxx <p> @param writer An already opened Writer. */ void setWriter(const log4cxx::helpers::WriterPtr& writer); +#ifdef LOG4CXX_MULTI_PROCESS + const log4cxx::helpers::WriterPtr getWriter() { return writer; }; +#endif virtual bool requiresLayout() const;