QtDebug: Include file, line, function information

Record the file, line, and function where a qDebug, qWarning, qCritical
or qFatal call happens, and make this information available in a custom
message handler.

The patch uses the C preprocessor to replace qDebug, qWarning, ... with
a line that also records the current file, line, and function. Custom
message handlers can access this information via a new QMessageLogContext
argument.

Change-Id: I0a9b89c1d137e41775932d3b1a35da4ebf12d18d
Reviewed-by: David Faure <faure@kde.org>
This commit is contained in:
Kai Koehne 2012-01-17 16:20:45 +01:00 committed by Qt by Nokia
parent ea783ff51f
commit d394ca7f27
14 changed files with 674 additions and 139 deletions

View File

@ -246,27 +246,27 @@ const TInputType &myMin(const TInputType &value1, const TInputType &value2)
#include <stdio.h>
#include <stdlib.h>
void myMessageOutput(QtMsgType type, const char *msg)
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const char *msg)
{
switch (type) {
case QtDebugMsg:
fprintf(stderr, "Debug: %s\n", msg);
fprintf(stderr, "Debug: %s (%s:%u, %s)\n", msg, context.file, context.line, context.function);
break;
case QtWarningMsg:
fprintf(stderr, "Warning: %s\n", msg);
fprintf(stderr, "Warning: %s (%s:%u, %s)\n", msg, context.file, context.line, context.function);
break;
case QtCriticalMsg:
fprintf(stderr, "Critical: %s\n", msg);
fprintf(stderr, "Critical: %s (%s:%u, %s)\n", msg, context.file, context.line, context.function);
break;
case QtFatalMsg:
fprintf(stderr, "Fatal: %s\n", msg);
fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", msg, context.file, context.line, context.function);
abort();
}
}
int main(int argc, char **argv)
{
qInstallMsgHandler(myMessageOutput);
qInstallMessageHandler(myMessageOutput);
QApplication app(argc, argv);
...
return app.exec();
@ -532,6 +532,11 @@ class MyClass : public QObject
CApaApplication *myApplicationFactory();
//! [47]
//! [49]
void myMessageHandler(QtMsgType, const QMessageLogContext &, const char *);
//! [49]
//! [qlikely]
// the condition inside the "if" will be successful most of the times
for (int i = 1; i <= 365; i++) {

View File

@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtGui>
#include <QtDebug>
#include <QDeclarativeComponent>
//! [1]
void statusChanged(QDeclarativeComponent::Status status) {
if (status == QDeclarativeComponent::Error) {
foreach (const QDeclarativeError &error, component->errors()) {
const QByteArray file = error.url().toEncoded();
QMessageLogger(file.constData(), error.line(), 0).debug() << error.description();
}
}
}
//! [1]

View File

@ -5,13 +5,15 @@ HEADERS += \
global/qnamespace.h \
global/qendian.h \
global/qnumeric_p.h \
global/qnumeric.h
global/qnumeric.h \
global/qlogging.h
SOURCES += \
global/qglobal.cpp \
global/qlibraryinfo.cpp \
global/qmalloc.cpp \
global/qnumeric.cpp
global/qnumeric.cpp \
global/qlogging.cpp
# qlibraryinfo.cpp includes qconfig.cpp
INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global

View File

@ -47,6 +47,7 @@
#include "qdir.h"
#include "qstringlist.h"
#include "qdatetime.h"
#include "qdebug.h"
#ifndef QT_NO_QOBJECT
#include <private/qthread_p.h>
@ -442,8 +443,12 @@ QT_BEGIN_NAMESPACE
Finally, the QtMsgType definition identifies the various messages
that can be generated and sent to a Qt message handler;
QtMsgHandler is a type definition for a pointer to a function with
the signature \c {void myMsgHandler(QtMsgType, const char *)}.
QMessageHandler is a type definition for a pointer to a function with
the signature
\c {void myMessageHandler(QtMsgType, const QMessageLogContext &, const char *)}.
QMessageLogContext class contains the line, file, and function the
message was logged at. This information is created by the QMessageLogger
class.
\section1 Functions
@ -473,8 +478,8 @@ QT_BEGIN_NAMESPACE
The remaining functions are qRound() and qRound64(), which both
accept a \l qreal value as their argument returning the value
rounded up to the nearest integer and 64-bit integer respectively,
the qInstallMsgHandler() function which installs the given
QtMsgHandler, and the qVersion() function which returns the
the qInstallMessageHandler() function which installs the given
QMessageHandler, and the qVersion() function which returns the
version number of Qt at run-time as a string.
\section1 Macros
@ -675,15 +680,31 @@ QT_BEGIN_NAMESPACE
/*!
\typedef QtMsgHandler
\relates <QtGlobal>
\deprecated
This is a typedef for a pointer to a function with the following
signature:
\snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 7
\sa QtMsgType, qInstallMsgHandler()
This typedef is deprecated, you should use QMessageHandler instead.
\sa QtMsgType, QMessageHandler, qInstallMsgHandler(), qInstallMessageHandler()
*/
/*!
\typedef QMessageHandler
\relates <QtGlobal>
\since 5.0
This is a typedef for a pointer to a function with the following
signature:
\snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 49
\sa QtMsgType, qInstallMessageHandler()
*/
/*!
\enum QtMsgType
\relates <QtGlobal>
@ -704,7 +725,7 @@ QT_BEGIN_NAMESPACE
\value QtSystemMsg
\sa QtMsgHandler, qInstallMsgHandler()
\sa QMessageHandler, qInstallMessageHandler()
*/
/*! \typedef QFunctionPointer
@ -1705,7 +1726,8 @@ Q_CORE_EXPORT unsigned int qt_int_sqrt(unsigned int n)
void *qMemCopy(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); }
void *qMemSet(void *dest, int c, size_t n) { return memset(dest, c, n); }
static QtMsgHandler handler = 0; // pointer to debug handler
static QtMsgHandler msgHandler = 0; // pointer to debug handler (without context)
static QMessageHandler messageHandler = 0; // pointer to debug handler (with context)
#if !defined(Q_OS_WIN) && !defined(QT_NO_THREAD) && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX) && \
defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L
@ -1786,10 +1808,22 @@ QString qt_error_string(int errorCode)
return ret.trimmed();
}
/*!
\fn QtMsgHandler qInstallMsgHandler(QtMsgHandler handler)
\relates <QtGlobal>
\deprecated
Installs a Qt message \a handler which has been defined
previously. This method is deprecated, use qInstallMessageHandler
instead.
\sa QtMsgHandler, qInstallMessageHandler
*/
/*!
\fn QMessageHandler qInstallMessageHandler(QMessageHandler handler)
\relates <QtGlobal>
\since 5.0
Installs a Qt message \a handler which has been defined
previously. Returns a pointer to the previous message handler
@ -1811,7 +1845,7 @@ QString qt_error_string(int errorCode)
Only one message handler can be defined, since this is usually
done on an application-wide basis to control debug output.
To restore the message handler, call \c qInstallMsgHandler(0).
To restore the message handler, call \c qInstallMessageHandler(0).
Example:
@ -1820,9 +1854,12 @@ QString qt_error_string(int errorCode)
\sa qDebug(), qWarning(), qCritical(), qFatal(), QtMsgType,
{Debugging Techniques}
*/
#if defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB)
extern bool usingWinMain;
extern Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char* str);
extern Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char *str);
extern Q_CORE_EXPORT void qWinMessageHandler(QtMsgType t, const QMessageLogContext &context,
const char *str);
#endif
/*!
@ -1840,17 +1877,38 @@ static void qDefaultMsgHandler(QtMsgType, const char *buf)
#endif
}
/*!
\internal
*/
static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &, const char *buf)
{
qDefaultMsgHandler(type, buf);
}
QMessageHandler qInstallMessageHandler(QMessageHandler h)
{
if (!messageHandler)
messageHandler = qDefaultMessageHandler;
QMessageHandler old = messageHandler;
messageHandler = h;
#if defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB)
if (!messageHandler && usingWinMain)
messageHandler = qWinMessageHandler;
#endif
return old;
}
QtMsgHandler qInstallMsgHandler(QtMsgHandler h)
{
//if handler is 0, set it to the
//default message handler
if (!handler)
handler = qDefaultMsgHandler;
QtMsgHandler old = handler;
handler = h;
if (!msgHandler)
msgHandler = qDefaultMsgHandler;
QtMsgHandler old = msgHandler;
msgHandler = h;
#if defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB)
if (!handler && usingWinMain)
handler = qWinMsgHandler;
if (!msgHandler && usingWinMain)
msgHandler = qWinMsgHandler;
#endif
return old;
}
@ -1858,11 +1916,20 @@ QtMsgHandler qInstallMsgHandler(QtMsgHandler h)
/*!
\internal
*/
void qt_message_output(QtMsgType msgType, const char *buf)
void qt_message_output(QtMsgType msgType, const QMessageLogContext &context, const char *buf)
{
if (!handler)
handler = qDefaultMsgHandler;
(*handler)(msgType, buf);
if (!msgHandler)
msgHandler = qDefaultMsgHandler;
if (!messageHandler)
messageHandler = qDefaultMessageHandler;
// prefer new message handler over the old one
if (msgHandler == qDefaultMsgHandler
|| messageHandler != qDefaultMessageHandler) {
(*messageHandler)(msgType, context, buf);
} else {
(*msgHandler)(msgType, buf);
}
if (msgType == QtFatalMsg
|| (msgType == QtWarningMsg
@ -1904,14 +1971,15 @@ static void qEmergencyOut(QtMsgType msgType, const char *msg, va_list ap)
emergency_buf[255] = '\0';
if (msg)
qvsnprintf(emergency_buf, 255, msg, ap);
qt_message_output(msgType, emergency_buf);
QMessageLogContext context;
qt_message_output(msgType, context, emergency_buf);
}
#endif
/*!
\internal
*/
static void qt_message(QtMsgType msgType, const char *msg, va_list ap)
static void qt_message(QtMsgType msgType, const QMessageLogContext &context, const char *msg, va_list ap)
{
#if !defined(QT_NO_EXCEPTIONS)
if (std::uncaught_exception()) {
@ -1931,11 +1999,12 @@ static void qt_message(QtMsgType msgType, const char *msg, va_list ap)
#endif
}
}
qt_message_output(msgType, buf.constData());
qt_message_output(msgType, context, buf.constData());
}
#undef qDebug
/*!
\fn qDebug(const char *message, ...)
\relates <QtGlobal>
Calls the message handler with the debug message \a msg. If no
@ -1964,21 +2033,42 @@ static void qt_message(QtMsgType msgType, const char *msg, va_list ap)
the end. It supports many C++ and Qt types.
To suppress the output at run-time, install your own message handler
with qInstallMsgHandler().
with qInstallMessageHandler().
\sa qWarning(), qCritical(), qFatal(), qInstallMsgHandler(),
\sa qWarning(), qCritical(), qFatal(), qInstallMessageHandler(),
{Debugging Techniques}
*/
void qDebug(const char *msg, ...)
void QMessageLogger::debug(const char *msg, ...)
{
va_list ap;
va_start(ap, msg); // use variable arg list
qt_message(QtDebugMsg, msg, ap);
qt_message(QtDebugMsg, context, msg, ap);
va_end(ap);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug QMessageLogger::debug()
{
QDebug dbg = QDebug(QtDebugMsg);
QMessageLogContext &ctxt = dbg.stream->context;
ctxt.file = context.file;
ctxt.line = context.line;
ctxt.function = context.function;
return dbg;
}
QNoDebug QMessageLogger::noDebug()
{
return QNoDebug();
}
#endif
#undef qWarning
/*!
\fn qWarning(const char *message, ...)
\relates <QtGlobal>
Calls the message handler with the warning message \a msg. If no
@ -2004,20 +2094,35 @@ void qDebug(const char *msg, ...)
appends a newline at the end.
To suppress the output at runtime, install your own message handler
with qInstallMsgHandler().
with qInstallMessageHandler().
\sa qDebug(), qCritical(), qFatal(), qInstallMsgHandler(),
\sa qDebug(), qCritical(), qFatal(), qInstallMessageHandler(),
{Debugging Techniques}
*/
void qWarning(const char *msg, ...)
void QMessageLogger::warning(const char *msg, ...)
{
va_list ap;
va_start(ap, msg); // use variable arg list
qt_message(QtWarningMsg, msg, ap);
qt_message(QtWarningMsg, context, msg, ap);
va_end(ap);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug QMessageLogger::warning()
{
QDebug dbg = QDebug(QtWarningMsg);
QMessageLogContext &ctxt = dbg.stream->context;
ctxt.file = context.file;
ctxt.line = context.line;
ctxt.function = context.function;
return dbg;
}
#endif
#undef qCritical
/*!
\fn qCritical(const char *message, ...)
\relates <QtGlobal>
Calls the message handler with the critical message \a msg. If no
@ -2040,19 +2145,32 @@ void qWarning(const char *msg, ...)
appended at the end.
To suppress the output at runtime, install your own message handler
with qInstallMsgHandler().
with qInstallMessageHandler().
\sa qDebug(), qWarning(), qFatal(), qInstallMsgHandler(),
\sa qDebug(), qWarning(), qFatal(), qInstallMessageHandler(),
{Debugging Techniques}
*/
void qCritical(const char *msg, ...)
void QMessageLogger::critical(const char *msg, ...)
{
va_list ap;
va_start(ap, msg); // use variable arg list
qt_message(QtCriticalMsg, msg, ap);
qt_message(QtCriticalMsg, context, msg, ap);
va_end(ap);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug QMessageLogger::critical()
{
QDebug dbg = QDebug(QtCriticalMsg);
QMessageLogContext &ctxt = dbg.stream->context;
ctxt.file = context.file;
ctxt.line = context.line;
ctxt.function = context.function;
return dbg;
}
#endif
void qErrnoWarning(const char *msg, ...)
{
// qt_error_string() will allocate anyway, so we don't have
@ -2064,7 +2182,8 @@ void qErrnoWarning(const char *msg, ...)
buf.vsprintf(msg, ap);
va_end(ap);
qCritical("%s (%s)", buf.toLocal8Bit().constData(), qt_error_string(-1).toLocal8Bit().constData());
QMessageLogger().critical("%s (%s)", buf.toLocal8Bit().constData(),
qt_error_string(-1).toLocal8Bit().constData());
}
void qErrnoWarning(int code, const char *msg, ...)
@ -2078,10 +2197,13 @@ void qErrnoWarning(int code, const char *msg, ...)
buf.vsprintf(msg, ap);
va_end(ap);
qCritical("%s (%s)", buf.toLocal8Bit().constData(), qt_error_string(code).toLocal8Bit().constData());
QMessageLogger().critical("%s (%s)", buf.toLocal8Bit().constData(),
qt_error_string(code).toLocal8Bit().constData());
}
#undef qFatal
/*!
\fn qFatal(const char *message, ...)
\relates <QtGlobal>
Calls the message handler with the fatal message \a msg. If no
@ -2100,16 +2222,17 @@ void qErrnoWarning(int code, const char *msg, ...)
\snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 30
To suppress the output at runtime, install your own message handler
with qInstallMsgHandler().
with qInstallMessageHandler().
\sa qDebug(), qCritical(), qWarning(), qInstallMsgHandler(),
\sa qDebug(), qCritical(), qWarning(), qInstallMessageHandler(),
{Debugging Techniques}
*/
void qFatal(const char *msg, ...)
void QMessageLogger::fatal(const char *msg, ...)
{
va_list ap;
va_start(ap, msg); // use variable arg list
qt_message(QtFatalMsg, msg, ap);
qt_message(QtFatalMsg, context, msg, ap);
va_end(ap);
}

View File

@ -1637,65 +1637,12 @@ inline void qUnused(T &x) { (void)x; }
# define qPrintable(string) QString(string).toLocal8Bit().constData()
#endif
Q_CORE_EXPORT void qDebug(const char *, ...) /* print debug message */
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 1, 2)))
#endif
;
Q_CORE_EXPORT void qWarning(const char *, ...) /* print warning message */
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 1, 2)))
#endif
;
class QString;
Q_CORE_EXPORT QString qt_error_string(int errorCode = -1);
Q_CORE_EXPORT void qCritical(const char *, ...) /* print critical message */
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 1, 2)))
#endif
;
Q_CORE_EXPORT void qFatal(const char *, ...) /* print fatal message and exit */
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 1, 2)))
#endif
;
Q_CORE_EXPORT void qErrnoWarning(int code, const char *msg, ...);
Q_CORE_EXPORT void qErrnoWarning(const char *msg, ...);
/*
Forward declarations only.
In order to use the qDebug() stream, you must #include<QDebug>
*/
class QDebug;
class QNoDebug;
#if !defined(QT_NO_DEBUG_OUTPUT) && !defined(QT_NO_DEBUG_STREAM)
Q_CORE_EXPORT_INLINE QDebug qDebug();
#else
inline QNoDebug qDebug();
#endif
#if !defined(QT_NO_WARNING_OUTPUT) && !defined(QT_NO_DEBUG_STREAM)
Q_CORE_EXPORT_INLINE QDebug qWarning();
#else
inline QNoDebug qWarning();
#endif
#if !defined(QT_NO_DEBUG_STREAM)
Q_CORE_EXPORT_INLINE QDebug qCritical();
#endif
#define QT_NO_QDEBUG_MACRO while (false) qDebug
#ifdef QT_NO_DEBUG_OUTPUT
# define qDebug QT_NO_QDEBUG_MACRO
#endif
#define QT_NO_QWARNING_MACRO while (false) qWarning
#ifdef QT_NO_WARNING_OUTPUT
# define qWarning QT_NO_QWARNING_MACRO
#endif
Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line);
#if !defined(Q_ASSERT)
@ -1774,12 +1721,6 @@ inline T *q_check_ptr(T *p) { Q_CHECK_PTR(p); return p; }
# endif
#endif
enum QtMsgType { QtDebugMsg, QtWarningMsg, QtCriticalMsg, QtFatalMsg, QtSystemMsg = QtCriticalMsg };
Q_CORE_EXPORT void qt_message_output(QtMsgType, const char *buf);
typedef void (*QtMsgHandler)(QtMsgType, const char *);
Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler);
typedef void (*QFunctionPointer)();
@ -2499,6 +2440,9 @@ template <typename T> struct QEnableIf<true, T> { typedef T Type; };
QT_END_NAMESPACE
QT_END_HEADER
// qDebug and friends
#include "qlogging.h"
#endif /* __cplusplus */
#endif /* QGLOBAL_H */

