ctkErrorLogStreamMessageHandler.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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 "ctkErrorLogStreamMessageHandler.h"
  20. #include "ctkUtils.h"
  21. // STD includes
  22. #include <iostream>
  23. #include <streambuf>
  24. #include <string>
  25. namespace
  26. {
  27. // --------------------------------------------------------------------------
  28. // ctkStreamHandler
  29. //
  30. // See http://lists.trolltech.com/qt-interest/2005-06/thread00166-0.html
  31. //
  32. // --------------------------------------------------------------------------
  33. class ctkStreamHandler : public std::streambuf
  34. {
  35. public:
  36. ctkStreamHandler(ctkErrorLogStreamMessageHandler* messageHandler,
  37. ctkErrorLogLevel::LogLevel logLevel,
  38. std::ostream& stream);
  39. void setEnabled(bool value);
  40. protected:
  41. virtual int_type overflow(int_type v);
  42. virtual std::streamsize xsputn(const char *p, std::streamsize n);
  43. private:
  44. void initBuffer();
  45. std::string* currentBuffer();
  46. ctkErrorLogStreamMessageHandler * MessageHandler;
  47. ctkErrorLogLevel::LogLevel LogLevel;
  48. bool Enabled;
  49. std::ostream& Stream;
  50. std::streambuf* SavedBuffer;
  51. QHash<Qt::HANDLE, std::string*> StringBuffers;
  52. QMutex Mutex;
  53. };
  54. // --------------------------------------------------------------------------
  55. // ctkStreamHandler methods
  56. // --------------------------------------------------------------------------
  57. ctkStreamHandler::ctkStreamHandler(ctkErrorLogStreamMessageHandler* messageHandler,
  58. ctkErrorLogLevel::LogLevel logLevel,
  59. std::ostream& stream) :
  60. MessageHandler(messageHandler), LogLevel(logLevel), Stream(stream)
  61. {
  62. this->Enabled = false;
  63. }
  64. // --------------------------------------------------------------------------
  65. void ctkStreamHandler::setEnabled(bool value)
  66. {
  67. if (this->Enabled == value)
  68. {
  69. return;
  70. }
  71. if (value)
  72. {
  73. this->SavedBuffer = this->Stream.rdbuf();
  74. this->Stream.rdbuf(this);
  75. }
  76. else
  77. {
  78. // Output anything that is left
  79. // if (!this->StringBuffer.empty())
  80. // {
  81. // Q_ASSERT(this->MessageHandler);
  82. // this->MessageHandler->handleMessage(this->LogLevel,
  83. // this->MessageHandler->handlerPrettyName(), this->StringBuffer.c_str());
  84. // }
  85. this->Stream.rdbuf(this->SavedBuffer);
  86. }
  87. this->Enabled = value;
  88. }
  89. // --------------------------------------------------------------------------
  90. void ctkStreamHandler::initBuffer()
  91. {
  92. Qt::HANDLE threadId = QThread::currentThreadId();
  93. if (!this->StringBuffers.contains(threadId))
  94. {
  95. this->StringBuffers.insert(threadId, new std::string);
  96. }
  97. }
  98. // --------------------------------------------------------------------------
  99. std::string* ctkStreamHandler::currentBuffer()
  100. {
  101. return this->StringBuffers.value(QThread::currentThreadId());
  102. }
  103. // --------------------------------------------------------------------------
  104. std::streambuf::int_type ctkStreamHandler::overflow(std::streambuf::int_type v)
  105. {
  106. QMutexLocker locker(&this->Mutex);
  107. this->initBuffer();
  108. if (v == '\n')
  109. {
  110. Q_ASSERT(this->MessageHandler);
  111. this->MessageHandler->handleMessage(
  112. ctk::qtHandleToString(QThread::currentThreadId()), this->LogLevel,
  113. this->MessageHandler->handlerPrettyName(), this->currentBuffer()->c_str());
  114. this->currentBuffer()->erase(this->currentBuffer()->begin(), this->currentBuffer()->end());
  115. }
  116. else
  117. {
  118. *this->currentBuffer() += v;
  119. }
  120. return v;
  121. }
  122. // --------------------------------------------------------------------------
  123. std::streamsize ctkStreamHandler::xsputn(const char *p, std::streamsize n)
  124. {
  125. QMutexLocker locker(&this->Mutex);
  126. this->initBuffer();
  127. this->currentBuffer()->append(p, p + n);
  128. std::string::size_type pos = 0;
  129. while (pos != std::string::npos)
  130. {
  131. pos = this->currentBuffer()->find('\n');
  132. if (pos != std::string::npos)
  133. {
  134. std::string tmp(this->currentBuffer()->begin(), this->currentBuffer()->begin() + pos);
  135. Q_ASSERT(this->MessageHandler);
  136. this->MessageHandler->handleMessage(
  137. ctk::qtHandleToString(QThread::currentThreadId()), this->LogLevel,
  138. this->MessageHandler->handlerPrettyName(), tmp.c_str());
  139. this->currentBuffer()->erase(this->currentBuffer()->begin(), this->currentBuffer()->begin() + pos + 1);
  140. }
  141. }
  142. return n;
  143. }
  144. }
  145. // --------------------------------------------------------------------------
  146. // ctkErrorLogStreamMessageHandlerPrivate
  147. // --------------------------------------------------------------------------
  148. class ctkErrorLogStreamMessageHandlerPrivate
  149. {
  150. public:
  151. ctkErrorLogStreamMessageHandlerPrivate();
  152. ~ctkErrorLogStreamMessageHandlerPrivate();
  153. ctkStreamHandler * CoutStreamHandler;
  154. ctkStreamHandler * CerrStreamHandler;
  155. };
  156. // --------------------------------------------------------------------------
  157. // ctkErrorLogStreamMessageHandlerPrivate methods
  158. //------------------------------------------------------------------------------
  159. ctkErrorLogStreamMessageHandlerPrivate::ctkErrorLogStreamMessageHandlerPrivate()
  160. {
  161. }
  162. //------------------------------------------------------------------------------
  163. ctkErrorLogStreamMessageHandlerPrivate::~ctkErrorLogStreamMessageHandlerPrivate()
  164. {
  165. delete this->CoutStreamHandler;
  166. delete this->CerrStreamHandler;
  167. }
  168. //------------------------------------------------------------------------------
  169. // ctkErrorLogStreamMessageHandler methods
  170. //------------------------------------------------------------------------------
  171. QString ctkErrorLogStreamMessageHandler::HandlerName = QLatin1String("Stream");
  172. // --------------------------------------------------------------------------
  173. ctkErrorLogStreamMessageHandler::ctkErrorLogStreamMessageHandler() :
  174. Superclass(), d_ptr(new ctkErrorLogStreamMessageHandlerPrivate())
  175. {
  176. Q_D(ctkErrorLogStreamMessageHandler);
  177. d->CoutStreamHandler = new ctkStreamHandler(this, ctkErrorLogLevel::Info, std::cout);
  178. d->CerrStreamHandler = new ctkStreamHandler(this, ctkErrorLogLevel::Critical, std::cerr);
  179. }
  180. // --------------------------------------------------------------------------
  181. ctkErrorLogStreamMessageHandler::~ctkErrorLogStreamMessageHandler()
  182. {
  183. }
  184. // --------------------------------------------------------------------------
  185. QString ctkErrorLogStreamMessageHandler::handlerName()const
  186. {
  187. return ctkErrorLogStreamMessageHandler::HandlerName;
  188. }
  189. // --------------------------------------------------------------------------
  190. void ctkErrorLogStreamMessageHandler::setEnabledInternal(bool value)
  191. {
  192. Q_D(ctkErrorLogStreamMessageHandler);
  193. d->CoutStreamHandler->setEnabled(value);
  194. d->CerrStreamHandler->setEnabled(value);
  195. }