summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qglobal.cpp33
-rw-r--r--src/corelib/global/qlogging.cpp64
-rw-r--r--src/corelib/global/qlogging.h2
-rw-r--r--tests/auto/corelib/global/qlogging/app/main.cpp7
-rw-r--r--tests/auto/corelib/global/qlogging/tst_qlogging.cpp38
5 files changed, 127 insertions, 17 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 7036b72f08..38ddd7bf97 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -3088,5 +3088,38 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
instead.
\sa QtMsgHandler, qInstallMessageHandler
*/
+/*!
+ \fn void qSetMessagePattern(const QString &pattern)
+ \relates <QtGlobal>
+ \since 5.0
+
+ \brief Changes the output of the default message handler.
+
+ Allows to tweak the output of qDebug(), qWarning(), qCritical() and qFatal().
+
+ Following placeholders are supported:
+
+ \table
+ \header \li Placeholder \li Description
+ \row \li \c %{appname} \li QCoreApplication::applicationName()
+ \row \li \c %{file} \li Path to source file
+ \row \li \c %{function} \li Function
+ \row \li \c %{line} \li Line in source file
+ \row \li \c %{message} \li The actual message
+ \row \li \c %{pid} \li QCoreApplication::applicationPid()
+ \row \li \c %{threadid} \li ID of current thread
+ \row \li \c %{type} \li "debug", "warning", "critical" or "fatal"
+ \endtable
+
+ The default pattern is "%{message}".
+
+ The pattern can also be changed at runtime by setting the QT_MESSAGE_PATTERN
+ environment variable; if both qSetMessagePattern() is called and QT_MESSAGE_PATTERN is
+ set, the environment variable takes precedence.
+
+ qSetMessagePattern() has no effect if a custom message handler is installed.
+
+ \sa qInstallMessageHandler, Debugging Techniques
+ */
QT_END_NAMESPACE
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index 1f5b121143..8726c18689 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -45,6 +45,7 @@
#include "qstring.h"
#include "qvarlengtharray.h"
#include "qdebug.h"
+#include "qmutex.h"
#ifndef QT_BOOTSTRAPPED
#include "qcoreapplication.h"
#include "qthread.h"
@@ -400,21 +401,53 @@ static const char appnameTokenC[] = "%{appname}";
static const char threadidTokenC[] = "%{threadid}";
static const char emptyTokenC[] = "";
+static const char defaultPattern[] = "%{message}";
+
+
struct QMessagePattern {
QMessagePattern();
~QMessagePattern();
+ void setPattern(const QString &pattern);
+
// 0 terminated arrays of literal tokens / literal or placeholder tokens
const char **literals;
const char **tokens;
+
+ bool fromEnvironment;
+ static QBasicMutex mutex;
};
+QBasicMutex QMessagePattern::mutex;
+
QMessagePattern::QMessagePattern()
+ : literals(0)
+ , tokens(0)
+ , fromEnvironment(false)
{
- QString pattern = QString::fromLocal8Bit(qgetenv("QT_MESSAGE_PATTERN"));
- if (pattern.isEmpty()) {
- pattern = QLatin1String("%{message}");
+ const QString envPattern = QString::fromLocal8Bit(qgetenv("QT_MESSAGE_PATTERN"));
+ if (envPattern.isEmpty()) {
+ setPattern(QLatin1String(defaultPattern));
+ } else {
+ setPattern(envPattern);
+ fromEnvironment = true;
}
+}
+
+QMessagePattern::~QMessagePattern()
+{
+ for (int i = 0; literals[i] != 0; ++i)
+ delete [] literals[i];
+ delete [] literals;
+ literals = 0;
+ delete [] tokens;
+ tokens = 0;
+}
+
+void QMessagePattern::setPattern(const QString &pattern)
+{
+ delete [] tokens;
+ delete [] literals;
// scanner
QList<QString> lexemes;
@@ -495,16 +528,6 @@ QMessagePattern::QMessagePattern()
memcpy(literals, literalsVar.constData(), literalsVar.size() * sizeof(const char*));
}
-QMessagePattern::~QMessagePattern()
-{
- for (int i = 0; literals[i] != 0; ++i)
- delete [] literals[i];
- delete [] literals;
- literals = 0;
- delete [] tokens;
- tokens = 0;
-}
-
Q_GLOBAL_STATIC(QMessagePattern, qMessagePattern)
/*!
@@ -515,6 +538,8 @@ Q_CORE_EXPORT QString qMessageFormatString(QtMsgType type, const QMessageLogCont
{
QString message;
+ QMutexLocker lock(&QMessagePattern::mutex);
+
QMessagePattern *pattern = qMessagePattern();
if (!pattern) {
// after destruction of static QMessagePattern instance
@@ -523,6 +548,10 @@ Q_CORE_EXPORT QString qMessageFormatString(QtMsgType type, const QMessageLogCont
return message;
}
+ // don't print anything if pattern was empty
+ if (pattern->tokens[0] == 0)
+ return message;
+
// we do not convert file, function, line literals to local encoding due to overhead
for (int i = 0; pattern->tokens[i] != 0; ++i) {
const char *token = pattern->tokens[i];
@@ -741,6 +770,14 @@ QtMsgHandler qInstallMsgHandler(QtMsgHandler h)
return old;
}
+void qSetMessagePattern(const QString &pattern)
+{
+ QMutexLocker lock(&QMessagePattern::mutex);
+
+ if (!qMessagePattern()->fromEnvironment)
+ qMessagePattern()->setPattern(pattern);
+}
+
void QMessageLogContext::copy(const QMessageLogContext &logContext)
{
this->category = logContext.category;
@@ -748,4 +785,5 @@ void QMessageLogContext::copy(const QMessageLogContext &logContext)
this->line = logContext.line;
this->function = logContext.function;
}
+
QT_END_NAMESPACE
diff --git a/src/corelib/global/qlogging.h b/src/corelib/global/qlogging.h
index 216b847952..ae388b0a38 100644
--- a/src/corelib/global/qlogging.h
+++ b/src/corelib/global/qlogging.h
@@ -168,6 +168,8 @@ Q_CORE_EXPORT QtMessageHandler qInstallMessageHandler(QtMessageHandler);
typedef void (*QMessageHandler)(QtMsgType, const QMessageLogContext &, const char *);
Q_CORE_EXPORT QMessageHandler qInstallMessageHandler(QMessageHandler);
+Q_CORE_EXPORT void qSetMessagePattern(const QString &messagePattern);
+
QT_END_HEADER
QT_END_NAMESPACE
diff --git a/tests/auto/corelib/global/qlogging/app/main.cpp b/tests/auto/corelib/global/qlogging/app/main.cpp
index dfa52315c7..2f5a975e43 100644
--- a/tests/auto/corelib/global/qlogging/app/main.cpp
+++ b/tests/auto/corelib/global/qlogging/app/main.cpp
@@ -51,8 +51,15 @@ int main(int argc, char **argv)
QCoreApplication app(argc, argv);
app.setApplicationName("tst_qlogging");
+ qSetMessagePattern("[%{type}] %{message}");
+
qDebug("qDebug");
qWarning("qWarning");
qCritical("qCritical");
+
+ qSetMessagePattern(QString());
+
+ qDebug("qDebug2");
+
return 0;
}
diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
index 1d6aa89035..5474b9aa3b 100644
--- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
+++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
@@ -630,13 +630,16 @@ void tst_qmessagehandler::cleanupFuncinfo()
void tst_qmessagehandler::qMessagePattern()
{
QProcess process;
+ const QString appExe = m_appDir + "/app";
+ //
+ // test QT_MESSAGE_PATTERN
+ //
QStringList environment = QProcess::systemEnvironment();
// %{file} is tricky because of shadow builds
environment.prepend("QT_MESSAGE_PATTERN=\"%{type} %{appname} %{line} %{function} %{message}\"");
process.setEnvironment(environment);
- QString appExe = m_appDir + "/app";
process.start(appExe);
QVERIFY2(process.waitForStarted(), qPrintable(
QString::fromLatin1("Could not start %1: %2").arg(appExe, process.errorString())));
@@ -649,9 +652,10 @@ void tst_qmessagehandler::qMessagePattern()
QVERIFY(output.contains("debug 45 T::T static constructor"));
// we can't be sure whether the QT_MESSAGE_PATTERN is already destructed
QVERIFY(output.contains("static destructor"));
- QVERIFY(output.contains("debug tst_qlogging 54 main qDebug"));
- QVERIFY(output.contains("warning tst_qlogging 55 main qWarning"));
- QVERIFY(output.contains("critical tst_qlogging 56 main qCritical"));
+ QVERIFY(output.contains("debug tst_qlogging 56 main qDebug"));
+ QVERIFY(output.contains("warning tst_qlogging 57 main qWarning"));
+ QVERIFY(output.contains("critical tst_qlogging 58 main qCritical"));
+ QVERIFY(output.contains("debug tst_qlogging 62 main qDebug2"));
environment = QProcess::systemEnvironment();
environment.prepend("QT_MESSAGE_PATTERN=\"PREFIX: %{unknown} %{message}\"");
@@ -668,6 +672,32 @@ void tst_qmessagehandler::qMessagePattern()
QVERIFY(output.contains("QT_MESSAGE_PATTERN: Unknown placeholder %{unknown}"));
QVERIFY(output.contains("PREFIX: qDebug"));
+
+ //
+ // test qSetMessagePattern
+ //
+ QMutableListIterator<QString> iter(environment);
+ while (iter.hasNext()) {
+ if (iter.next().startsWith("QT_MESSAGE_PATTERN"))
+ iter.remove();
+ }
+ process.setEnvironment(environment);
+
+ process.start(appExe);
+ QVERIFY2(process.waitForStarted(), qPrintable(
+ QString::fromLatin1("Could not start %1: %2").arg(appExe, process.errorString())));
+ process.waitForFinished();
+
+ output = process.readAllStandardError();
+ //qDebug() << output;
+ QByteArray expected = "static constructor\n"
+ "[debug] qDebug\n"
+ "[warning] qWarning\n"
+ "[critical] qCritical\n";
+#ifdef Q_OS_WIN
+ output.replace("\r\n", "\n");
+#endif
+ QCOMPARE(QString::fromLatin1(output), QString::fromLatin1(expected));
}
QTEST_MAIN(tst_qmessagehandler)