From c0d249019b098890fb8e5e9e144c2dd8029a670c Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 13 Apr 2012 13:37:56 +0200 Subject: Allow qDebug output to be configured by qSetMessagePattern() Add qSetMessagePattern() to configure the default message pattern. This one can still be overwritten by setting the QT_MESSAGE_PATTERN environment variable. Without this method, there's actually no way to change the default output programatically. Since QT_MESSAGE_PATTERN is evaluated when the first message arrives, setting it via e.g. qputenv might have no effect/be too late. Change-Id: I115e0c30606f128fdbf5c169a951ffa2a6a48517 Reviewed-by: Thiago Macieira --- src/corelib/global/qglobal.cpp | 33 +++++++++++++++++++++ src/corelib/global/qlogging.cpp | 64 ++++++++++++++++++++++++++++++++--------- src/corelib/global/qlogging.h | 2 ++ 3 files changed, 86 insertions(+), 13 deletions(-) (limited to 'src') 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 + \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 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 -- cgit v1.2.3