View File

@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qlogging.h>
QT_BEGIN_NAMESPACE
/*!
\class QMessageLogContext
\relates <QtGlobal>
\brief The QMessageLogContext class provides additional information about a log message.
\since 5.0
The class provides information about the source code location a qDebug(), qWarning(),
qCritical() or qFatal() message was generated.
\sa QMessageLogger, QMessageHandler, qInstallMessageHandler()
*/
/*!
\class QMessageLogger
\relates <QtGlobal>
\brief The QMessageLogger class generates log messages.
\since 5.0
QMessageLogger is used to generate messages for the Qt logging framework. Most of the time
is transparently used through the qDebug(), qWarning(), qCritical, or qFatal() functions,
which are actually macros that expand to QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug()
et al.
One example of direct use is to forward errors that stem from a scripting language, e.g. QML:
\snippet doc/src/snippets/code/qlogging/qlogging.cpp 1
\sa QMessageLogContext, qDebug(), qWarning(), qCritical(), qFatal()
*/
QT_END_NAMESPACE

View File

@ -0,0 +1,161 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtCore/qglobal.h>
#ifndef QLOGGING_H
#define QLOGGING_H
#if 0
// header is automatically included in qglobal.h
#pragma qt_no_master_include
#endif
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
/*
Forward declarations only.
In order to use the qDebug() stream, you must #include<QDebug>
*/
class QDebug;
class QNoDebug;
enum QtMsgType { QtDebugMsg, QtWarningMsg, QtCriticalMsg, QtFatalMsg, QtSystemMsg = QtCriticalMsg };
class QMessageLogContext
{
Q_DISABLE_COPY(QMessageLogContext)
public:
QMessageLogContext() : version(1), line(0), file(0), function(0) {}
Q_DECL_CONSTEXPR QMessageLogContext(const char *file, int line, const char *function)
: version(1), line(line), file(file), function(function) {}
int version;
int line;
const char *file;
const char *function;
private:
friend class QMessageLogger;
friend class QDebug;
};
class Q_CORE_EXPORT QMessageLogger
{
Q_DISABLE_COPY(QMessageLogger)
public:
QMessageLogger() : context() {}
Q_DECL_CONSTEXPR QMessageLogger(const char *file, int line, const char *function)
: context(file, line, function) {}
void debug(const char *msg, ...)
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 2, 3)))
#endif
;
void noDebug(const char *, ...)
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 2, 3)))
#endif
{}
void warning(const char *msg, ...)
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 2, 3)))
#endif
;
void critical(const char *msg, ...)
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 2, 3)))
#endif
;
void fatal(const char *msg, ...)
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 2, 3)))
#endif
;
#ifndef QT_NO_DEBUG_STREAM
QDebug debug();
QDebug warning();
QDebug critical();
QNoDebug noDebug();
#endif // QT_NO_DEBUG_STREAM
private:
QMessageLogContext context;
};
Q_CORE_EXPORT void qt_message_output(QtMsgType, const QMessageLogContext &context, const char *buf);
/*
qDebug, qWarning, qCritical, qFatal are redefined to automatically include context information
*/
#define qDebug QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug
#define qWarning QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning
#define qCritical QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical
#define qFatal QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).fatal
#define QT_NO_QDEBUG_MACRO while (false) QMessageLogger().noDebug
#define QT_NO_QWARNING_MACRO while (false) QMessageLogger().noDebug
#ifdef QT_NO_DEBUG_OUTPUT
# undef qDebug
# define qDebug QT_NO_QDEBUG_MACRO
#endif
#ifdef QT_NO_WARNING_OUTPUT
# undef qWarning
# define qWarning QT_NO_QWARNING_MACRO
#endif
// deprecated. Use qInstallMessageHandler instead!
typedef void (*QtMsgHandler)(QtMsgType, const char *);
Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler);
typedef void (*QMessageHandler)(QtMsgType, const QMessageLogContext &, const char *);
Q_CORE_EXPORT QMessageHandler qInstallMessageHandler(QMessageHandler);
QT_END_HEADER
QT_END_NAMESPACE
#endif // QLOGGING_H

