• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDECore

kdebug.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002     Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
00003                   2002 Holger Freyther (freyther@kde.org)
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #define KDE_EXTENDED_DEBUG_OUTPUT
00022 
00023 #ifndef QT_NO_CAST_FROM_ASCII
00024 #define QT_NO_CAST_FROM_ASCII
00025 #endif
00026 #ifndef QT_NO_CAST_TO_ASCII
00027 #define QT_NO_CAST_TO_ASCII
00028 #endif
00029 #ifndef KDE3_SUPPORT
00030 #define KDE3_SUPPORT
00031 #endif
00032 
00033 #include "kdebug.h"
00034 #include <QThreadStorage>
00035 
00036 #ifdef Q_WS_WIN
00037 #include <fcntl.h>
00038 #include <windows.h>
00039 #ifndef _WIN32_WCE
00040 #include <wincon.h>
00041 #endif
00042 #else
00043 #include <unistd.h>
00044 #include <stdio.h>
00045 #endif
00046 
00047 #ifdef NDEBUG
00048 #undef kDebug
00049 #undef kBacktrace
00050 #endif
00051 
00052 #include <config.h>
00053 
00054 #ifdef HAVE_SYS_TIME_H
00055 #include <sys/time.h>
00056 #endif
00057 #ifdef HAVE_TIME_H
00058 #include <time.h>
00059 #endif
00060 
00061 #include "kglobal.h"
00062 #include "kstandarddirs.h"
00063 #include "kdatetime.h"
00064 #include "kcmdlineargs.h"
00065 
00066 #include <kmessage.h>
00067 #include <klocale.h>
00068 #include <kconfiggroup.h>
00069 #include <kurl.h>
00070 
00071 #include <QtCore/QFile>
00072 #include <QtCore/QHash>
00073 #include <QtCore/QObject>
00074 #include <QtCore/QChar>
00075 #include <QtCore/QCoreApplication>
00076 
00077 #include <stdlib.h> // abort
00078 #include <unistd.h> // getpid
00079 #include <stdarg.h> // vararg stuff
00080 #include <ctype.h>      // isprint
00081 #include <syslog.h>
00082 #include <errno.h>
00083 #include <string.h>
00084 #include <kconfig.h>
00085 #include "kcomponentdata.h"
00086 
00087 #ifdef Q_OS_SOLARIS
00088 // For the purposes of KDebug Solaris has a GNU-libc-compatible
00089 // backtrace() function. This isn't detected by the CMake checks
00090 // normally (check_function_exists fails), but we know it's there.
00091 // For better results, we would use walk_context(), but that's
00092 // a little more code -- see also the crash handler in kcrash.cpp .
00093 #define HAVE_BACKTRACE (1)
00094 #endif
00095 
00096 #ifdef HAVE_BACKTRACE
00097 #include <execinfo.h>
00098 #ifdef __GNUC__
00099 #define HAVE_BACKTRACE_DEMANGLE
00100 #include <cxxabi.h>
00101 #endif
00102 #endif
00103 
00104 #include "kdebugdbusiface_p.h"
00105 #include <QMutex>
00106 
00107 
00108 
00109 KDECORE_EXPORT bool kde_kdebug_enable_dbus_interface = false;
00110 
00111 class KNoDebugStream: public QIODevice
00112 {
00113     // Q_OBJECT
00114 public:
00115     KNoDebugStream() { open(WriteOnly); }
00116     bool isSequential() const { return true; }
00117     qint64 readData(char *, qint64) { return 0; /* eof */ }
00118     qint64 readLineData(char *, qint64) { return 0; /* eof */ }
00119     qint64 writeData(const char *, qint64 len) { return len; }
00120 };
00121 
00122 class KSyslogDebugStream: public KNoDebugStream
00123 {
00124     // Q_OBJECT
00125 public:
00126     qint64 writeData(const char *data, qint64 len)
00127         {
00128             if (len) {
00129                 // not using fromRawData because we need a terminating NUL
00130                 const QByteArray buf(data, len);
00131                 syslog(m_priority, "%s", buf.constData());
00132             }
00133             return len;
00134         }
00135     void setPriority(int priority) { m_priority = priority; }
00136 private:
00137     int m_priority;
00138 };
00139 
00140 class KFileDebugStream: public KNoDebugStream
00141 {
00142     // Q_OBJECT
00143 public:
00144     qint64 writeData(const char *data, qint64 len)
00145         {
00146             if (len) {
00147                 QFile aOutputFile(m_fileName);
00148                 aOutputFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered);
00149                 QByteArray buf = QByteArray::fromRawData(data, len);
00150                 aOutputFile.write(buf.trimmed());
00151                 aOutputFile.putChar('\n');
00152                 aOutputFile.close();
00153             }
00154             return len;
00155         }
00156     void setFileName(const QString& fn) { m_fileName = fn; }
00157 private:
00158     QString m_fileName;
00159 };
00160 
00161 class KMessageBoxDebugStream: public KNoDebugStream
00162 {
00163     // Q_OBJECT
00164 public:
00165     qint64 writeData(const char *data, qint64 len)
00166         {
00167             if (len) {
00168                 // Since we are in kdecore here, we cannot use KMsgBox
00169                 QString msg = QString::fromAscii(data, len);
00170                 KMessage::message(KMessage::Information, msg, m_caption);
00171             }
00172             return len;
00173         }
00174     void setCaption(const QString& h) { m_caption = h; }
00175 private:
00176     QString m_caption;
00177 };
00178 
00179 class KLineEndStrippingDebugStream: public KNoDebugStream
00180 {
00181     // Q_OBJECT
00182 public:
00183     qint64 writeData(const char *data, qint64 len)
00184         {
00185             QByteArray buf = QByteArray::fromRawData(data, len);
00186             qt_message_output(QtDebugMsg, buf.trimmed().constData());
00187             return len;
00188         }
00189 };
00190 
00191 struct KDebugPrivate
00192 {
00193     enum OutputMode {
00194         FileOutput = 0,
00195         MessageBoxOutput = 1,
00196         QtOutput = 2,
00197         SyslogOutput = 3,
00198         NoOutput = 4,
00199         DefaultOutput = QtOutput, // if you change DefaultOutput, also change the defaults in kdebugdialog!
00200         Unknown = 5
00201     };
00202 
00203     struct Area {
00204         inline Area() { clear(); }
00205         void clear(OutputMode set = Unknown)
00206         {
00207             for (int i = 0; i < 4; ++i) {
00208                 logFileName[i].clear();
00209                 mode[i] = set;
00210             }
00211         }
00212 
00213         QByteArray name;
00214         QString logFileName[4];
00215         OutputMode mode[4];
00216     };
00217     typedef QHash<unsigned int, Area> Cache;
00218 
00219     KDebugPrivate()
00220         : config(0), kDebugDBusIface(0), m_disableAll(false), m_seenMainComponent(false)
00221     {
00222         Q_ASSERT(int(QtDebugMsg) == 0);
00223         Q_ASSERT(int(QtFatalMsg) == 3);
00224 
00225         // Create the D-Bus interface if it has not been created yet
00226         // But only register to D-Bus if we are in a process with a D-Bus event loop,
00227         // otherwise introspection will just hang.
00228         // Examples of processes without a D-Bus event loop: kioslaves and the main kdeinit process.
00229         //
00230         // How to know that we have a real event loop? That's tricky.
00231         // We could delay registration in kDebugDBusIface with a QTimer, but
00232         // it would still get triggered by kioslaves that use enterLoop/exitLoop
00233         // to run kio jobs synchronously.
00234         //
00235         // Solution: we have a bool that is set by KApplication
00236         // (kioslaves should use QCoreApplication but not KApplication).
00237         if (kde_kdebug_enable_dbus_interface) {
00238             kDebugDBusIface = new KDebugDBusIface;
00239         }
00240 
00241         for (int i = 0; i < 8; i++) {
00242             m_nullOutputYesNoCache[i] = -1;
00243         }
00244 
00245     }
00246 
00247     ~KDebugPrivate()
00248     {
00249         delete config;
00250         delete kDebugDBusIface;
00251     }
00252 
00253     void loadAreaNames()
00254     {
00255         // Don't clear the cache here, that would lose previously registered dynamic areas
00256         //cache.clear();
00257 
00258         Area &areaData = cache[0];
00259         areaData.clear();
00260 
00261         if (KGlobal::hasMainComponent()) {
00262             areaData.name = KGlobal::mainComponent().componentName().toUtf8();
00263             m_seenMainComponent = true;
00264         } else {
00265             areaData.name = qApp ? qAppName().toUtf8() : QByteArray("unnamed app");
00266             m_seenMainComponent = false;
00267         }
00268         //qDebug() << "loadAreaNames: area 0 has name" << areaData.name;
00269 
00270         for (int i = 0; i < 8; i++) {
00271             m_nullOutputYesNoCache[i] = -1;
00272         }
00273 
00274         QString filename(KStandardDirs::locate("config", QLatin1String("kdebug.areas")));
00275         if (filename.isEmpty()) {
00276             return;
00277         }
00278         QFile file(filename);
00279         if (!file.open(QIODevice::ReadOnly)) {
00280             qWarning("Couldn't open %s", filename.toLocal8Bit().constData());
00281             file.close();
00282             return;
00283         }
00284 
00285         uint lineNumber=0;
00286 
00287         while (!file.atEnd()) {
00288             const QByteArray line = file.readLine().trimmed();
00289             ++lineNumber;
00290             if (line.isEmpty())
00291                 continue;
00292 
00293             int i=0;
00294             unsigned char ch=line[i];
00295 
00296             if (ch =='#')
00297                 continue; // We have an eof, a comment or an empty line
00298 
00299             if (ch < '0' && ch > '9') {
00300                 qWarning("Syntax error: no number (line %u)",lineNumber);
00301                 continue;
00302             }
00303 
00304             do {
00305                 ch=line[++i];
00306             } while (ch >= '0' && ch <= '9' && i < line.length());
00307 
00308             unsigned int number = line.left(i).toUInt();
00309 
00310             while (i < line.length() && line[i] <= ' ')
00311                 i++;
00312 
00313             Area areaData;
00314             areaData.name = line.mid(i);
00315             cache.insert(number, areaData);
00316         }
00317         file.close();
00318     }
00319 
00320     inline int level(QtMsgType type)
00321     { return int(type) - int(QtDebugMsg); }
00322 
00323     QString groupNameForArea(unsigned int area) const
00324     {
00325         QString groupName = QString::number(area);
00326         if (area == 0 || !config->hasGroup(groupName)) {
00327             groupName = QString::fromLocal8Bit(cache.value(area).name);
00328         }
00329         return groupName;
00330     }
00331 
00332     OutputMode areaOutputMode(QtMsgType type, unsigned int area, bool enableByDefault)
00333     {
00334         if (!configObject())
00335             return QtOutput;
00336 
00337         QString key;
00338         switch (type) {
00339         case QtDebugMsg:
00340             key = QLatin1String( "InfoOutput" );
00341             if (m_disableAll)
00342                 return NoOutput;
00343             break;
00344         case QtWarningMsg:
00345             key = QLatin1String( "WarnOutput" );
00346             break;
00347         case QtFatalMsg:
00348             key = QLatin1String( "FatalOutput" );
00349             break;
00350         case QtCriticalMsg:
00351         default:
00352             /* Programmer error, use "Error" as default */
00353             key = QLatin1String( "ErrorOutput" );
00354             break;
00355         }
00356 
00357         const KConfigGroup cg(config, groupNameForArea(area));
00358         const int mode = cg.readEntry(key, int(enableByDefault ? DefaultOutput : NoOutput));
00359         return OutputMode(mode);
00360     }
00361 
00362     QString logFileName(QtMsgType type, unsigned int area)
00363     {
00364         if (!configObject())
00365             return QString();
00366 
00367         const char* aKey;
00368         switch (type)
00369         {
00370         case QtDebugMsg:
00371             aKey = "InfoFilename";
00372             break;
00373         case QtWarningMsg:
00374             aKey = "WarnFilename";
00375             break;
00376         case QtFatalMsg:
00377             aKey = "FatalFilename";
00378             break;
00379         case QtCriticalMsg:
00380         default:
00381             aKey = "ErrorFilename";
00382             break;
00383         }
00384 
00385         KConfigGroup cg(config, groupNameForArea(area));
00386         return cg.readPathEntry(aKey, QLatin1String("kdebug.dbg"));
00387     }
00388 
00389     KConfig* configObject()
00390     {
00391         if (!config) {
00392             config = new KConfig(QLatin1String("kdebugrc"), KConfig::NoGlobals);
00393             m_disableAll = config->group(QString()).readEntry("DisableAll", false);
00394         }
00395         return config;
00396     }
00397 
00398     Cache::Iterator areaData(QtMsgType type, unsigned int num, bool enableByDefault = true)
00399     {
00400         if (!cache.contains(0)) {
00401             //qDebug() << "cache size=" << cache.count() << "loading area names";
00402             loadAreaNames(); // fills 'cache'
00403             Q_ASSERT(cache.contains(0));
00404         } else if (!m_seenMainComponent && KGlobal::hasMainComponent()) {
00405             // Update the name for area 0 once a main component exists
00406             cache[0].name = KGlobal::mainComponent().componentName().toUtf8();
00407             m_seenMainComponent = true;
00408         }
00409 
00410         Cache::Iterator it = cache.find(num);
00411         if (it == cache.end()) {
00412             // unknown area
00413             Q_ASSERT(cache.contains(0));
00414             it = cache.find(0);
00415             num = 0;
00416         }
00417 
00418         if (num == 0 && type == QtDebugMsg) { // area 0 is special, it becomes the named area "appname"
00419             static bool s_firstDebugFromApplication = true;
00420             if (s_firstDebugFromApplication && !m_disableAll) {
00421                 s_firstDebugFromApplication = false;
00422                 //qDebug() << "First debug output from" << it->name << "writing out with default" << enableByDefault;
00423                 writeGroupForNamedArea(it->name, enableByDefault);
00424             }
00425         }
00426 
00427         const int lev = level(type);
00428         //qDebug() << "in cache for" << num << ":" << it->mode[lev];
00429         if (it->mode[lev] == Unknown)
00430             it->mode[lev] = areaOutputMode(type, num, enableByDefault);
00431         if (it->mode[lev] == FileOutput && it->logFileName[lev].isEmpty())
00432             it->logFileName[lev] = logFileName(type, num);
00433 
00434         Q_ASSERT(it->mode[lev] != Unknown);
00435 
00436         return it;
00437     }
00438 
00439     QDebug setupFileWriter(const QString &fileName)
00440     {
00441         if (!filewriter.hasLocalData())
00442             filewriter.setLocalData(new KFileDebugStream);
00443         filewriter.localData()->setFileName(fileName);
00444         QDebug result(filewriter.localData());
00445         return result;
00446     }
00447 
00448     QDebug setupMessageBoxWriter(QtMsgType type, const QByteArray &areaName)
00449     {
00450         if (!messageboxwriter.hasLocalData())
00451             messageboxwriter.setLocalData(new KMessageBoxDebugStream);
00452         QDebug result(messageboxwriter.localData());
00453         QByteArray header;
00454 
00455         switch (type) {
00456         case QtDebugMsg:
00457             header = "Info (";
00458             break;
00459         case QtWarningMsg:
00460             header = "Warning (";
00461             break;
00462         case QtFatalMsg:
00463             header = "Fatal Error (";
00464             break;
00465         case QtCriticalMsg:
00466         default:
00467             header = "Error (";
00468             break;
00469         }
00470 
00471         header += areaName;
00472         header += ')';
00473         messageboxwriter.localData()->setCaption(QString::fromAscii(header));
00474         return result;
00475     }
00476 
00477     QDebug setupSyslogWriter(QtMsgType type)
00478     {
00479         if (!syslogwriter.hasLocalData())
00480             syslogwriter.setLocalData(new KSyslogDebugStream);
00481         QDebug result(syslogwriter.localData());
00482         int level = 0;
00483 
00484         switch (type) {
00485         case QtDebugMsg:
00486             level = LOG_INFO;
00487             break;
00488         case QtWarningMsg:
00489             level = LOG_WARNING;
00490             break;
00491         case QtFatalMsg:
00492             level = LOG_CRIT;
00493             break;
00494         case QtCriticalMsg:
00495         default:
00496             level = LOG_ERR;
00497             break;
00498         }
00499         syslogwriter.localData()->setPriority(level);
00500         return result;
00501     }
00502 
00503     QDebug setupQtWriter(QtMsgType type)
00504     {
00505         if (type != QtDebugMsg) {
00506             if (type == QtWarningMsg) {
00507                 // KDE warnings are not the same thing as Qt warnings
00508                 // in Qt, warnings indicate bad code, which must be corrected before the release
00509                 // in KDE, it's just something that everyone sees (including users)
00510                 type = QtDebugMsg;
00511             }
00512             return QDebug(type);
00513         }
00514         return QDebug(&lineendstrippingwriter);
00515     }
00516 
00517     QDebug printHeader(QDebug s, const QByteArray &areaName, const char * file, int line, const char *funcinfo, QtMsgType type, bool colored)
00518     {
00519 #ifdef KDE_EXTENDED_DEBUG_OUTPUT
00520         static bool printProcessInfo = (qgetenv("KDE_DEBUG_NOPROCESSINFO").isEmpty());
00521         static bool printAreaName = (qgetenv("KDE_DEBUG_NOAREANAME").isEmpty());
00522         static bool printMethodName = (qgetenv("KDE_DEBUG_NOMETHODNAME").isEmpty());
00523         static bool printFileLine = (!qgetenv("KDE_DEBUG_FILELINE").isEmpty());
00524 
00525         static int printTimeStamp = qgetenv("KDE_DEBUG_TIMESTAMP").toInt();
00526         QByteArray programName;
00527         s = s.nospace();
00528         if (printTimeStamp > 0) {
00529             if (printTimeStamp >= 2) {
00530                 // the extended print: 17:03:24.123
00531                 const QString sformat = QString::fromLatin1("hh:mm:ss.zzz");
00532                 s << qPrintable(QDateTime::currentDateTime().time().toString(sformat));
00533             } else {
00534                 // the default print: 17:03:24
00535                 s << qPrintable(QDateTime::currentDateTime().time().toString());
00536             }
00537             s << ' ';
00538         }
00539 
00540         if (printProcessInfo) {
00541             programName = cache.value(0).name;
00542             if (programName.isEmpty()) {
00543                 if (QCoreApplication::instance())
00544                     programName = QCoreApplication::instance()->applicationName().toLocal8Bit();
00545                 else
00546                     programName = "<unknown program name>";
00547             }
00548             s << programName.constData() << "(" << unsigned(getpid()) << ")";
00549         }
00550         if (printAreaName && (!printProcessInfo || areaName != programName)) {
00551             if (printProcessInfo)
00552                 s << "/";
00553             s << areaName.constData();
00554         }
00555 
00556         if (m_indentString.hasLocalData()) {
00557             s << m_indentString.localData()->toLatin1().constData();
00558         }
00559 
00560         if (printFileLine) {
00561             s << ' ' << file << ':' << line << ' ';
00562         }
00563 
00564         if (funcinfo && printMethodName) {
00565             if (colored) {
00566                 if (type <= QtDebugMsg)
00567                     s << "\033[0;34m"; //blue
00568                 else
00569                     s << "\033[0;31m"; //red
00570             }
00571 # ifdef Q_CC_GNU
00572             // strip the function info down to the base function name
00573             // note that this throws away the template definitions,
00574             // the parameter types (overloads) and any const/volatile qualifiers
00575             QByteArray info = funcinfo;
00576             int pos = info.indexOf('(');
00577             Q_ASSERT_X(pos != -1, "kDebug",
00578                        "Bug in kDebug(): I don't know how to parse this function name");
00579             while (info.at(pos - 1) == ' ')
00580                 // that '(' we matched was actually the opening of a function-pointer
00581                 pos = info.indexOf('(', pos + 1);
00582 
00583             info.truncate(pos);
00584             // gcc 4.1.2 don't put a space between the return type and
00585             // the function name if the function is in an anonymous namespace
00586             int index = 1;
00587             forever {
00588                 index = info.indexOf("<unnamed>::", index);
00589                 if ( index == -1 )
00590                     break;
00591 
00592                 if ( info.at(index-1) != ':' )
00593                     info.insert(index, ' ');
00594 
00595                 index += strlen("<unnamed>::");
00596             }
00597             pos = info.lastIndexOf(' ');
00598             if (pos != -1) {
00599                 int startoftemplate = info.lastIndexOf('<');
00600                 if (startoftemplate != -1 && pos > startoftemplate &&
00601                     pos < info.lastIndexOf(">::"))
00602                     // we matched a space inside this function's template definition
00603                     pos = info.lastIndexOf(' ', startoftemplate);
00604             }
00605 
00606             if (pos + 1 == info.length())
00607                 // something went wrong, so gracefully bail out
00608                 s << " " << funcinfo;
00609             else
00610                 s << " " << info.constData() + pos + 1;
00611 # else
00612             s << " " << funcinfo;
00613 # endif
00614            if(colored)
00615                s  << "\033[0m";
00616         }
00617 
00618         s << ":";
00619 #else
00620         Q_UNUSED(funcinfo);
00621         if (!areaName.isEmpty())
00622             s << areaName.constData() << ':';
00623 #endif
00624         return s.space();
00625     }
00626 
00627     QDebug stream(QtMsgType type, unsigned int area, const char *debugFile, int line,
00628                   const char *funcinfo)
00629     {
00630         static bool env_colored = (!qgetenv("KDE_COLOR_DEBUG").isEmpty());
00631         Cache::Iterator it = areaData(type, area);
00632         OutputMode mode = it->mode[level(type)];
00633         Q_ASSERT(mode != Unknown);
00634         QString file = it->logFileName[level(type)];
00635         QByteArray areaName = it->name;
00636 
00637         if (areaName.isEmpty())
00638             areaName = cache.value(0).name;
00639 
00640         bool colored=false;
00641 
00642         QDebug s(&devnull);
00643         switch (mode) {
00644         case FileOutput:
00645             s = setupFileWriter(file);
00646             break;
00647         case MessageBoxOutput:
00648             s = setupMessageBoxWriter(type, areaName);
00649             break;
00650         case SyslogOutput:
00651             s = setupSyslogWriter(type);
00652             break;
00653         case NoOutput:
00654             s = QDebug(&devnull);
00655             return s; //no need to take the time to "print header" if we don't want to output anyway
00656             break;
00657         case Unknown: // should not happen
00658         default:                // QtOutput
00659             s = setupQtWriter(type);
00660 #ifndef Q_OS_WIN
00661             //only color if the debug goes to a tty.
00662             colored = env_colored && isatty(fileno(stderr));
00663 #endif
00664             break;
00665         }
00666 
00667         return printHeader(s, areaName, debugFile, line, funcinfo, type, colored);
00668     }
00669 
00670     void writeGroupForNamedArea(const QByteArray& areaName, bool enabled)
00671     {
00672         // Ensure that this area name appears in kdebugrc, so that users (via kdebugdialog)
00673         // can turn it off.
00674         KConfig* cfgObj = configObject();
00675         if (cfgObj) {
00676             KConfigGroup cg(cfgObj, QString::fromUtf8(areaName));
00677             const QString key = QString::fromLatin1("InfoOutput");
00678             if (!cg.hasKey(key)) {
00679                 cg.writeEntry(key, int(enabled ? KDebugPrivate::QtOutput : KDebugPrivate::NoOutput));
00680                 cg.sync();
00681             }
00682         }
00683     }
00684 
00685     QMutex mutex;
00686     KConfig *config;
00687     KDebugDBusIface *kDebugDBusIface;
00688     Cache cache;
00689     bool m_disableAll;
00690     bool m_seenMainComponent; // false: area zero still contains qAppName
00691     int m_nullOutputYesNoCache[8];
00692 
00693     KNoDebugStream devnull;
00694     QThreadStorage<QString*> m_indentString;
00695     QThreadStorage<KSyslogDebugStream*> syslogwriter;
00696     QThreadStorage<KFileDebugStream*> filewriter;
00697     QThreadStorage<KMessageBoxDebugStream*> messageboxwriter;
00698     KLineEndStrippingDebugStream lineendstrippingwriter;
00699 };
00700 
00701 K_GLOBAL_STATIC(KDebugPrivate, kDebug_data)
00702 
00703 #ifdef HAVE_BACKTRACE
00704 static QString maybeDemangledName(char *name)
00705 {
00706 #ifdef HAVE_BACKTRACE_DEMANGLE
00707     const int len = strlen(name);
00708     QByteArray in = QByteArray::fromRawData(name, len);
00709     const int mangledNameStart = in.indexOf("(_");
00710     if (mangledNameStart >= 0) {
00711         const int mangledNameEnd = in.indexOf('+', mangledNameStart + 2);
00712         if (mangledNameEnd >= 0) {
00713             int status;
00714             // if we forget about this line and the one that undoes its effect we don't change the
00715             // internal data of the QByteArray::fromRawData() ;)
00716             name[mangledNameEnd] = 0;
00717             char *demangled = abi::__cxa_demangle(name + mangledNameStart + 1, 0, 0, &status);
00718             name[mangledNameEnd] = '+';
00719             if (demangled) {
00720                 QString ret = QString::fromLatin1(name, mangledNameStart + 1) +
00721                               QString::fromLatin1(demangled) +
00722                               QString::fromLatin1(name + mangledNameEnd, len - mangledNameEnd);
00723                 free(demangled);
00724                 return ret;
00725             }
00726         }
00727     }
00728 #endif
00729     return QString::fromLatin1(name);
00730 }
00731 #endif
00732 
00733 QString kRealBacktrace(int levels)
00734 {
00735     QString s;
00736 #ifdef HAVE_BACKTRACE
00737     void* trace[256];
00738     int n = backtrace(trace, 256);
00739     if (!n)
00740     return s;
00741     char** strings = backtrace_symbols (trace, n);
00742 
00743     if ( levels != -1 )
00744         n = qMin( n, levels );
00745     s = QLatin1String("[\n");
00746 
00747     for (int i = 0; i < n; ++i)
00748         s += QString::number(i) + QLatin1String(": ") +
00749              maybeDemangledName(strings[i]) + QLatin1Char('\n');
00750     s += QLatin1String("]\n");
00751     if (strings)
00752         free (strings);
00753 #endif
00754     return s;
00755 }
00756 
00757 QDebug kDebugDevNull()
00758 {
00759     return QDebug(&kDebug_data->devnull);
00760 }
00761 
00762 QDebug kDebugStream(QtMsgType level, int area, const char *file, int line, const char *funcinfo)
00763 {
00764     if (kDebug_data.isDestroyed()) {
00765         // we don't know what to return now...
00766         qCritical().nospace() << "kDebugStream called after destruction (from "
00767                               << (funcinfo ? funcinfo : "")
00768                               << (file ? " file " : " unknown file")
00769                               << (file ? file :"")
00770                               << " line " << line << ")";
00771         return QDebug(level);
00772     }
00773 
00774     QMutexLocker locker(&kDebug_data->mutex);
00775     return kDebug_data->stream(level, area, file, line, funcinfo);
00776 }
00777 
00778 QDebug perror(QDebug s, KDebugTag)
00779 {
00780     return s << QString::fromLocal8Bit(strerror(errno));
00781 }
00782 
00783 QDebug operator<<(QDebug s, const KDateTime &time)
00784 {
00785     if ( time.isDateOnly() )
00786         s.nospace() << "KDateTime(" << qPrintable(time.toString(KDateTime::QtTextDate)) << ")";
00787     else
00788         s.nospace() << "KDateTime(" << qPrintable(time.toString(KDateTime::ISODate)) << ")";
00789     return s.space();
00790 }
00791 
00792 QDebug operator<<(QDebug s, const KUrl &url)
00793 {
00794     s.nospace() << "KUrl(" << url.prettyUrl() << ")";
00795     return s.space();
00796 }
00797 
00798 void kClearDebugConfig()
00799 {
00800     if (!kDebug_data) return;
00801     KDebugPrivate* d = kDebug_data;
00802     QMutexLocker locker(&d->mutex);
00803     delete d->config;
00804     d->config = 0;
00805 
00806     KDebugPrivate::Cache::Iterator it = d->cache.begin(),
00807                                   end = d->cache.end();
00808     for ( ; it != end; ++it)
00809         it->clear();
00810 
00811     for (int i = 0; i < 8; i++) {
00812         d->m_nullOutputYesNoCache[i] = -1;
00813     }
00814 }
00815 
00816 // static
00817 bool KDebug::hasNullOutput(QtMsgType type,
00818                            bool condition,
00819                            int area,
00820                            bool enableByDefault)
00821 {
00822     if (!condition) {
00823         return true;
00824     }
00825     if (kDebug_data.isDestroyed()) {
00826          // kDebugStream() will generate a warning anyway, so we don't.
00827         return false;
00828     }
00829     KDebugPrivate *const d = kDebug_data;
00830     QMutexLocker locker(&d->mutex);
00831 
00832     if (type == QtDebugMsg) {
00833         int *entries = d->m_nullOutputYesNoCache;
00834         for (int i = 0; i < 8; i += 2) {
00835             if (entries[i] == area) {
00836                 return entries[i + 1];
00837             }
00838         }
00839     }
00840 
00841     KDebugPrivate::Cache::Iterator it = d->areaData(type, area, enableByDefault);
00842     const bool ret = it->mode[d->level(type)] == KDebugPrivate::NoOutput;
00843 
00844     // cache result for next time...
00845     if (type == QtDebugMsg) {
00846         int *entries = d->m_nullOutputYesNoCache;
00847         int idx = (qrand() % 4) * 2;
00848         entries[idx] = area;
00849         entries[idx + 1] = ret;
00850     }
00851 
00852     return ret;
00853 }
00854 
00855 int KDebug::registerArea(const QByteArray& areaName, bool enabled)
00856 {
00857     // TODO for optimization: static int s_lastAreaNumber = 1;
00858     KDebugPrivate* d = kDebug_data;
00859     QMutexLocker locker(&d->mutex);
00860     int areaNumber = 1;
00861     while (d->cache.contains(areaNumber)) {
00862         ++areaNumber;
00863     }
00864     KDebugPrivate::Area areaData;
00865     areaData.name = areaName;
00866     //qDebug() << "Assigning area number" << areaNumber << "for name" << areaName;
00867     d->cache.insert(areaNumber, areaData);
00868     d->writeGroupForNamedArea(areaName, enabled);
00869     return areaNumber;
00870 }
00871 
00872 #ifndef KDE_NO_DEBUG_OUTPUT
00873 
00874 KDebug::Block::Block(const char* label, int area)
00875     : m_label(label), m_area(area), d(0)
00876 {
00877     if (hasNullOutputQtDebugMsg(area)) {
00878         m_label = 0; // remember, for the dtor
00879     } else {
00880         m_startTime.start();
00881         kDebug(area) << "BEGIN:" << label;
00882 
00883         // The indent string is per thread
00884         QThreadStorage<QString*> & indentString = kDebug_data->m_indentString;
00885         if (!indentString.hasLocalData()) {
00886             indentString.setLocalData(new QString);
00887         }
00888         *(indentString.localData()) += QLatin1String("  ");
00889     }
00890 }
00891 
00892 KDebug::Block::~Block()
00893 {
00894     if (m_label) {
00895         const double duration = m_startTime.elapsed() / 1000.0;
00896         QThreadStorage<QString*> & indentString = kDebug_data->m_indentString;
00897         indentString.localData()->chop(2);
00898 
00899         // Print timing information, and a special message (DELAY) if the method took longer than 5s
00900         if (duration < 5.0) {
00901             kDebug(m_area)
00902                 << "END__:"
00903                 << m_label
00904                 << qPrintable(QString::fromLatin1("[Took: %3s]").arg(QString::number(duration, 'g', 2)));
00905         } else {
00906             kDebug(m_area)
00907                 << "END__:"
00908                 << m_label
00909                 << qPrintable(QString::fromLatin1("[DELAY Took (quite long) %3s]").arg(QString::number(duration, 'g', 2)));
00910         }
00911     }
00912 }
00913 
00914 #endif

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal