21 #define KDE_EXTENDED_DEBUG_OUTPUT
23 #ifndef QT_NO_CAST_FROM_ASCII
24 #define QT_NO_CAST_FROM_ASCII
26 #ifndef QT_NO_CAST_TO_ASCII
27 #define QT_NO_CAST_TO_ASCII
34 #include <QThreadStorage>
54 #ifdef HAVE_SYS_TIME_H
71 #include <QtCore/QFile>
72 #include <QtCore/QHash>
73 #include <QtCore/QObject>
74 #include <QtCore/QChar>
75 #include <QtCore/QCoreApplication>
93 #define HAVE_BACKTRACE (1)
99 #define HAVE_BACKTRACE_DEMANGLE
115 KNoDebugStream() {
open(WriteOnly); }
116 bool isSequential()
const {
return true; }
119 qint64 writeData(
const char *,
qint64 len) {
return len; }
122 class KSyslogDebugStream:
public KNoDebugStream
130 const QByteArray buf(data, len);
131 syslog(m_priority,
"%s", buf.constData());
135 void setPriority(
int priority) { m_priority = priority; }
140 class KFileDebugStream:
public KNoDebugStream
147 QFile aOutputFile(m_fileName);
148 if (aOutputFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered)) {
149 QByteArray buf = QByteArray::fromRawData(data, len);
150 aOutputFile.write(buf.trimmed());
151 aOutputFile.putChar(
'\n');
156 void setFileName(
const QString& fn) { m_fileName = fn; }
161 class KMessageBoxDebugStream:
public KNoDebugStream
169 QString msg = QString::fromLatin1(data, len);
174 void setCaption(
const QString& h) { m_caption = h; }
179 class KLineEndStrippingDebugStream:
public KNoDebugStream
185 QByteArray buf = QByteArray::fromRawData(data, len);
186 qt_message_output(QtDebugMsg, buf.trimmed().constData());
195 MessageBoxOutput = 1,
199 DefaultOutput = QtOutput,
204 inline Area() { clear(); }
205 void clear(OutputMode set =
Unknown)
207 for (
int i = 0; i < 4; ++i) {
208 logFileName[i].clear();
220 :
config(0), kDebugDBusIface(0), m_disableAll(false), m_seenMainComponent(false)
222 Q_ASSERT(
int(QtDebugMsg) == 0);
223 Q_ASSERT(
int(QtFatalMsg) == 3);
241 for (
int i = 0; i < 8; i++) {
242 m_nullOutputYesNoCache[i] = -1;
250 delete kDebugDBusIface;
258 Area &areaData = cache[0];
263 m_seenMainComponent =
true;
265 areaData.name = qApp ? qAppName().toUtf8() : QByteArray(
"unnamed app");
266 m_seenMainComponent =
false;
270 for (
int i = 0; i < 8; i++) {
271 m_nullOutputYesNoCache[i] = -1;
275 if (filename.isEmpty()) {
278 QFile file(filename);
279 if (!file.open(QIODevice::ReadOnly)) {
280 qWarning(
"Couldn't open %s", filename.toLocal8Bit().constData());
287 while (!file.atEnd()) {
288 const QByteArray line = file.readLine().trimmed();
294 unsigned char ch=line[i];
299 if (ch < '0' || ch >
'9') {
300 qWarning(
"Syntax error parsing '%s': no number (line %u)", qPrintable(filename), lineNumber);
306 }
while (ch >=
'0' && ch <=
'9' && i < line.length());
308 unsigned int number = line.left(i).toUInt();
310 while (i < line.length() && line[i] <=
' ')
314 areaData.name = line.mid(i);
315 cache.insert(number, areaData);
320 inline int level(QtMsgType type)
321 {
return int(type) - int(QtDebugMsg); }
323 QString groupNameForArea(
unsigned int area)
const
325 QString groupName = QString::number(area);
327 groupName = QString::fromLocal8Bit(cache.value(area).name);
332 OutputMode areaOutputMode(QtMsgType type,
unsigned int area,
bool enableByDefault)
340 key = QLatin1String(
"InfoOutput" );
345 key = QLatin1String(
"WarnOutput" );
348 key = QLatin1String(
"FatalOutput" );
353 key = QLatin1String(
"ErrorOutput" );
358 const int mode = cg.readEntry(key,
int(enableByDefault ? DefaultOutput : NoOutput));
359 return OutputMode(mode);
362 QString logFileName(QtMsgType type,
unsigned int area)
371 aKey =
"InfoFilename";
374 aKey =
"WarnFilename";
377 aKey =
"FatalFilename";
381 aKey =
"ErrorFilename";
386 return cg.readPathEntry(aKey, QLatin1String(
"kdebug.dbg"));
398 Cache::Iterator areaData(QtMsgType type,
unsigned int num,
bool enableByDefault =
true)
400 if (!cache.contains(0)) {
403 Q_ASSERT(cache.contains(0));
407 m_seenMainComponent =
true;
410 Cache::Iterator it = cache.find(num);
411 if (it == cache.end()) {
413 Q_ASSERT(cache.contains(0));
419 static bool s_firstDebugFromApplication =
true;
420 if (s_firstDebugFromApplication && !m_disableAll) {
421 s_firstDebugFromApplication =
false;
423 writeGroupForNamedArea(it->name, enableByDefault);
427 const int lev = level(type);
430 it->mode[lev] = areaOutputMode(type, num, enableByDefault);
431 if (it->mode[lev] == FileOutput && it->logFileName[lev].isEmpty())
432 it->logFileName[lev] = logFileName(type, num);
434 Q_ASSERT(it->mode[lev] !=
Unknown);
439 QDebug setupFileWriter(
const QString &fileName)
441 if (!filewriter.hasLocalData())
442 filewriter.setLocalData(
new KFileDebugStream);
443 filewriter.localData()->setFileName(fileName);
444 QDebug result(filewriter.localData());
448 QDebug setupMessageBoxWriter(QtMsgType type,
const QByteArray &areaName)
450 if (!messageboxwriter.hasLocalData())
451 messageboxwriter.setLocalData(
new KMessageBoxDebugStream);
452 QDebug result(messageboxwriter.localData());
460 header =
"Warning (";
463 header =
"Fatal Error (";
473 messageboxwriter.localData()->setCaption(QString::fromLatin1(header));
477 QDebug setupSyslogWriter(QtMsgType type)
479 if (!syslogwriter.hasLocalData())
480 syslogwriter.setLocalData(
new KSyslogDebugStream);
481 QDebug result(syslogwriter.localData());
499 syslogwriter.localData()->setPriority(level);
503 QDebug setupQtWriter(QtMsgType type)
505 if (type != QtDebugMsg) {
506 if (type == QtWarningMsg) {
514 return QDebug(&lineendstrippingwriter);
517 QDebug printHeader(QDebug s,
const QByteArray &areaName,
const char * file,
int line,
const char *funcinfo, QtMsgType type,
bool colored)
519 #ifdef KDE_EXTENDED_DEBUG_OUTPUT
520 static bool printProcessInfo = (qgetenv(
"KDE_DEBUG_NOPROCESSINFO").isEmpty());
521 static bool printAreaName = (qgetenv(
"KDE_DEBUG_NOAREANAME").isEmpty());
522 static bool printMethodName = (qgetenv(
"KDE_DEBUG_NOMETHODNAME").isEmpty());
523 static bool printFileLine = (!qgetenv(
"KDE_DEBUG_FILELINE").isEmpty());
525 static int printTimeStamp = qgetenv(
"KDE_DEBUG_TIMESTAMP").toInt();
526 QByteArray programName;
528 if (printTimeStamp > 0) {
529 if (printTimeStamp >= 2) {
531 const QString sformat = QString::fromLatin1(
"hh:mm:ss.zzz");
532 s << qPrintable(QDateTime::currentDateTime().time().toString(sformat));
535 s << qPrintable(QDateTime::currentDateTime().time().toString());
540 if (printProcessInfo) {
541 programName = cache.value(0).name;
542 if (programName.isEmpty()) {
543 if (QCoreApplication::instance())
544 programName = QCoreApplication::instance()->applicationName().toLocal8Bit();
546 programName =
"<unknown program name>";
548 s << programName.constData() <<
"(" << unsigned(getpid()) <<
")";
550 if (printAreaName && (!printProcessInfo || areaName != programName)) {
551 if (printProcessInfo)
553 s << areaName.constData();
556 if (m_indentString.hasLocalData()) {
557 s << m_indentString.localData()->toLatin1().constData();
561 s <<
' ' << file <<
':' << line <<
' ';
564 if (funcinfo && printMethodName) {
566 if (type <= QtDebugMsg)
575 QByteArray info = funcinfo;
576 int pos = info.indexOf(
'(');
577 Q_ASSERT_X(pos != -1,
"kDebug",
578 "Bug in kDebug(): I don't know how to parse this function name");
579 while (info.at(pos - 1) ==
' ')
581 pos = info.indexOf(
'(', pos + 1);
588 index = info.indexOf(
"<unnamed>::", index);
592 if ( info.at(index-1) !=
':' )
593 info.insert(index,
' ');
595 index += strlen(
"<unnamed>::");
597 pos = info.lastIndexOf(
' ');
599 int startoftemplate = info.lastIndexOf(
'<');
600 if (startoftemplate != -1 && pos > startoftemplate &&
601 pos < info.lastIndexOf(
">::"))
603 pos = info.lastIndexOf(
' ', startoftemplate);
606 if (pos + 1 == info.length())
608 s <<
" " << funcinfo;
610 s <<
" " << info.constData() + pos + 1;
612 s <<
" " << funcinfo;
621 if (!areaName.isEmpty())
622 s << areaName.constData() <<
':';
627 QDebug stream(QtMsgType type,
unsigned int area,
const char *debugFile,
int line,
628 const char *funcinfo)
630 static bool env_colored = (!qgetenv(
"KDE_COLOR_DEBUG").isEmpty());
631 static bool env_colors_on_any_fd = (!qgetenv(
"KDE_COLOR_DEBUG_ALWAYS").isEmpty());
632 Cache::Iterator it = areaData(type, area);
633 OutputMode mode = it->mode[level(type)];
635 QString file = it->logFileName[level(type)];
636 QByteArray areaName = it->name;
638 if (areaName.isEmpty())
639 areaName = cache.value(0).name;
646 s = setupFileWriter(file);
648 case MessageBoxOutput:
649 s = setupMessageBoxWriter(type, areaName);
652 s = setupSyslogWriter(type);
655 s = QDebug(&devnull);
660 s = setupQtWriter(type);
663 colored = env_colored && (env_colors_on_any_fd || isatty(fileno(stderr)));
668 return printHeader(s, areaName, debugFile, line, funcinfo, type, colored);
671 void writeGroupForNamedArea(
const QByteArray& areaName,
bool enabled)
675 KConfig* cfgObj = configObject();
678 const QString key = QString::fromLatin1(
"InfoOutput");
679 if (!cg.hasKey(key)) {
680 cg.writeEntry(key,
int(enabled ? KDebugPrivate::QtOutput : KDebugPrivate::NoOutput));
691 bool m_seenMainComponent;
692 int m_nullOutputYesNoCache[8];
694 KNoDebugStream devnull;
695 QThreadStorage<QString*> m_indentString;
696 QThreadStorage<KSyslogDebugStream*> syslogwriter;
697 QThreadStorage<KFileDebugStream*> filewriter;
698 QThreadStorage<KMessageBoxDebugStream*> messageboxwriter;
699 KLineEndStrippingDebugStream lineendstrippingwriter;
704 #ifdef HAVE_BACKTRACE
707 #ifdef HAVE_BACKTRACE_DEMANGLE
708 const int len = strlen(name);
709 QByteArray in = QByteArray::fromRawData(name, len);
710 const int mangledNameStart = in.indexOf(
"(_");
711 if (mangledNameStart >= 0) {
712 const int mangledNameEnd = in.indexOf(
'+', mangledNameStart + 2);
713 if (mangledNameEnd >= 0) {
717 name[mangledNameEnd] = 0;
718 char *demangled = abi::__cxa_demangle(name + mangledNameStart + 1, 0, 0, &status);
719 name[mangledNameEnd] =
'+';
721 QString ret = QString::fromLatin1(name, mangledNameStart + 1) +
722 QString::fromLatin1(demangled) +
723 QString::fromLatin1(name + mangledNameEnd, len - mangledNameEnd);
730 return QString::fromLatin1(name);
737 #ifdef HAVE_BACKTRACE
739 int n = backtrace(trace, 256);
742 char** strings = backtrace_symbols (trace, n);
745 n = qMin( n, levels );
746 s = QLatin1String(
"[\n");
748 for (
int i = 0; i < n; ++i)
749 s += QString::number(i) + QLatin1String(
": ") +
751 s += QLatin1String(
"]\n");
760 return QDebug(&kDebug_data->devnull);
763 QDebug
kDebugStream(QtMsgType level,
int area,
const char *file,
int line,
const char *funcinfo)
765 if (kDebug_data.isDestroyed()) {
767 qCritical().nospace() <<
"kDebugStream called after destruction (from "
768 << (funcinfo ? funcinfo :
"")
769 << (file ?
" file " :
" unknown file")
771 <<
" line " << line <<
")";
772 return QDebug(level);
775 QMutexLocker locker(&kDebug_data->mutex);
776 return kDebug_data->stream(level, area, file, line, funcinfo);
781 return s << QString::fromLocal8Bit(strerror(errno));
795 s.nospace() <<
"KUrl(" << url.
prettyUrl() <<
")";
801 if (!kDebug_data)
return;
802 KDebugPrivate* d = kDebug_data;
803 QMutexLocker locker(&d->mutex);
807 KDebugPrivate::Cache::Iterator it = d->cache.begin(),
808 end = d->cache.end();
809 for ( ; it != end; ++it)
812 for (
int i = 0; i < 8; i++) {
813 d->m_nullOutputYesNoCache[i] = -1;
821 bool enableByDefault)
826 if (kDebug_data.isDestroyed()) {
830 KDebugPrivate *
const d = kDebug_data;
831 QMutexLocker locker(&d->mutex);
833 if (type == QtDebugMsg) {
834 int *entries = d->m_nullOutputYesNoCache;
835 for (
int i = 0; i < 8; i += 2) {
836 if (entries[i] == area) {
837 return entries[i + 1];
842 KDebugPrivate::Cache::Iterator it = d->areaData(type, area, enableByDefault);
843 const bool ret = it->mode[d->level(type)] == KDebugPrivate::NoOutput;
846 if (type == QtDebugMsg) {
847 int *entries = d->m_nullOutputYesNoCache;
848 int idx = (qrand() % 4) * 2;
850 entries[idx + 1] = ret;
859 KDebugPrivate* d = kDebug_data;
860 QMutexLocker locker(&d->mutex);
862 while (d->cache.contains(areaNumber)) {
865 KDebugPrivate::Area areaData;
866 areaData.name = areaName;
868 d->cache.insert(areaNumber, areaData);
869 d->writeGroupForNamedArea(areaName, enabled);
873 #ifndef KDE_NO_DEBUG_OUTPUT
875 class KDebug::Block::Private
882 : m_label(0), m_area(area), d(0)
890 kDebug(area) <<
"BEGIN:" << label;
893 QThreadStorage<QString*> & indentString = kDebug_data->m_indentString;
894 if (!indentString.hasLocalData()) {
895 indentString.setLocalData(
new QString);
897 *(indentString.localData()) += QLatin1String(
" ");
904 const double duration = m_startTime.elapsed() / 1000.0;
905 QThreadStorage<QString*> & indentString = kDebug_data->m_indentString;
906 indentString.localData()->chop(2);
909 if (duration < 5.0) {
912 << d->m_label.constData()
913 << qPrintable(QString::fromLatin1(
"[Took: %3s]").arg(QString::number(duration,
'g', 2)));
917 << d->m_label.constData()
918 << qPrintable(QString::fromLatin1(
"[DELAY Took (quite long) %3s]").arg(QString::number(duration,
'g', 2)));
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
Display a long message of a certain type.
bool kde_kdebug_enable_dbus_interface
QDebug perror(QDebug s, KDebugTag)
Date/times with associated time zone.
static bool hasNullOutput(QtMsgType type, bool condition, int area, bool enableByDefault)
#define K_GLOBAL_STATIC(TYPE, NAME)
This macro makes it easy to use non-POD types as global statics.
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
This function is just for convenience.
Same format as Qt::TextDate (i.e.
bool hasGroup(const QString &group) const
Returns true if the specified group is known about.
KConfigGroup group(const QByteArray &group)
Returns an object for the named subgroup.
QString toString(const QString &format) const
Returns the date/time as a string.
bool isDateOnly() const
Returns whether the instance represents a date/time or a date-only value.
Represents and parses a URL.
KSharedConfigPtr config()
Returns the general config object.
int open(const QString &pathname, int flags, mode_t mode)
Cascade to system settings, but omit user's globals.
QDebug operator<<(QDebug s, const KDateTime &time)
static int registerArea(const QByteArray &areaName, bool enabled=true)
QString componentName() const
Returns the name of the component.
static bool hasNullOutputQtDebugMsg(int area=KDE_DEFAULT_DEBUG_AREA)
static QString maybeDemangledName(char *name)
A class representing a date and time with an associated time zone.
A class for one specific group in a KConfig object.
The central class of the KDE configuration data system.
const KComponentData & mainComponent()
Returns the global component data.
QDebug kDebugStream(QtMsgType level, int area, const char *file, int line, const char *funcinfo)
Block(const char *label, int area=KDE_DEFAULT_DEBUG_AREA)
D-Bus interface to KDebug.
T readEntry(const QString &key, const T &aDefault) const
Reads the value of an entry specified by pKey in the current group.
QString prettyUrl(AdjustPathOption trailing=LeaveTrailingSlash) const
Returns the URL as string in human-friendly format.
QString kRealBacktrace(int levels)