appenderskeleton.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /******************************************************************************
  2. *
  3. * package: Log4Qt
  4. * file: appenderskeleton.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/appenderskeleton.h"
  28. #include <QtCore/QDebug>
  29. #include "log4qt/layout.h"
  30. #include "log4qt/loggingevent.h"
  31. #include "log4qt/logmanager.h"
  32. #include "log4qt/spi/filter.h"
  33. namespace Log4Qt
  34. {
  35. /**************************************************************************
  36. * Declarations
  37. ***************************************************************************/
  38. /*!
  39. * \brief The class RecursionGuardLocker controls a boolean flag.
  40. *
  41. * It is a helper class to control a boolean flag. The class sets the flag
  42. * on creation and resets it on destruction.
  43. */
  44. class RecursionGuardLocker
  45. {
  46. public:
  47. RecursionGuardLocker(bool *pGuard);
  48. ~RecursionGuardLocker();
  49. private:
  50. RecursionGuardLocker(const RecursionGuardLocker &rOther); // Not implemented
  51. RecursionGuardLocker &operator=(const RecursionGuardLocker &rOther); // Not implemented
  52. private:
  53. bool *mpGuard;
  54. };
  55. /**************************************************************************
  56. * C helper functions
  57. **************************************************************************/
  58. /**************************************************************************
  59. * Class implementation: RecursionGuardLocker
  60. ***************************************************************************/
  61. inline RecursionGuardLocker::RecursionGuardLocker(bool *pGuard)
  62. {
  63. Q_ASSERT_X(pGuard != 0, "RecursionGuardLocker::RecursionGuardLocker()", "Pointer to guard bool must not be null");
  64. mpGuard = pGuard;
  65. *mpGuard = true;
  66. }
  67. inline RecursionGuardLocker::~RecursionGuardLocker()
  68. {
  69. *mpGuard = false;
  70. };
  71. /**************************************************************************
  72. * Class implementation: AppenderSkeleton
  73. **************************************************************************/
  74. AppenderSkeleton::AppenderSkeleton(QObject *pParent) :
  75. Appender(pParent),
  76. mObjectGuard(QMutex::Recursive), // Recursive for doAppend()
  77. mAppendRecursionGuard(false),
  78. mIsActive(true),
  79. mIsClosed(false),
  80. mpLayout(0),
  81. mThreshold(Level::NULL_INT),
  82. mpHeadFilter(0),
  83. mpTailFilter(0)
  84. {
  85. }
  86. AppenderSkeleton::AppenderSkeleton(const bool isActive,
  87. QObject *pParent) :
  88. Appender(pParent),
  89. mObjectGuard(QMutex::Recursive), // Recursive for doAppend()
  90. mAppendRecursionGuard(false),
  91. mIsActive(isActive),
  92. mIsClosed(false),
  93. mpLayout(0),
  94. mThreshold(Level::NULL_INT),
  95. mpHeadFilter(0),
  96. mpTailFilter(0)
  97. {
  98. }
  99. void AppenderSkeleton::activateOptions()
  100. {
  101. QMutexLocker locker(&mObjectGuard);
  102. if (requiresLayout() && !layout())
  103. {
  104. LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Activation of appender '%1' that requires layout and has no layout set"),
  105. APPENDER_ACTIVATE_MISSING_LAYOUT_ERROR);
  106. e << name();
  107. logger()->error(e);
  108. return;
  109. }
  110. mIsActive = true;
  111. }
  112. void AppenderSkeleton::addFilter(Filter *pFilter)
  113. {
  114. if(!pFilter)
  115. {
  116. logger()->warn("Adding null Filter to Appender '%1'", name());
  117. return;
  118. }
  119. QMutexLocker locker(&mObjectGuard);
  120. mpTailFilter = pFilter;
  121. if (mpHeadFilter)
  122. mpHeadFilter->setNext(pFilter);
  123. else
  124. mpHeadFilter = pFilter;
  125. }
  126. void AppenderSkeleton::clearFilters()
  127. {
  128. QMutexLocker locker(&mObjectGuard);
  129. mpTailFilter = 0;
  130. mpHeadFilter = 0;
  131. }
  132. void AppenderSkeleton::close()
  133. {
  134. QMutexLocker locker(&mObjectGuard);
  135. mIsClosed = true;
  136. mIsActive = false;
  137. }
  138. void AppenderSkeleton::doAppend(const LoggingEvent &rEvent)
  139. {
  140. // The mutex serialises concurrent access from multiple threads.
  141. // - e.g. two threads using the same logger
  142. // - e.g. two threads using different logger with the same appender
  143. //
  144. // A call from the same thread will pass the mutex (QMutex::Recursive)
  145. // and get to the recursion guard. The recursion guard blocks recursive
  146. // invocation and prevents a possible endless loop.
  147. // - e.g. an appender logs an error with a logger that uses it
  148. QMutexLocker locker(&mObjectGuard);
  149. if (mAppendRecursionGuard)
  150. return;
  151. RecursionGuardLocker recursion_locker(&mAppendRecursionGuard);
  152. if (!checkEntryConditions())
  153. return;
  154. if (!isAsSevereAsThreshold(rEvent.level()))
  155. return;
  156. Filter *p_filter = mpHeadFilter;
  157. while(p_filter)
  158. {
  159. Filter::Decision decision = p_filter->decide(rEvent);
  160. if (decision == Filter::ACCEPT)
  161. break;
  162. else if (decision == Filter::DENY)
  163. return;
  164. else
  165. p_filter = p_filter->next();
  166. }
  167. append(rEvent);
  168. }
  169. bool AppenderSkeleton::checkEntryConditions() const
  170. {
  171. // Q_ASSERT_X(, "WriterAppender::checkEntryConditions()", "Lock must be held by caller")
  172. if (!isActive())
  173. {
  174. LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of non activated appender '%1'"),
  175. APPENDER_NOT_ACTIVATED_ERROR);
  176. e << name();
  177. logger()->error(e);
  178. return false;
  179. }
  180. if (isClosed())
  181. {
  182. LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of closed appender '%1'"),
  183. APPENDER_CLOSED_ERROR);
  184. e << name();
  185. logger()->error(e);
  186. return false;
  187. }
  188. if (requiresLayout() && !layout())
  189. {
  190. LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of appender '%1' that requires layout and has no layout set"),
  191. APPENDER_USE_MISSING_LAYOUT_ERROR);
  192. e << name();
  193. logger()->error(e);
  194. return false;
  195. }
  196. return true;
  197. }
  198. /**************************************************************************
  199. * Implementation: Operators, Helper
  200. **************************************************************************/
  201. } // namespace Log4Qt