View File

@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QDebug
{
friend class QMessageLogger;
struct Stream {
Stream(QIODevice *device) : ts(device), ref(1), type(QtDebugMsg), space(true), message_output(false) {}
Stream(QString *string) : ts(string, QIODevice::WriteOnly), ref(1), type(QtDebugMsg), space(true), message_output(false) {}
@ -70,6 +71,7 @@ class Q_CORE_EXPORT QDebug
QtMsgType type;
bool space;
bool message_output;
QMessageLogContext context;
} *stream;
public:
inline QDebug(QIODevice *device) : stream(new Stream(device)) {}
@ -81,7 +83,9 @@ public:
if (!--stream->ref) {
if(stream->message_output) {
QT_TRY {
qt_message_output(stream->type, stream->buffer.toLocal8Bit().data());
qt_message_output(stream->type,
stream->context,
stream->buffer.toLocal8Bit().data());
} QT_CATCH(std::bad_alloc&) { /* We're out of memory - give up. */ }
}
delete stream;
@ -269,27 +273,6 @@ inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
return debug.space();
}
#if !defined(QT_NO_DEBUG_OUTPUT) && !defined(QT_NO_DEBUG_STREAM)
Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); }
#else
#undef qDebug
inline QNoDebug qDebug() { return QNoDebug(); }
#define qDebug QT_NO_QDEBUG_MACRO
#endif
#if !defined(QT_NO_WARNING_OUTPUT) && !defined(QT_NO_DEBUG_STREAM)
Q_CORE_EXPORT_INLINE QDebug qWarning() { return QDebug(QtWarningMsg); }
#else
#undef qWarning
inline QNoDebug qWarning() { return QNoDebug(); }
#define qWarning QT_NO_QWARNING_MACRO
#endif
#if !defined(QT_NO_DEBUG_STREAM)
Q_CORE_EXPORT_INLINE QDebug qCritical() { return QDebug(QtCriticalMsg); }
#endif
QT_END_NAMESPACE
QT_END_HEADER

