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