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