dailyrollingfileappender.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. /******************************************************************************
  2. *
  3. * package: Log4Qt
  4. * file: dailyrollingfileappender.cpp
  5. * created: September 2007
  6. * author: Martin Heinrich
  7. *
  8. *
  9. * Copyright 2007 Martin Heinrich
  10. *
  11. * Licensed under the Apache License, Version 2.0 (the "License");
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing, software
  18. * distributed under the License is distributed on an "AS IS" BASIS,
  19. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing permissions and
  21. * limitations under the License.
  22. *
  23. ******************************************************************************/
  24. /******************************************************************************
  25. * Dependencies
  26. ******************************************************************************/
  27. #include "log4qt/dailyrollingfileappender.h"
  28. #include <QtCore/QDebug>
  29. #include <QtCore/QFile>
  30. #include <QtCore/QMetaEnum>
  31. #include <QtCore/QTextCodec>
  32. #include "log4qt/helpers/datetime.h"
  33. #include "log4qt/layout.h"
  34. #include "log4qt/loggingevent.h"
  35. namespace Log4Qt
  36. {
  37. /**************************************************************************
  38. * Declarations
  39. **************************************************************************/
  40. /**************************************************************************
  41. * C helper functions
  42. **************************************************************************/
  43. /**************************************************************************
  44. * Class implementation: DailyRollingFileAppender
  45. **************************************************************************/
  46. DailyRollingFileAppender::DailyRollingFileAppender(QObject *pParent) :
  47. FileAppender(pParent),
  48. mDatePattern()
  49. {
  50. setDatePattern(DAILY_ROLLOVER);
  51. }
  52. DailyRollingFileAppender::DailyRollingFileAppender(Layout *pLayout,
  53. const QString &rFileName,
  54. const QString &rDatePattern,
  55. QObject *pParent) :
  56. FileAppender(pLayout, rFileName, pParent),
  57. mDatePattern()
  58. {
  59. setDatePattern(rDatePattern);
  60. }
  61. DailyRollingFileAppender::~DailyRollingFileAppender()
  62. {
  63. close();
  64. }
  65. void DailyRollingFileAppender::setDatePattern(DatePattern datePattern)
  66. {
  67. switch (datePattern)
  68. {
  69. case MINUTELY_ROLLOVER:
  70. setDatePattern(QLatin1String("'.'yyyy-MM-dd-hh-mm"));
  71. break;
  72. case HOURLY_ROLLOVER:
  73. setDatePattern(QLatin1String("'.'yyyy-MM-dd-hh"));
  74. break;
  75. case HALFDAILY_ROLLOVER:
  76. setDatePattern(QLatin1String("'.'yyyy-MM-dd-a"));
  77. break;
  78. case DAILY_ROLLOVER:
  79. setDatePattern(QLatin1String("'.'yyyy-MM-dd"));
  80. break;
  81. case WEEKLY_ROLLOVER:
  82. setDatePattern(QLatin1String("'.'yyyy-ww"));
  83. break;
  84. case MONTHLY_ROLLOVER:
  85. setDatePattern(QLatin1String("'.'yyyy-MM"));
  86. break;
  87. default:
  88. Q_ASSERT_X(false, "DailyRollingFileAppender::setDatePattern()", "Invalid datePattern constant");
  89. setDatePattern(DAILY_ROLLOVER);
  90. };
  91. }
  92. void DailyRollingFileAppender::activateOptions()
  93. {
  94. QMutexLocker locker(&mObjectGuard);
  95. computeFrequency();
  96. if (!mActiveDatePattern.isEmpty())
  97. {
  98. computeRollOverTime();
  99. FileAppender::activateOptions();
  100. }
  101. }
  102. void DailyRollingFileAppender::append(const LoggingEvent &rEvent)
  103. {
  104. // Q_ASSERT_X(, "DailyRollingFileAppender::append()", "Lock must be held by caller")
  105. if (QDateTime::currentDateTime() > mRollOverTime)
  106. rollOver();
  107. FileAppender::append(rEvent);
  108. }
  109. bool DailyRollingFileAppender::checkEntryConditions() const
  110. {
  111. // Q_ASSERT_X(, "DailyRollingFileAppender::checkEntryConditions()", "Lock must be held by caller")
  112. if (mActiveDatePattern.isEmpty())
  113. {
  114. LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of appender '%1' without having a valid date pattern set"),
  115. APPENDER_USE_INVALID_PATTERN_ERROR);
  116. e << name();
  117. logger()->error(e);
  118. return false;
  119. }
  120. return FileAppender::checkEntryConditions();
  121. }
  122. #ifndef QT_NO_DEBUG_STREAM
  123. QDebug DailyRollingFileAppender::debug(QDebug &rDebug) const
  124. {
  125. QString layout_name;
  126. if (layout())
  127. layout_name = layout()->name();
  128. QString codec_name;
  129. if (encoding())
  130. codec_name = QLatin1String(encoding()->name());
  131. rDebug.nospace() << "DailyRollingFileAppender("
  132. << "name:" << name() << " "
  133. << "activedatepattern:" << mActiveDatePattern << " "
  134. << "appendfile:" << appendFile() << " "
  135. << "bufferedio:" << bufferedIo() << " "
  136. << "datepattern:" << datePattern() << " "
  137. << "encoding:" << codec_name << " "
  138. << "frequency:" << frequencyToString() << " "
  139. << "file:" << file() << " "
  140. << "filter:" << firstFilter() << " "
  141. << "immediateflush:" << immediateFlush() << " "
  142. << "isactive:" << isActive() << " "
  143. << "isclosed:" << isClosed() << " "
  144. << "layout:" << layout_name << " "
  145. << "referencecount:" << referenceCount() << " "
  146. << "rollovertime:" << mRollOverTime
  147. << "threshold:" << threshold().toString()
  148. << "writer:" << writer()
  149. << ")";
  150. return rDebug.space();
  151. }
  152. #endif // QT_NO_DEBUG_STREAM
  153. void DailyRollingFileAppender::computeFrequency()
  154. {
  155. // Q_ASSERT_X(, "DailyRollingFileAppender::computeFrequency()", "Lock must be held by caller")
  156. const DateTime start_time(QDate(1999, 1, 1), QTime(0, 0));
  157. const QString start_string = start_time.toString(mDatePattern);
  158. mActiveDatePattern.clear();
  159. if (start_string != static_cast<DateTime>(start_time.addSecs(60)).toString(mDatePattern))
  160. mFrequency = MINUTELY_ROLLOVER;
  161. else if (start_string != static_cast<DateTime>(start_time.addSecs(60 * 60)).toString(mDatePattern))
  162. mFrequency = HOURLY_ROLLOVER;
  163. else if (start_string != static_cast<DateTime>(start_time.addSecs(60 * 60 * 12)).toString(mDatePattern))
  164. mFrequency = HALFDAILY_ROLLOVER;
  165. else if (start_string != static_cast<DateTime>(start_time.addDays(1)).toString(mDatePattern))
  166. mFrequency = DAILY_ROLLOVER;
  167. else if (start_string != static_cast<DateTime>(start_time.addDays(7)).toString(mDatePattern))
  168. mFrequency = WEEKLY_ROLLOVER;
  169. else if (start_string != static_cast<DateTime>(start_time.addMonths(1)).toString(mDatePattern))
  170. mFrequency = MONTHLY_ROLLOVER;
  171. else
  172. {
  173. LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("The pattern '%1' does not specify a frequency for appender '%2'"),
  174. APPENDER_INVALID_PATTERN_ERROR);
  175. e << mDatePattern << name();
  176. logger()->error(e);
  177. return;
  178. }
  179. mActiveDatePattern = mDatePattern;
  180. logger()->trace("Frequency set to %2 using date pattern %1",
  181. mActiveDatePattern,
  182. frequencyToString());
  183. }
  184. void DailyRollingFileAppender::computeRollOverTime()
  185. {
  186. // Q_ASSERT_X(, "DailyRollingFileAppender::computeRollOverTime()", "Lock must be held by caller")
  187. Q_ASSERT_X(!mActiveDatePattern.isEmpty(), "DailyRollingFileAppender::computeRollOverTime()", "No active date pattern");
  188. QDateTime now = QDateTime::currentDateTime();
  189. QDate now_date = now.date();
  190. QTime now_time = now.time();
  191. QDateTime start;
  192. switch (mFrequency)
  193. {
  194. case MINUTELY_ROLLOVER:
  195. {
  196. start = QDateTime(now_date,
  197. QTime(now_time.hour(),
  198. now_time.minute(),
  199. 0, 0));
  200. mRollOverTime = start.addSecs(60);
  201. }
  202. break;
  203. case HOURLY_ROLLOVER:
  204. {
  205. start = QDateTime(now_date,
  206. QTime(now_time.hour(),
  207. 0, 0, 0));
  208. mRollOverTime = start.addSecs(60*60);
  209. }
  210. break;
  211. case HALFDAILY_ROLLOVER:
  212. {
  213. int hour = now_time.hour();
  214. if (hour >= 12)
  215. hour = 12;
  216. else
  217. hour = 0;
  218. start = QDateTime(now_date,
  219. QTime(hour, 0, 0, 0));
  220. mRollOverTime = start.addSecs(60*60*12);
  221. }
  222. break;
  223. case DAILY_ROLLOVER:
  224. {
  225. start = QDateTime(now_date,
  226. QTime(0, 0, 0, 0));
  227. mRollOverTime = start.addDays(1);
  228. }
  229. break;
  230. case WEEKLY_ROLLOVER:
  231. {
  232. // QT numbers the week days 1..7. The week starts on Monday.
  233. // Change it to being numbered 0..6, starting with Sunday.
  234. int day = now_date.dayOfWeek();
  235. if (day == Qt::Sunday)
  236. day = 0;
  237. start = QDateTime(now_date,
  238. QTime(0, 0, 0, 0)).addDays(-1 * day);
  239. mRollOverTime = start.addDays(7);
  240. }
  241. break;
  242. case MONTHLY_ROLLOVER:
  243. {
  244. start = QDateTime(QDate(now_date.year(),
  245. now_date.month(),
  246. 1),
  247. QTime(0, 0, 0, 0));
  248. mRollOverTime = start.addMonths(1);
  249. }
  250. break;
  251. default:
  252. Q_ASSERT_X(false, "DailyRollingFileAppender::computeInterval()", "Invalid datePattern constant");
  253. mRollOverTime = QDateTime::fromTime_t(0);
  254. }
  255. mRollOverSuffix = static_cast<DateTime>(start).toString(mActiveDatePattern);
  256. Q_ASSERT_X(static_cast<DateTime>(now).toString(mActiveDatePattern) == mRollOverSuffix,
  257. "DailyRollingFileAppender::computeRollOverTime()", "File name changes within interval");
  258. Q_ASSERT_X(mRollOverSuffix != static_cast<DateTime>(mRollOverTime).toString(mActiveDatePattern),
  259. "DailyRollingFileAppender::computeRollOverTime()", "File name does not change with rollover");
  260. logger()->trace("Computing roll over time from %1: The interval start time is %2. The roll over time is %3",
  261. now,
  262. start,
  263. mRollOverTime);
  264. }
  265. QString DailyRollingFileAppender::frequencyToString() const
  266. {
  267. QMetaEnum meta_enum = metaObject()->enumerator(metaObject()->indexOfEnumerator("DatePattern"));
  268. return QLatin1String(meta_enum.valueToKey(mFrequency));
  269. }
  270. void DailyRollingFileAppender::rollOver()
  271. {
  272. // Q_ASSERT_X(, "DailyRollingFileAppender::rollOver()", "Lock must be held by caller")
  273. Q_ASSERT_X(!mActiveDatePattern.isEmpty(), "DailyRollingFileAppender::rollOver()", "No active date pattern");
  274. QString roll_over_suffix = mRollOverSuffix;
  275. computeRollOverTime();
  276. if (roll_over_suffix == mRollOverSuffix)
  277. return;
  278. closeFile();
  279. QString target_file_name = file() + roll_over_suffix;
  280. QFile f(target_file_name);
  281. if (f.exists() && !removeFile(f))
  282. return;
  283. f.setFileName(file());
  284. if (!renameFile(f, target_file_name))
  285. return;
  286. openFile();
  287. }
  288. /**************************************************************************
  289. * Implementation: Operators, Helper
  290. **************************************************************************/
  291. } // namespace Log4Qt