ctkErrorLogStreamMessageHandler.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // Qt includes
  15. #include <QMutexLocker>
  16. #include <QThread>
  17. #include <QHash>
  18. // CTK includes
  19. #include "ctkErrorLogContext.h"
  20. #include "ctkErrorLogStreamMessageHandler.h"
  21. #include "ctkUtils.h"
  22. // STD includes
  23. #include <iostream>
  24. #include <streambuf>
  25. #include <string>
  26. namespace
  27. {
  28. // --------------------------------------------------------------------------
  29. // ctkStreamHandler
  30. //
  31. // See http://lists.trolltech.com/qt-interest/2005-06/thread00166-0.html
  32. //
  33. // --------------------------------------------------------------------------
  34. class ctkStreamHandler : public std::streambuf
  35. {
  36. public:
  37. ctkStreamHandler(ctkErrorLogStreamMessageHandler* messageHandler,
  38. ctkErrorLogLevel::LogLevel logLevel,
  39. std::ostream& stream);
  40. void setEnabled(bool value);
  41. protected:
  42. virtual int_type overflow(int_type v);
  43. virtual std::streamsize xsputn(const char *p, std::streamsize n);
  44. private:
  45. void initBuffer();
  46. std::string* currentBuffer();
  47. ctkErrorLogStreamMessageHandler * MessageHandler;
  48. ctkErrorLogLevel::LogLevel LogLevel;
  49. ctkErrorLogContext LogContext;
  50. bool Enabled;
  51. std::ostream& Stream;
  52. std::streambuf* SavedBuffer;
  53. QHash<Qt::HANDLE, std::string*> StringBuffers;
  54. QMutex Mutex;
  55. };
  56. // --------------------------------------------------------------------------
  57. // ctkStreamHandler methods
  58. // --------------------------------------------------------------------------
  59. ctkStreamHandler::ctkStreamHandler(ctkErrorLogStreamMessageHandler* messageHandler,
  60. ctkErrorLogLevel::LogLevel logLevel,
  61. std::ostream& stream) :
  62. MessageHandler(messageHandler), LogLevel(logLevel), Stream(stream)
  63. {
  64. this->Enabled = false;
  65. }
  66. // --------------------------------------------------------------------------
  67. void ctkStreamHandler::setEnabled(bool value)
  68. {
  69. if (this->Enabled == value)
  70. {
  71. return;
  72. }
  73. if (value)
  74. {
  75. this->SavedBuffer = this->Stream.rdbuf();
  76. this->Stream.rdbuf(this);
  77. }
  78. else
  79. {
  80. // Output anything that is left
  81. // if (!this->StringBuffer.empty())
  82. // {
  83. // Q_ASSERT(this->MessageHandler);
  84. // this->MessageHandler->handleMessage(this->LogLevel,
  85. // this->MessageHandler->handlerPrettyName(), this->StringBuffer.c_str());
  86. // }
  87. this->Stream.rdbuf(this->SavedBuffer);
  88. }
  89. this->Enabled = value;
  90. }
  91. // --------------------------------------------------------------------------
  92. void ctkStreamHandler::initBuffer()
  93. {
  94. Qt::HANDLE threadId = QThread::currentThreadId();
  95. if (!this->StringBuffers.contains(threadId))
  96. {
  97. this->StringBuffers.insert(threadId, new std::string);
  98. }
  99. }
  100. // --------------------------------------------------------------------------
  101. std::string* ctkStreamHandler::currentBuffer()
  102. {
  103. return this->StringBuffers.value(QThread::currentThreadId());
  104. }
  105. // --------------------------------------------------------------------------
  106. std::streambuf::int_type ctkStreamHandler::overflow(std::streambuf::int_type v)
  107. {
  108. QMutexLocker locker(&this->Mutex);
  109. this->initBuffer();
  110. if (v == '\n')
  111. {
  112. Q_ASSERT(this->MessageHandler);
  113. this->MessageHandler->handleMessage(
  114. ctk::qtHandleToString(QThread::currentThreadId()), this->LogLevel,
  115. this->MessageHandler->handlerPrettyName(),
  116. ctkErrorLogContext(this->currentBuffer()->c_str()), this->currentBuffer()->c_str());
  117. this->currentBuffer()->erase(this->currentBuffer()->begin(), this->currentBuffer()->end());
  118. }
  119. else
  120. {
  121. *this->currentBuffer() += v;
  122. }
  123. return v;
  124. }
  125. // --------------------------------------------------------------------------
  126. std::streamsize ctkStreamHandler::xsputn(const char *p, std::streamsize n)
  127. {
  128. QMutexLocker locker(&this->Mutex);
  129. this->initBuffer();
  130. this->currentBuffer()->append(p, p + n);
  131. std::string::size_type pos = 0;
  132. while (pos != std::string::npos)
  133. {
  134. pos = this->currentBuffer()->find('\n');
  135. if (pos != std::string::npos)
  136. {
  137. std::string tmp(this->currentBuffer()->begin(), this->currentBuffer()->begin() + pos);
  138. Q_ASSERT(this->MessageHandler);
  139. this->MessageHandler->handleMessage(
  140. ctk::qtHandleToString(QThread::currentThreadId()), this->LogLevel,
  141. this->MessageHandler->handlerPrettyName(),
  142. ctkErrorLogContext(tmp.c_str()), tmp.c_str());
  143. this->currentBuffer()->erase(this->currentBuffer()->begin(), this->currentBuffer()->begin() + pos + 1);
  144. }
  145. }
  146. return n;
  147. }
  148. }
  149. // --------------------------------------------------------------------------
  150. // ctkErrorLogStreamMessageHandlerPrivate
  151. // --------------------------------------------------------------------------
  152. class ctkErrorLogStreamMessageHandlerPrivate
  153. {
  154. public:
  155. ctkErrorLogStreamMessageHandlerPrivate();
  156. ~ctkErrorLogStreamMessageHandlerPrivate();
  157. ctkStreamHandler * CoutStreamHandler;
  158. ctkStreamHandler * CerrStreamHandler;
  159. };
  160. // --------------------------------------------------------------------------
  161. // ctkErrorLogStreamMessageHandlerPrivate methods
  162. //------------------------------------------------------------------------------
  163. ctkErrorLogStreamMessageHandlerPrivate::ctkErrorLogStreamMessageHandlerPrivate()
  164. {
  165. }
  166. //------------------------------------------------------------------------------
  167. ctkErrorLogStreamMessageHandlerPrivate::~ctkErrorLogStreamMessageHandlerPrivate()
  168. {
  169. delete this->CoutStreamHandler;
  170. delete this->CerrStreamHandler;
  171. }
  172. //------------------------------------------------------------------------------
  173. // ctkErrorLogStreamMessageHandler methods
  174. //------------------------------------------------------------------------------
  175. QString ctkErrorLogStreamMessageHandler::HandlerName = QLatin1String("Stream");
  176. // --------------------------------------------------------------------------
  177. ctkErrorLogStreamMessageHandler::ctkErrorLogStreamMessageHandler() :
  178. Superclass(), d_ptr(new ctkErrorLogStreamMessageHandlerPrivate())
  179. {
  180. Q_D(ctkErrorLogStreamMessageHandler);
  181. d->CoutStreamHandler = new ctkStreamHandler(this, ctkErrorLogLevel::Info, std::cout);
  182. d->CerrStreamHandler = new ctkStreamHandler(this, ctkErrorLogLevel::Critical, std::cerr);
  183. }
  184. // --------------------------------------------------------------------------
  185. ctkErrorLogStreamMessageHandler::~ctkErrorLogStreamMessageHandler()
  186. {
  187. }
  188. // --------------------------------------------------------------------------
  189. QString ctkErrorLogStreamMessageHandler::handlerName()const
  190. {
  191. return ctkErrorLogStreamMessageHandler::HandlerName;
  192. }
  193. // --------------------------------------------------------------------------
  194. void ctkErrorLogStreamMessageHandler::setEnabledInternal(bool value)
  195. {
  196. Q_D(ctkErrorLogStreamMessageHandler);
  197. d->CoutStreamHandler->setEnabled(value);
  198. d->CerrStreamHandler->setEnabled(value);
  199. }