1 /******************************************************************************
2 QtAV: Multimedia framework based on Qt and FFmpeg
3 Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
4
5 * This file is part of QtAV (from 2013)
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 ******************************************************************************/
21
22 /*!
23 * DO NOT appear qDebug, qWanring etc in Logger.cpp! They are undefined and redefined to QtAV:Internal::Logger.xxx
24 */
25 // we need LogLevel so must include QtAV_Global.h
26 #include <QtCore/QString>
27 #include <QtCore/QMutex>
28 #include "QtAV/QtAV_Global.h"
29 #include "Logger.h"
30
31 #ifndef QTAV_NO_LOG_LEVEL
32
33 void ffmpeg_version_print();
34 namespace QtAV {
35 namespace Internal {
36 static QString gQtAVLogTag = QString();
37
38 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
39 typedef Logger::Context QMessageLogger;
40 #endif
41
log_helper(QtMsgType msgType,const QMessageLogger * qlog,const char * msg,va_list ap)42 static void log_helper(QtMsgType msgType, const QMessageLogger *qlog, const char* msg, va_list ap) {
43 static QMutex m;
44 QMutexLocker lock(&m);
45 Q_UNUSED(lock);
46 static int repeat = 0;
47 static QString last_msg;
48 static QtMsgType last_type = QtDebugMsg;
49 QString qmsg(gQtAVLogTag);
50 QString formated;
51 if (msg) {
52 formated = QString().vsprintf(msg, ap);
53 }
54 // repeate check
55 if (last_type == msgType && last_msg == formated) {
56 repeat++;
57 return;
58 }
59 if (repeat > 0) {
60 // print repeat message and current message
61 qmsg = QStringLiteral("%1(repeat %2)%3\n%4%5")
62 .arg(qmsg).arg(repeat).arg(last_msg).arg(qmsg).arg(formated);
63 } else {
64 qmsg += formated;
65 }
66 repeat = 0;
67 last_type = msgType;
68 last_msg = formated;
69
70 // qt_message_output is a public api
71 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
72 qt_message_output(msgType, qmsg.toUtf8().constData());
73 return;
74 #else
75 if (!qlog) {
76 QMessageLogContext ctx;
77 qt_message_output(msgType, ctx, qmsg);
78 return;
79 }
80 #endif
81 #ifndef QT_NO_DEBUG_STREAM
82 if (msgType == QtWarningMsg)
83 qlog->warning() << qmsg;
84 else if (msgType == QtCriticalMsg)
85 qlog->critical() << qmsg;
86 else if (msgType == QtFatalMsg)
87 qlog->fatal("%s", qmsg.toUtf8().constData());
88 else
89 qlog->debug() << qmsg;
90 #else
91 if (msgType == QtFatalMsg)
92 qlog->fatal("%s", qmsg.toUtf8().constData());
93 #endif //
94 }
95
96 // macro does not support A::##X
97
debug(const char * msg,...) const98 void Logger::debug(const char *msg, ...) const
99 {
100 QtAVDebug d; // initialize something. e.g. environment check
101 Q_UNUSED(d);
102 const int v = (int)logLevel();
103 if (v <= (int)LogOff)
104 return;
105 if (v > (int)LogDebug && v < (int)LogAll)
106 return;
107 va_list ap;
108 va_start(ap, msg);
109 // can not use ctx.debug() <<... because QT_NO_DEBUG_STREAM maybe defined
110 log_helper(QtDebugMsg, &ctx, msg, ap);
111 va_end(ap);
112 }
113
warning(const char * msg,...) const114 void Logger::warning(const char *msg, ...) const
115 {
116 QtAVDebug d; // initialize something. e.g. environment check
117 Q_UNUSED(d);
118 const int v = (int)logLevel();
119 if (v <= (int)LogOff)
120 return;
121 if (v > (int)LogWarning && v < (int)LogAll)
122 return;
123 va_list ap;
124 va_start(ap, msg);
125 log_helper(QtWarningMsg, &ctx, msg, ap);
126 va_end(ap);
127 }
128
critical(const char * msg,...) const129 void Logger::critical(const char *msg, ...) const
130 {
131 QtAVDebug d; // initialize something. e.g. environment check
132 Q_UNUSED(d);
133 const int v = (int)logLevel();
134 if (v <= (int)LogOff)
135 return;
136 if (v > (int)LogCritical && v < (int)LogAll)
137 return;
138 va_list ap;
139 va_start(ap, msg);
140 log_helper(QtCriticalMsg, &ctx, msg, ap);
141 va_end(ap);
142 }
143
fatal(const char * msg,...) const144 void Logger::fatal(const char *msg, ...) const Q_DECL_NOTHROW
145 {
146 QtAVDebug d; // initialize something. e.g. environment check
147 Q_UNUSED(d);
148 const int v = (int)logLevel();
149 /*
150 if (v <= (int)LogOff)
151 abort();
152 if (v > (int)LogFatal && v < (int)LogAll)
153 abort();
154 */
155 if (v > (int)LogOff) {
156 va_list ap;
157 va_start(ap, msg);
158 log_helper(QtFatalMsg, &ctx, msg, ap);
159 va_end(ap);
160 }
161 abort();
162 }
163
164 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
165 #ifndef QT_NO_DEBUG_STREAM
166 // internal used by Logger::fatal(const char*,...) with log level checked, so always do things here
fatal(const char * msg,...) const167 void Logger::Context::fatal(const char *msg, ...) const Q_DECL_NOTHROW
168 {
169 va_list ap;
170 va_start(ap, msg);
171 QString qmsg;
172 if (msg)
173 qmsg += QString().vsprintf(msg, ap);
174 qt_message_output(QtFatalMsg, qmsg.toUtf8().constData());
175 va_end(ap);
176 abort();
177 }
178 #endif //QT_NO_DEBUG_STREAM
179 #endif //QT_VERSION
180
181 #ifndef QT_NO_DEBUG_STREAM
182 // will print message in ~QDebug()
183 // can not use QDebug on stack. It must lives in QtAVDebug
debug() const184 QtAVDebug Logger::debug() const
185 {
186 QtAVDebug d(QtDebugMsg); //// initialize something. e.g. environment check
187 const int v = (int)logLevel();
188 if (v <= (int)LogOff)
189 return d;
190 if (v <= (int)LogDebug || v >= (int)LogAll)
191 d.setQDebug(new QDebug(ctx.debug()));
192 return d; //ref > 0
193 }
194
warning() const195 QtAVDebug Logger::warning() const
196 {
197 QtAVDebug d(QtWarningMsg);
198 const int v = (int)logLevel();
199 if (v <= (int)LogOff)
200 return d;
201 if (v <= (int)LogWarning || v >= (int)LogAll)
202 d.setQDebug(new QDebug(ctx.warning()));
203 return d;
204 }
205
critical() const206 QtAVDebug Logger::critical() const
207 {
208 QtAVDebug d(QtCriticalMsg);
209 const int v = (int)logLevel();
210 if (v <= (int)LogOff)
211 return d;
212 if (v <= (int)LogCritical || v >= (int)LogAll)
213 d.setQDebug(new QDebug(ctx.critical()));
214 return d;
215 }
216 // no QMessageLogger::fatal()
217 #endif //QT_NO_DEBUG_STREAM
218
219 bool isLogLevelSet();
220 void print_library_info();
221
QtAVDebug(QtMsgType t,QDebug * d)222 QtAVDebug::QtAVDebug(QtMsgType t, QDebug *d)
223 : type(t)
224 , dbg(0)
225 {
226 if (d)
227 setQDebug(d); // call *dbg << gQtAVLogTag
228 static bool sFirstRun = true;
229 if (!sFirstRun)
230 return;
231 sFirstRun = false;
232 printf("%s\n", aboutQtAV_PlainText().toUtf8().constData());
233 // check environment var and call other functions at first Qt logging call
234 // always override setLogLevel()
235 QByteArray env = qgetenv("QTAV_LOG_LEVEL");
236 if (env.isEmpty())
237 env = qgetenv("QTAV_LOG");
238 if (!env.isEmpty()) {
239 bool ok = false;
240 const int level = env.toInt(&ok);
241 if (ok) {
242 if (level < (int)LogOff)
243 setLogLevel(LogOff);
244 else if (level > (int)LogAll)
245 setLogLevel(LogAll);
246 else
247 setLogLevel((LogLevel)level);
248 } else {
249 env = env.toLower();
250 if (env.endsWith("off"))
251 setLogLevel(LogOff);
252 else if (env.endsWith("debug"))
253 setLogLevel(LogDebug);
254 else if (env.endsWith("warning"))
255 setLogLevel(LogWarning);
256 else if (env.endsWith("critical"))
257 setLogLevel(LogCritical);
258 else if (env.endsWith("fatal"))
259 setLogLevel(LogFatal);
260 else if (env.endsWith("all") || env.endsWith("default"))
261 setLogLevel(LogAll);
262 }
263 }
264 env = qgetenv("QTAV_LOG_TAG");
265 if (!env.isEmpty()) {
266 gQtAVLogTag = QString::fromUtf8(env);
267 }
268
269 if ((int)logLevel() > (int)LogOff) {
270 print_library_info();
271 }
272 }
273
~QtAVDebug()274 QtAVDebug::~QtAVDebug()
275 {
276 }
277
setQDebug(QDebug * d)278 void QtAVDebug::setQDebug(QDebug *d)
279 {
280 dbg = QSharedPointer<QDebug>(d);
281 if (dbg && !gQtAVLogTag.isEmpty()) {
282 *dbg << gQtAVLogTag;
283 }
284 }
285
286 #if 0
287 QtAVDebug debug(const char *msg, ...)
288 {
289 if ((int)logLevel() > (int)Debug && logLevel() != All) {
290 return QtAVDebug();
291 }
292 va_list ap;
293 va_start(ap, msg); // use variable arg list
294 QMessageLogContext ctx;
295 log_helper(QtDebugMsg, &ctx, msg, ap);
296 va_end(ap);
297 return QtAVDebug();
298 }
299 #endif
300
301 } //namespace Internal
302 } // namespace QtAV
303
304 #endif //QTAV_NO_LOG_LEVEL
305