QsLogDestFile.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // Copyright (c) 2013, Razvan Petru
  2. // All rights reserved.
  3. // Redistribution and use in source and binary forms, with or without modification,
  4. // are permitted provided that the following conditions are met:
  5. // * Redistributions of source code must retain the above copyright notice, this
  6. // list of conditions and the following disclaimer.
  7. // * Redistributions in binary form must reproduce the above copyright notice, this
  8. // list of conditions and the following disclaimer in the documentation and/or other
  9. // materials provided with the distribution.
  10. // * The name of the contributors may not be used to endorse or promote products
  11. // derived from this software without specific prior written permission.
  12. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  13. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  15. // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  16. // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  17. // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  18. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  19. // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  20. // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  21. // OF THE POSSIBILITY OF SUCH DAMAGE.
  22. #include "QsLogDestFile.h"
  23. #include <QTextCodec>
  24. #include <QDateTime>
  25. #include <QtGlobal>
  26. #include <iostream>
  27. const int QsLogging::SizeRotationStrategy::MaxBackupCount = 10;
  28. QsLogging::RotationStrategy::~RotationStrategy()
  29. {
  30. }
  31. QsLogging::SizeRotationStrategy::SizeRotationStrategy() : mCurrentSizeInBytes(0), mMaxSizeInBytes(0), mBackupsCount(0)
  32. {
  33. }
  34. void QsLogging::SizeRotationStrategy::setInitialInfo(const QFile& file)
  35. {
  36. mFileName = file.fileName();
  37. mCurrentSizeInBytes = file.size();
  38. }
  39. void QsLogging::SizeRotationStrategy::includeMessageInCalculation(const QString& message)
  40. {
  41. mCurrentSizeInBytes += message.toUtf8().size();
  42. }
  43. bool QsLogging::SizeRotationStrategy::shouldRotate()
  44. {
  45. return mCurrentSizeInBytes > mMaxSizeInBytes;
  46. }
  47. // Algorithm assumes backups will be named filename.X, where 1 <= X <= mBackupsCount.
  48. // All X's will be shifted up.
  49. void QsLogging::SizeRotationStrategy::rotate()
  50. {
  51. if (!mBackupsCount)
  52. {
  53. if (!QFile::remove(mFileName))
  54. std::cerr << "QsLog: backup delete failed " << qPrintable(mFileName);
  55. return;
  56. }
  57. // 1. find the last existing backup than can be shifted up
  58. const QString logNamePattern = mFileName + QString::fromUtf8(".%1");
  59. int lastExistingBackupIndex = 0;
  60. for (int i = 1; i <= mBackupsCount; ++i)
  61. {
  62. const QString backupFileName = logNamePattern.arg(i);
  63. if (QFile::exists(backupFileName))
  64. lastExistingBackupIndex = qMin(i, mBackupsCount - 1);
  65. else
  66. break;
  67. }
  68. // 2. shift up
  69. for (int i = lastExistingBackupIndex; i >= 1; --i)
  70. {
  71. const QString oldName = logNamePattern.arg(i);
  72. const QString newName = logNamePattern.arg(i + 1);
  73. QFile::remove(newName);
  74. const bool renamed = QFile::rename(oldName, newName);
  75. if (!renamed)
  76. {
  77. std::cerr << "QsLog: could not rename backup " << qPrintable(oldName) << " to " << qPrintable(newName);
  78. }
  79. }
  80. // 3. rename current log file
  81. const QString newName = logNamePattern.arg(1);
  82. if (QFile::exists(newName))
  83. QFile::remove(newName);
  84. if (!QFile::rename(mFileName, newName))
  85. {
  86. std::cerr << "QsLog: could not rename log " << qPrintable(mFileName) << " to " << qPrintable(newName);
  87. }
  88. }
  89. QIODevice::OpenMode QsLogging::SizeRotationStrategy::recommendedOpenModeFlag()
  90. {
  91. return QIODevice::Append;
  92. }
  93. void QsLogging::SizeRotationStrategy::setMaximumSizeInBytes(qint64 size)
  94. {
  95. Q_ASSERT(size >= 0);
  96. mMaxSizeInBytes = size;
  97. }
  98. void QsLogging::SizeRotationStrategy::setBackupCount(int backups)
  99. {
  100. Q_ASSERT(backups >= 0);
  101. mBackupsCount = qMin(backups, SizeRotationStrategy::MaxBackupCount);
  102. }
  103. qint64 QsLogging::SizeRotationStrategy::currentSizeInBytes()
  104. {
  105. return mCurrentSizeInBytes;
  106. }
  107. QsLogging::FileDestination::FileDestination(const QString& filePath, RotationStrategyPtr rotationStrategy)
  108. : mRotationStrategy(rotationStrategy)
  109. {
  110. mFile.setFileName(filePath);
  111. if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag()))
  112. std::cerr << "QsLog: could not open log file " << qPrintable(filePath);
  113. mOutputStream.setDevice(&mFile);
  114. mOutputStream.setCodec("UTF-8");
  115. mRotationStrategy->setInitialInfo(mFile);
  116. }
  117. void QsLogging::FileDestination::write(const QString& message, Level)
  118. {
  119. mRotationStrategy->includeMessageInCalculation(message);
  120. if (mRotationStrategy->shouldRotate())
  121. rotate();
  122. mOutputStream << message << "\n";
  123. mOutputStream.flush();
  124. }
  125. bool QsLogging::FileDestination::isValid()
  126. {
  127. return mFile.isOpen();
  128. }
  129. void QsLogging::FileDestination::rotate()
  130. {
  131. mOutputStream.setDevice(NULL);
  132. mFile.close();
  133. mRotationStrategy->rotate();
  134. if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag()))
  135. std::cerr << "QsLog: could not reopen log file " << qPrintable(mFile.fileName());
  136. mRotationStrategy->setInitialInfo(mFile);
  137. mOutputStream.setDevice(&mFile);
  138. mOutputStream.setCodec("UTF-8");
  139. }