Index: src/examples/cpp/console.cpp =================================================================== --- src/examples/cpp/console.cpp (revision 85586) +++ src/examples/cpp/console.cpp (working copy) @@ -16,6 +16,8 @@ */ #include +#include +#include #include #include #include Index: src/main/cpp/fixedwindowrollingpolicy.cpp =================================================================== --- src/main/cpp/fixedwindowrollingpolicy.cpp (revision 85586) +++ src/main/cpp/fixedwindowrollingpolicy.cpp (working copy) @@ -160,8 +160,13 @@ 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; Index: src/main/cpp/outputstream.cpp =================================================================== --- src/main/cpp/outputstream.cpp (revision 85586) +++ src/main/cpp/outputstream.cpp (working copy) @@ -17,6 +17,7 @@ #include #include +#include using namespace log4cxx; using namespace log4cxx::helpers; @@ -28,3 +29,13 @@ 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 Index: src/main/cpp/outputstreamwriter.cpp =================================================================== --- src/main/cpp/outputstreamwriter.cpp (revision 85586) +++ src/main/cpp/outputstreamwriter.cpp (working copy) @@ -58,9 +58,15 @@ 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 @@ 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 } } Index: src/main/cpp/rollingfileappender.cpp =================================================================== --- src/main/cpp/rollingfileappender.cpp (revision 85586) +++ src/main/cpp/rollingfileappender.cpp (working copy) @@ -19,6 +19,19 @@ #pragma warning ( disable: 4231 4251 4275 4786 ) #endif +#ifdef LOG4CXX_MULTI_PROCESS +#include +#include +#include +#include +#include +#ifndef MAX_FILE_LEN +#define MAX_FILE_LEN 2048 +#endif +#include +#include +#endif + #include #include #include @@ -41,7 +54,7 @@ /** * Construct a new instance. */ -RollingFileAppenderSkeleton::RollingFileAppenderSkeleton() { +RollingFileAppenderSkeleton::RollingFileAppenderSkeleton() : _event(NULL){ } RollingFileAppender::RollingFileAppender() { @@ -115,9 +128,20 @@ + 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 @@ * @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); - try { - RolloverDescriptionPtr rollover1(rollingPolicy->rollover(getFile(), p)); + { + synchronized sync(mutex); - if (rollover1 != NULL) { - if (rollover1->getActiveFileName() == getFile()) { - closeWriter(); +#ifdef LOG4CXX_MULTI_PROCESS + std::string fileName(getFile()); + RollingPolicyBase *basePolicy = dynamic_cast(&(*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); + } + } - bool success = true; + 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); + } - if (rollover1->getSynchronous() != NULL) { - success = false; - - try { - success = rollover1->getSynchronous()->execute(p); - } catch (std::exception& ex) { - LogLog::warn(LOG4CXX_STR("Exception on 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; - } + 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")); + } - // - // async action not yet implemented - // - ActionPtr asyncAction(rollover1->getAsynchronous()); - if (asyncAction != NULL) { - asyncAction->execute(p); - } + 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.")); + } - setFile( - rollover1->getActiveFileName(), rollover1->getAppend(), - bufferedIO, bufferSize, p); - } else { - setFile( - rollover1->getActiveFileName(), true, bufferedIO, bufferSize, p); + bAlreadyRolled = ((st1 == APR_SUCCESS) && (st2 == APR_SUCCESS) + && ((finfo1.device != finfo2.device) || (finfo1.inode != finfo2.inode))); } - } else { - OutputStreamPtr os(new FileOutputStream( - rollover1->getActiveFileName(), rollover1->getAppend())); - WriterPtr newWriter(createWriter(os)); - closeWriter(); - setFile(rollover1->getActiveFileName()); - setWriter(newWriter); + + if (!bAlreadyRolled){ +#endif + try { + RolloverDescriptionPtr rollover1(rollingPolicy->rollover(getFile(), p)); + if (rollover1 != NULL) { + if (rollover1->getActiveFileName() == getFile()) { + closeWriter(); - bool success = true; + bool success = true; + if (rollover1->getSynchronous() != NULL) { + success = false; - if (rollover1->getSynchronous() != NULL) { - success = false; + try { + success = rollover1->getSynchronous()->execute(p); + } catch (std::exception& ex) { + LogLog::warn(LOG4CXX_STR("Exception on rollover")); + } + } - 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; + } - 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); + } - // - // 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); - writeHeader(p); - } + bool success = true; - return 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); + } + +#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 @@ // is not provided. However appender should still be in good // condition and the append should still happen. try { - rollover(p); + _event = &(const_cast(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 @@ 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 @@ 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. Index: src/main/cpp/timebasedrollingpolicy.cpp =================================================================== --- src/main/cpp/timebasedrollingpolicy.cpp (revision 85586) +++ src/main/cpp/timebasedrollingpolicy.cpp (working copy) @@ -18,6 +18,10 @@ #pragma warning ( disable: 4231 4251 4275 4786 ) #endif +#ifdef LOG4CXX_MULTI_PROCESS +#include +#endif + #include #include #include @@ -27,6 +31,8 @@ #include #include #include +#include +#include #ifndef INT64_C #define INT64_C(x) x ## LL @@ -34,7 +40,6 @@ #include - using namespace log4cxx; using namespace log4cxx::rolling; using namespace log4cxx::helpers; @@ -42,9 +47,111 @@ 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 @@ 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) { @@ -118,6 +243,7 @@ return new RolloverDescription( currentActiveFile, append, noAction, noAction); } else { + bRefreshCurFile = true; return new RolloverDescription( lastFileName.substr(0, lastFileName.length() - suffixLength), append, noAction, noAction); @@ -138,6 +264,19 @@ 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 // @@ -176,18 +315,48 @@ 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(appender)->setFile(mapCurrentBase); + } + } + return ((apr_time_now()) > nextCheck) || (!bAlreadyInitialized); +#else return apr_time_now() > nextCheck; +#endif } Index: src/main/cpp/writer.cpp =================================================================== --- src/main/cpp/writer.cpp (revision 85586) +++ src/main/cpp/writer.cpp (working copy) @@ -17,6 +17,7 @@ #include #include +#include using namespace log4cxx::helpers; @@ -27,3 +28,9 @@ 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 Index: src/main/include/log4cxx/helpers/fileoutputstream.h =================================================================== --- src/main/include/log4cxx/helpers/fileoutputstream.h (revision 85586) +++ src/main/include/log4cxx/helpers/fileoutputstream.h (working copy) @@ -52,6 +52,9 @@ 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&); Index: src/main/include/log4cxx/helpers/outputstream.h =================================================================== --- src/main/include/log4cxx/helpers/outputstream.h (revision 85586) +++ src/main/include/log4cxx/helpers/outputstream.h (working copy) @@ -19,6 +19,9 @@ #define _LOG4CXX_HELPERS_OUTPUTSTREAM_H #include +#ifdef LOG4CXX_MULTI_PROCESS +#include +#endif namespace log4cxx { @@ -45,6 +48,10 @@ 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&); Index: src/main/include/log4cxx/helpers/outputstreamwriter.h =================================================================== --- src/main/include/log4cxx/helpers/outputstreamwriter.h (revision 85586) +++ src/main/include/log4cxx/helpers/outputstreamwriter.h (working copy) @@ -52,6 +52,10 @@ 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&); Index: src/main/include/log4cxx/helpers/writer.h =================================================================== --- src/main/include/log4cxx/helpers/writer.h (revision 85586) +++ src/main/include/log4cxx/helpers/writer.h (working copy) @@ -19,6 +19,7 @@ #define _LOG4CXX_HELPERS_WRITER_H #include +#include namespace log4cxx { @@ -44,6 +45,9 @@ 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&); Index: src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h =================================================================== --- src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h (revision 85586) +++ src/main/include/log4cxx/rolling/rollingfileappenderskeleton.h (working copy) @@ -57,6 +57,10 @@ */ size_t fileLength; + /** + * save the loggingevent + */ + spi::LoggingEventPtr* _event; public: /** * The default constructor simply calls its {@link @@ -133,8 +137,27 @@ * @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. * @param increment additional bytes written to log file. */ Index: src/main/include/log4cxx/rolling/rollingpolicybase.h =================================================================== --- src/main/include/log4cxx/rolling/rollingpolicybase.h (revision 85586) +++ src/main/include/log4cxx/rolling/rollingpolicybase.h (working copy) @@ -96,6 +96,9 @@ LogString getFileNamePattern() const; +#ifdef LOG4CXX_MULTI_PROCESS + PatternConverterList getPatternConverterList() { return patternConverters; } +#endif protected: /** * Parse file name pattern. Index: src/main/include/log4cxx/rolling/timebasedrollingpolicy.h =================================================================== --- src/main/include/log4cxx/rolling/timebasedrollingpolicy.h (revision 85586) +++ src/main/include/log4cxx/rolling/timebasedrollingpolicy.h (working copy) @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include namespace log4cxx { @@ -157,6 +160,50 @@ 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,7 +213,42 @@ 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. * * @param file current value of RollingFileAppender.getFile(). Index: src/main/include/log4cxx/writerappender.h =================================================================== --- src/main/include/log4cxx/writerappender.h (revision 85586) +++ src/main/include/log4cxx/writerappender.h (working copy) @@ -179,6 +179,9 @@

@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;