View File

@ -161,6 +161,10 @@ Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char* str)
staticCriticalSection.unlock();
}
Q_CORE_EXPORT void qWinMessageHandler(QtMsgType t, const QMessageLogContext &, const char* str)
{
qWinMsgHandler(t, str);
}
/*****************************************************************************
qWinMain() - Initializes Windows. Called from WinMain() in qtmain_win.cpp

View File

@ -51,6 +51,7 @@ SOURCES += \
../../corelib/codecs/qtextcodec.cpp \
../../corelib/codecs/qutfcodec.cpp \
../../corelib/global/qglobal.cpp \
../../corelib/global/qlogging.cpp \
../../corelib/global/qmalloc.cpp \
../../corelib/global/qnumeric.cpp \
../../corelib/io/qabstractfileengine.cpp \

View File

@ -5,4 +5,5 @@ SUBDIRS=\
qgetputenv \
qglobal \
qnumeric \
qrand
qrand \
qmessagehandler

View File

@ -0,0 +1,4 @@
CONFIG += testcase parallel_test
TARGET = tst_qmessagehandler
QT = core testlib
SOURCES = tst_qmessagehandler.cpp

View File

@ -0,0 +1,147 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qdebug.h>
#include <QtTest/QtTest>
#include <qglobal.h>
class tst_qmessagehandler : public QObject
{
Q_OBJECT
private slots:
void cleanup();
void defaultHandler();
void installMessageHandler();
void installMsgHandler();
void installBothHandler();
};
static QtMsgType s_type;
const char *s_file;
int s_line;
const char *s_function;
static QString s_message;
void customMessageHandler(QtMsgType type, const QMessageLogContext &context, const char *msg)
{
s_type = type;
s_file = context.file;
s_line = context.line;
s_function = context.function;
s_message = QString::fromLocal8Bit(msg);
}
void customMsgHandler(QtMsgType type, const char *msg)
{
s_type = type;
s_file = 0;
s_line = 0;
s_function = 0;
s_message = QString::fromLocal8Bit(msg);
}
void tst_qmessagehandler::cleanup()
{
qInstallMsgHandler(0);
qInstallMessageHandler(0);
s_type = QtFatalMsg;
s_file = 0;
s_line = 0;
s_function = 0;
}
void tst_qmessagehandler::defaultHandler()
{
// check that the default works
QTest::ignoreMessage(QtDebugMsg, "defaultHandler");
qDebug("defaultHandler");
}
void tst_qmessagehandler::installMessageHandler()
{
QMessageHandler oldHandler = qInstallMessageHandler(customMessageHandler);
qDebug("installMessageHandler"); int line = __LINE__;
QCOMPARE(s_type, QtDebugMsg);
QCOMPARE(s_message, QString::fromLocal8Bit("installMessageHandler"));
QCOMPARE(s_file, __FILE__);
QCOMPARE(s_function, Q_FUNC_INFO);
QCOMPARE(s_line, line);
QMessageHandler myHandler = qInstallMessageHandler(oldHandler);
QCOMPARE((void*)myHandler, (void*)customMessageHandler);
}
void tst_qmessagehandler::installMsgHandler()
{
QtMsgHandler oldHandler = qInstallMsgHandler(customMsgHandler);
qDebug("installMsgHandler");
QCOMPARE(s_type, QtDebugMsg);
QCOMPARE(s_message, QString::fromLocal8Bit("installMsgHandler"));
QCOMPARE(s_file, (const char*)0);
QCOMPARE(s_function, (const char*)0);
QCOMPARE(s_line, 0);
QtMsgHandler myHandler = qInstallMsgHandler(oldHandler);
QCOMPARE((void*)myHandler, (void*)customMsgHandler);
}
void tst_qmessagehandler::installBothHandler()
{
qInstallMessageHandler(customMessageHandler);
qInstallMsgHandler(customMsgHandler);
qDebug("installBothHandler"); int line = __LINE__;
QCOMPARE(s_type, QtDebugMsg);
QCOMPARE(s_message, QString::fromLocal8Bit("installBothHandler"));
QCOMPARE(s_file, __FILE__);
QCOMPARE(s_function, Q_FUNC_INFO);
QCOMPARE(s_line, line);
}
QTEST_MAIN(tst_qmessagehandler)
#include "tst_qmessagehandler.moc"

View File

@ -74,11 +74,17 @@ void tst_QDebug::assignment() const
static QtMsgType s_msgType;
static QByteArray s_msg;
static QByteArray s_file;
static int s_line;
static QByteArray s_function;
static void myMessageHandler(QtMsgType type, const char *msg)
static void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const char *msg)
{
s_msg = msg;
s_msgType = type;
s_file = context.file;
s_line = context.line;
s_function = context.function;
}
// Helper class to ensure that the testlib message handler gets
@ -87,17 +93,17 @@ static void myMessageHandler(QtMsgType type, const char *msg)
class MessageHandlerSetter
{
public:
MessageHandlerSetter(QtMsgHandler newMsgHandler)
: oldMsgHandler(qInstallMsgHandler(newMsgHandler))
MessageHandlerSetter(QMessageHandler newMessageHandler)
: oldMessageHandler(qInstallMessageHandler(newMessageHandler))
{ }
~MessageHandlerSetter()
{
qInstallMsgHandler(oldMsgHandler);
qInstallMessageHandler(oldMessageHandler);
}
private:
QtMsgHandler oldMsgHandler;
QMessageHandler oldMessageHandler;
};
/*! \internal
@ -107,8 +113,12 @@ void tst_QDebug::warningWithoutDebug() const
{
MessageHandlerSetter mhs(myMessageHandler);
{ qWarning() << "A qWarning() message"; }
QString file = __FILE__; int line = __LINE__ - 1; QString function = Q_FUNC_INFO;
QCOMPARE(s_msgType, QtWarningMsg);
QCOMPARE(QString::fromLatin1(s_msg.data()), QString::fromLatin1("A qWarning() message "));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
}
/*! \internal
@ -118,16 +128,24 @@ void tst_QDebug::criticalWithoutDebug() const
{
MessageHandlerSetter mhs(myMessageHandler);
{ qCritical() << "A qCritical() message"; }
QString file = __FILE__; int line = __LINE__ - 1; QString function = Q_FUNC_INFO;
QCOMPARE(s_msgType, QtCriticalMsg);
QCOMPARE(QString::fromLatin1(s_msg), QString::fromLatin1("A qCritical() message "));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
}
void tst_QDebug::debugWithBool() const
{
MessageHandlerSetter mhs(myMessageHandler);
{ qDebug() << false << true; }
QString file = __FILE__; int line = __LINE__ - 1; QString function = Q_FUNC_INFO;
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(QString::fromLatin1(s_msg), QString::fromLatin1("false true "));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
}
void tst_QDebug::veryLongWarningMessage() const
@ -140,8 +158,12 @@ void tst_QDebug::veryLongWarningMessage() const
test.append(part);
qWarning("Test output:\n%s\nend", qPrintable(test));
}
QString file = __FILE__; int line = __LINE__ - 2; QString function = Q_FUNC_INFO;
QCOMPARE(s_msgType, QtWarningMsg);
QCOMPARE(QString::fromLatin1(s_msg), QString::fromLatin1("Test output:\n")+test+QString::fromLatin1("\nend"));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
}
void tst_QDebug::qDebugQStringRef() const
@ -153,8 +175,12 @@ void tst_QDebug::qDebugQStringRef() const
MessageHandlerSetter mhs(myMessageHandler);
{ qDebug() << inRef; }
QString file = __FILE__; int line = __LINE__ - 1; QString function = Q_FUNC_INFO;
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(QString::fromLatin1(s_msg), QString::fromLatin1("\"input\" "));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
}
/* Use a null QStringRef. */
@ -163,19 +189,23 @@ void tst_QDebug::qDebugQStringRef() const
MessageHandlerSetter mhs(myMessageHandler);
{ qDebug() << inRef; }
QString file = __FILE__; int line = __LINE__ - 1; QString function = Q_FUNC_INFO;
QCOMPARE(s_msgType, QtDebugMsg);
QCOMPARE(QString::fromLatin1(s_msg), QString::fromLatin1("\"\" "));
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
}
}
void tst_QDebug::defaultMessagehandler() const
{
MessageHandlerSetter mhs(0);
QtMsgHandler defaultMessageHandler1 = qInstallMsgHandler(0);
QtMsgHandler defaultMessageHandler2 = qInstallMsgHandler(myMessageHandler);
QMessageHandler defaultMessageHandler1 = qInstallMessageHandler(0);
QMessageHandler defaultMessageHandler2 = qInstallMessageHandler(myMessageHandler);
bool same = (*defaultMessageHandler1 == *defaultMessageHandler2);
QVERIFY(same);
QtMsgHandler messageHandler = qInstallMsgHandler(0);
QMessageHandler messageHandler = qInstallMessageHandler(0);
same = (*messageHandler == *myMessageHandler);
QVERIFY(same);
}