在Log4Qt中存在一个比较大的问题,当使用 DailyRollingFileAppender对日志进行输出时,会无限输出文件,也就是说,当系统运行很久时,日志文件有可能很大,大到无法想象。因此,很多开发者希望在DailyRollingFileAppender中加一个属性,用于配置日志文件的个数。
但是如何做呢?
在Java语言中,我找到一个实例,但是在QT中,没能找到,因此,只能通过自己看源代码,分析从而进行改进。
主要代码如下:
dailyrollingfileappender.h:
class DailyRollingFileAppender : public FileAppender { Q_OBJECT /*! * The property holds the date pattern used by the appender. * * The default is DAILY_ROLLOVER for rollover at midnight each day. * * sa datePattern(), setDatePattern() */ Q_PROPERTY(QString datePattern READ datePattern WRITE setDatePattern) /*! * The property holds the maximum backup count used by the appender. * * The default is 1. * * sa maxBackupIndex(), setMaxBackupIndex() */ Q_PROPERTY(int maxBackupIndex READ maxBackupIndex WRITE setMaxBackupIndex) public: /*! * The enum DatePattern defines constants for date patterns. * * sa setDatePattern(DatePattern) */ enum DatePattern { /*! The minutely date pattern string is "'.'yyyy-MM-dd-hh-mm". */ MINUTELY_ROLLOVER = 0, /*! The hourly date pattern string is "'.'yyyy-MM-dd-hh". */ HOURLY_ROLLOVER, /*! The half-daily date pattern string is "'.'yyyy-MM-dd-a". */ HALFDAILY_ROLLOVER, /*! The daily date pattern string is "'.'yyyy-MM-dd". */ DAILY_ROLLOVER, /*! The weekly date pattern string is "'.'yyyy-ww". */ WEEKLY_ROLLOVER, /*! The monthly date pattern string is "'.'yyyy-MM". */ MONTHLY_ROLLOVER }; Q_ENUMS(DatePattern) DailyRollingFileAppender(QObject *pParent = 0); DailyRollingFileAppender(Layout *pLayout, const QString &rFileName, const QString &rDatePattern, const int rmaxBackupIndex = 7, QObject *pParent = 0); virtual ~DailyRollingFileAppender(); private: DailyRollingFileAppender(const DailyRollingFileAppender &rOther); // Not implemented DailyRollingFileAppender &operator=(const DailyRollingFileAppender &rOther); // Not implemented void removeFiles(); public: int maxBackupIndex() const; void setMaxBackupIndex(int maxBackupIndex); QString datePattern() const; /*! * Sets the datePattern to the value specified by the a datePattern * constant. */ void setDatePattern(DatePattern datePattern); void setDatePattern(const QString &rDatePattern); virtual void activateOptions(); protected: virtual void append(const LoggingEvent &rEvent); /*! * Tests if all entry conditions for using append() in this class are * met. * * If a conditions is not met, an error is logged and the function * returns false. Otherwise the result of * FileAppender::checkEntryConditions() is returned. * * The checked conditions are: * - A valid pattern has been set (APPENDER_USE_INVALID_PATTERN_ERROR) * * The function is called as part of the checkEntryConditions() chain * started by AppenderSkeleton::doAppend(). * * sa AppenderSkeleton::doAppend(), * AppenderSkeleton::checkEntryConditions() */ virtual bool checkEntryConditions() const; protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * a rDebug and returns the stream. * * <tt> * %DailyRollingFileAppender(name:"DRFA" activedatepattern:"'.'yyyy-MM-dd-hh-mm" * appendfile:false bufferedio:true * datepattern:"'.'yyyy-MM-dd-hh-mm" * encoding:"" frequency:"MINUTELY_ROLLOVER" * file:"/log.txt" filter:0x0 immediateflush:true * isactive:true isclosed:false layout:"TTCC" * referencecount:1 * rollovertime:QDateTime("Mon Oct 22 05:23:00 2007") * threshold: "NULL" writer: 0x0 ) * </tt> * sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM private: void computeFrequency(); void computeRollOverTime(); QString frequencyToString() const; void rollOver(); private: QString mDatePattern; DatePattern mFrequency; QString mActiveDatePattern; QDateTime mRollOverTime; QString mRollOverSuffix; protected: int mMaxBackupIndex; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline QString DailyRollingFileAppender::datePattern() const { QMutexLocker locker(&mObjectGuard); return mDatePattern; } inline void DailyRollingFileAppender::setDatePattern(const QString &rDatePattern) { QMutexLocker locker(&mObjectGuard); mDatePattern = rDatePattern; } inline int DailyRollingFileAppender::maxBackupIndex() const { QMutexLocker locker(&mObjectGuard); return mMaxBackupIndex; } inline void DailyRollingFileAppender::setMaxBackupIndex(int maxBackupIndex) { QMutexLocker locker(&mObjectGuard); mMaxBackupIndex = maxBackupIndex; }
其中,Q_PROPERTY(int maxBackupIndex READ maxBackupIndex WRITE setMaxBackupIndex)这句话什么重要。
dailyrollingfileappender.cpp:
DailyRollingFileAppender::DailyRollingFileAppender(QObject *pParent) : FileAppender(pParent), mDatePattern() { setDatePattern(DAILY_ROLLOVER); } DailyRollingFileAppender::DailyRollingFileAppender(Layout *pLayout, const QString &rFileName, const QString &rDatePattern, const int rmaxBackupIndex, QObject *pParent) : FileAppender(pLayout, rFileName, pParent), mDatePattern(), mMaxBackupIndex(rmaxBackupIndex) { setDatePattern(rDatePattern); } DailyRollingFileAppender::~DailyRollingFileAppender() { close(); } void DailyRollingFileAppender::setDatePattern(DatePattern datePattern) { switch (datePattern) { case MINUTELY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-MM-dd-hh-mm")); break; case HOURLY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-MM-dd-hh")); break; case HALFDAILY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-MM-dd-a")); break; case DAILY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-MM-dd")); break; case WEEKLY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-ww")); break; case MONTHLY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-MM")); break; default: Q_ASSERT_X(false, "DailyRollingFileAppender::setDatePattern()", "Invalid datePattern constant"); setDatePattern(DAILY_ROLLOVER); }; } void DailyRollingFileAppender::activateOptions() { QMutexLocker locker(&mObjectGuard); computeFrequency(); if (!mActiveDatePattern.isEmpty()) { computeRollOverTime(); FileAppender::activateOptions(); } } void DailyRollingFileAppender::append(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "DailyRollingFileAppender::append()", "Lock must be held by caller") if (QDateTime::currentDateTime() > mRollOverTime) rollOver(); FileAppender::append(rEvent); } bool DailyRollingFileAppender::checkEntryConditions() const { // Q_ASSERT_X(, "DailyRollingFileAppender::checkEntryConditions()", "Lock must be held by caller") if (mActiveDatePattern.isEmpty()) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of appender '%1' without having a valid date pattern set"), APPENDER_USE_INVALID_PATTERN_ERROR); e << name(); logger()->error(e); return false; } return FileAppender::checkEntryConditions(); } #ifndef QT_NO_DEBUG_STREAM QDebug DailyRollingFileAppender::debug(QDebug &rDebug) const { QString layout_name; if (layout()) layout_name = layout()->name(); QString codec_name; if (encoding()) codec_name = QLatin1String(encoding()->name()); rDebug.nospace() << "DailyRollingFileAppender(" << "name:" << name() << " " << "activedatepattern:" << mActiveDatePattern << " " << "appendfile:" << appendFile() << " " << "bufferedio:" << bufferedIo() << " " << "datepattern:" << datePattern() << " " << "encoding:" << codec_name << " " << "frequency:" << frequencyToString() << " " << "file:" << file() << " " << "filter:" << firstFilter() << " " << "immediateflush:" << immediateFlush() << " " << "isactive:" << isActive() << " " << "isclosed:" << isClosed() << " " << "layout:" << layout_name << " " << "referencecount:" << referenceCount() << " " << "rollovertime:" << mRollOverTime << "threshold:" << threshold().toString() << "writer:" << writer() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM void DailyRollingFileAppender::computeFrequency() { // Q_ASSERT_X(, "DailyRollingFileAppender::computeFrequency()", "Lock must be held by caller") const DateTime start_time(QDate(1999, 1, 1), QTime(0, 0)); const QString start_string = start_time.toString(mDatePattern); mActiveDatePattern.clear(); if (start_string != static_cast<DateTime>(start_time.addSecs(60)).toString(mDatePattern)) mFrequency = MINUTELY_ROLLOVER; else if (start_string != static_cast<DateTime>(start_time.addSecs(60 * 60)).toString(mDatePattern)) mFrequency = HOURLY_ROLLOVER; else if (start_string != static_cast<DateTime>(start_time.addSecs(60 * 60 * 12)).toString(mDatePattern)) mFrequency = HALFDAILY_ROLLOVER; else if (start_string != static_cast<DateTime>(start_time.addDays(1)).toString(mDatePattern)) mFrequency = DAILY_ROLLOVER; else if (start_string != static_cast<DateTime>(start_time.addDays(7)).toString(mDatePattern)) mFrequency = WEEKLY_ROLLOVER; else if (start_string != static_cast<DateTime>(start_time.addMonths(1)).toString(mDatePattern)) mFrequency = MONTHLY_ROLLOVER; else { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("The pattern '%1' does not specify a frequency for appender '%2'"), APPENDER_INVALID_PATTERN_ERROR); e << mDatePattern << name(); logger()->error(e); return; } mActiveDatePattern = mDatePattern; logger()->trace("Frequency set to %2 using date pattern %1", mActiveDatePattern, frequencyToString()); } void DailyRollingFileAppender::computeRollOverTime() { // Q_ASSERT_X(, "DailyRollingFileAppender::computeRollOverTime()", "Lock must be held by caller") Q_ASSERT_X(!mActiveDatePattern.isEmpty(), "DailyRollingFileAppender::computeRollOverTime()", "No active date pattern"); QDateTime now = QDateTime::currentDateTime(); QDate now_date = now.date(); QTime now_time = now.time(); QDateTime start; switch (mFrequency) { case MINUTELY_ROLLOVER: { start = QDateTime(now_date, QTime(now_time.hour(), now_time.minute(), 0, 0)); mRollOverTime = start.addSecs(60); } break; case HOURLY_ROLLOVER: { start = QDateTime(now_date, QTime(now_time.hour(), 0, 0, 0)); mRollOverTime = start.addSecs(60*60); } break; case HALFDAILY_ROLLOVER: { int hour = now_time.hour(); if (hour >= 12) hour = 12; else hour = 0; start = QDateTime(now_date, QTime(hour, 0, 0, 0)); mRollOverTime = start.addSecs(60*60*12); } break; case DAILY_ROLLOVER: { start = QDateTime(now_date, QTime(0, 0, 0, 0)); mRollOverTime = start.addDays(1); } break; case WEEKLY_ROLLOVER: { // QT numbers the week days 1..7. The week starts on Monday. // Change it to being numbered 0..6, starting with Sunday. int day = now_date.dayOfWeek(); if (day == Qt::Sunday) day = 0; start = QDateTime(now_date, QTime(0, 0, 0, 0)).addDays(-1 * day); mRollOverTime = start.addDays(7); } break; case MONTHLY_ROLLOVER: { start = QDateTime(QDate(now_date.year(), now_date.month(), 1), QTime(0, 0, 0, 0)); mRollOverTime = start.addMonths(1); } break; default: Q_ASSERT_X(false, "DailyRollingFileAppender::computeInterval()", "Invalid datePattern constant"); mRollOverTime = QDateTime::fromTime_t(0); } mRollOverSuffix = static_cast<DateTime>(start).toString(mActiveDatePattern); Q_ASSERT_X(static_cast<DateTime>(now).toString(mActiveDatePattern) == mRollOverSuffix, "DailyRollingFileAppender::computeRollOverTime()", "File name changes within interval"); Q_ASSERT_X(mRollOverSuffix != static_cast<DateTime>(mRollOverTime).toString(mActiveDatePattern), "DailyRollingFileAppender::computeRollOverTime()", "File name does not change with rollover"); logger()->trace("Computing roll over time from %1: The interval start time is %2. The roll over time is %3", now, start, mRollOverTime); } QString DailyRollingFileAppender::frequencyToString() const { QMetaEnum meta_enum = metaObject()->enumerator(metaObject()->indexOfEnumerator("DatePattern")); return QLatin1String(meta_enum.valueToKey(mFrequency)); } void DailyRollingFileAppender::removeFiles() { QDir dir("./logs"); dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); dir.setSorting(QDir::Time | QDir::Reversed); QFileInfoList list = dir.entryInfoList(); QFileInfo fileInfo; if(list.size() >= mMaxBackupIndex) { int index = 0; int diff = list.size() - mMaxBackupIndex; for (int i = 0; i < list.size(); ++i) { fileInfo = list.at(i); if(index >= diff) { break; } QFile file(fileInfo.absoluteFilePath()); QByteArray ba = fileInfo.absoluteFilePath().toLatin1(); cout<<ba.data()<<endl; file.remove(); index++; } } } void DailyRollingFileAppender::rollOver() { // Q_ASSERT_X(, "DailyRollingFileAppender::rollOver()", "Lock must be held by caller") Q_ASSERT_X(!mActiveDatePattern.isEmpty(), "DailyRollingFileAppender::rollOver()", "No active date pattern"); QString roll_over_suffix = mRollOverSuffix; computeRollOverTime(); if (roll_over_suffix == mRollOverSuffix) return; closeFile(); QString target_file_name = file() + roll_over_suffix; QFile f(target_file_name); if (f.exists() && !removeFile(f)) return; f.setFileName(file()); if (!renameFile(f, target_file_name)) return; openFile(); removeFiles(); //huabo }