ctkErrorLogStreamMessageHandler.cpp 7.2 KB

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