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 <QAtomicInt>
23 #include <QCoreApplication>
24 #include <QThread>
25 #include <QVariant>
26
27 // CTK includes
28 #include "ctkErrorLogContext.h"
29 #include "ctkErrorLogQtMessageHandler.h"
30 #include <ctkUtils.h>
31
32 // STD includes
33 #include <iostream>
34
35 // Handling log messages may generate log messages, which would cause infinite loop.
36 // We stop handling log messages if the maximum recursion depth is reached.
37 static QAtomicInt ctkErrorLogQtMessageHandler_CurrentRecursionDepth;
38
39 //------------------------------------------------------------------------------
40 QString ctkErrorLogQtMessageHandler::HandlerName = QLatin1String("Qt");
41
42 //------------------------------------------------------------------------------
43 //Q_DECLARE_METATYPE(QPointer<ctkErrorLogQtMessageHandler>)
Q_DECLARE_METATYPE(ctkErrorLogQtMessageHandler *)44 Q_DECLARE_METATYPE(ctkErrorLogQtMessageHandler*)
45
46 // --------------------------------------------------------------------------
47 ctkErrorLogQtMessageHandler::ctkErrorLogQtMessageHandler() : Superclass()
48 {
49 this->SavedQtMessageHandler = 0;
50
51 QCoreApplication * coreApp = QCoreApplication::instance();
52
53 // Keep track of all instantiated ctkErrorLogModel
54 QList<QVariant> handlers = coreApp->property("ctkErrorLogQtMessageHandlers").toList();
55 handlers << QVariant::fromValue(this);
56 //handlers << QVariant::fromValue(QPointer<ctkErrorLogQtMessageHandler>(this));
57 coreApp->setProperty("ctkErrorLogQtMessageHandlers", handlers);
58 }
59
60 namespace
61 {
62 //------------------------------------------------------------------------------
63 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
ctkErrorLogModelQtMessageOutput(QtMsgType type,const QMessageLogContext & context,const QString & msg)64 void ctkErrorLogModelQtMessageOutput(QtMsgType type, const QMessageLogContext& context,
65 const QString& msg)
66 {
67 ctkErrorLogQtMessageHandler_CurrentRecursionDepth.ref();
68 // Allow a couple of recursion levels to get a hint about where and why recursion occurs,
69 // so we stop processing the message if recursion depth is over 10.
70 if (ctkErrorLogQtMessageHandler_CurrentRecursionDepth.load() > 10)
71 {
72 ctkErrorLogQtMessageHandler_CurrentRecursionDepth.deref();
73 return;
74 }
75
76 //TODO: use context in the log message
77 Q_UNUSED(context)
78 // Warning: To avoid inifinite loop, do not use Q_ASSERT in this function.
79 if (msg.isEmpty())
80 {
81 ctkErrorLogQtMessageHandler_CurrentRecursionDepth.deref();
82 return;
83 }
84 ctkErrorLogLevel::LogLevel level = ctkErrorLogLevel::Unknown;
85 if (type == QtDebugMsg)
86 {
87 level = ctkErrorLogLevel::Debug;
88 }
89 #if QT_VERSION >= QT_VERSION_CHECK(5,5,0)
90 else if (type == QtInfoMsg)
91 {
92 level = ctkErrorLogLevel::Info;
93 }
94 #endif
95 else if (type == QtWarningMsg)
96 {
97 level = ctkErrorLogLevel::Warning;
98 }
99 else if (type == QtCriticalMsg)
100 {
101 level = ctkErrorLogLevel::Critical;
102 }
103 else if (type == QtFatalMsg)
104 {
105 level = ctkErrorLogLevel::Fatal;
106 }
107
108 QCoreApplication * coreApp = QCoreApplication::instance();
109 QList<QVariant> handlers = coreApp->property("ctkErrorLogQtMessageHandlers").toList();
110 foreach(QVariant v, handlers)
111 {
112 ctkErrorLogQtMessageHandler* handler = v.value<ctkErrorLogQtMessageHandler*>();
113 Q_ASSERT(handler);
114 // //QPointer<ctkErrorLogQtMessageHandler> handler = v.value<QPointer<ctkErrorLogQtMessageHandler> >();
115 // //if(handler.isNull())
116 // // {
117 // // continue;
118 // // }
119 handler->handleMessage(
120 ctk::qtHandleToString(QThread::currentThreadId()),
121 level, handler->handlerPrettyName(), ctkErrorLogContext(msg), msg);
122 }
123 ctkErrorLogQtMessageHandler_CurrentRecursionDepth.deref();
124 }
125 #else
126 void ctkErrorLogModelQtMessageOutput(QtMsgType type, const char *msg)
127 {
128 ctkErrorLogQtMessageHandler_CurrentRecursionDepth.ref();
129 // Allow a couple of recursion levels to get a hint about where and why recursion occurs,
130 // so we stop processing the message if recursion depth is over 10.
131 if (ctkErrorLogQtMessageHandler_CurrentRecursionDepth > 10)
132 {
133 ctkErrorLogQtMessageHandler_CurrentRecursionDepth.deref();
134 return;
135 }
136
137 // Warning: To avoid inifinite loop, do not use Q_ASSERT in this function.
138 if (QString(msg).isEmpty())
139 {
140 ctkErrorLogQtMessageHandler_CurrentRecursionDepth.deref();
141 return;
142 }
143 ctkErrorLogLevel::LogLevel level = ctkErrorLogLevel::Unknown;
144 if (type == QtDebugMsg)
145 {
146 level = ctkErrorLogLevel::Debug;
147 }
148 else if (type == QtWarningMsg)
149 {
150 level = ctkErrorLogLevel::Warning;
151 }
152 else if (type == QtCriticalMsg)
153 {
154 level = ctkErrorLogLevel::Critical;
155 }
156 else if (type == QtFatalMsg)
157 {
158 level = ctkErrorLogLevel::Fatal;
159 }
160
161 QCoreApplication * coreApp = QCoreApplication::instance();
162 QList<QVariant> handlers = coreApp->property("ctkErrorLogQtMessageHandlers").toList();
163 foreach(QVariant v, handlers)
164 {
165 ctkErrorLogQtMessageHandler* handler = v.value<ctkErrorLogQtMessageHandler*>();
166 Q_ASSERT(handler);
167 // //QPointer<ctkErrorLogQtMessageHandler> handler = v.value<QPointer<ctkErrorLogQtMessageHandler> >();
168 // //if(handler.isNull())
169 // // {
170 // // continue;
171 // // }
172 handler->handleMessage(
173 ctk::qtHandleToString(QThread::currentThreadId()),
174 level, handler->handlerPrettyName(), ctkErrorLogContext(msg), msg);
175 }
176 ctkErrorLogQtMessageHandler_CurrentRecursionDepth.deref();
177 }
178 #endif
179 }
180
181 // --------------------------------------------------------------------------
handlerName() const182 QString ctkErrorLogQtMessageHandler::handlerName()const
183 {
184 return ctkErrorLogQtMessageHandler::HandlerName;
185 }
186
187 // --------------------------------------------------------------------------
setEnabledInternal(bool value)188 void ctkErrorLogQtMessageHandler::setEnabledInternal(bool value)
189 {
190 if (value)
191 {
192 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
193 this->SavedQtMessageHandler = qInstallMessageHandler(ctkErrorLogModelQtMessageOutput);
194 #else
195 this->SavedQtMessageHandler = qInstallMsgHandler(ctkErrorLogModelQtMessageOutput);
196 #endif
197 }
198 else
199 {
200 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
201 qInstallMessageHandler(this->SavedQtMessageHandler);
202 #else
203 qInstallMsgHandler(this->SavedQtMessageHandler);
204 #endif
205 }
206 }
207