File indexing completed on 2024-05-12 04:44:37

0001 /*
0002     Copyright (c) 2003-2005 Max Howell <max.howell@methylblue.com>
0003     Copyright (c) 2007-2009 Mark Kretschmann <kretschmann@kde.org>
0004     Copyright (c) 2010 Kevin Funk <krf@electrostorm.net>
0005     Copyright (c) 2011 Harald Sitter <sitter@kde.org>
0006 
0007     This library is free software; you can redistribute it and/or
0008     modify it under the terms of the GNU Lesser General Public
0009     License as published by the Free Software Foundation; either
0010     version 2.1 of the License, or (at your option) any later version.
0011 
0012     This library is distributed in the hope that it will be useful,
0013     but WITHOUT ANY WARRANTY; without even the implied warranty of
0014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015     Lesser General Public License for more details.
0016 
0017     You should have received a copy of the GNU Lesser General Public
0018     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include "debug.h"
0022 #include "debug_p.h"
0023 
0024 #include <QtCore/QMutex>
0025 #include <QtCore/QObject>
0026 #include <QApplication>
0027 
0028 #ifdef Q_OS_UNIX
0029 # include <unistd.h>
0030 #endif
0031 
0032 // Define Application wide prefix
0033 #ifndef APP_PREFIX
0034 #define APP_PREFIX QLatin1String( "PHONON-VLC" )
0035 #endif
0036 
0037 #define DEBUG_INDENT_OBJECTNAME QLatin1String("Debug_Indent_object")
0038 
0039 QRecursiveMutex Debug::mutex;
0040 
0041 using namespace Debug;
0042 
0043 static bool s_debugColorsEnabled = true;
0044 static DebugLevel s_debugLevel = DEBUG_NONE;
0045 
0046 IndentPrivate::IndentPrivate(QObject* parent)
0047     : QObject(parent)
0048 {
0049     setObjectName( DEBUG_INDENT_OBJECTNAME );
0050 }
0051 
0052 /**
0053  * We can't use a statically instantiated QString for the indent, because
0054  * static namespaces are unique to each dlopened library. So we piggy back
0055  * the QString on the KApplication instance
0056  */
0057 IndentPrivate* IndentPrivate::instance()
0058 {
0059     QObject* qOApp = reinterpret_cast<QObject*>(qApp);
0060     QObject* obj = qOApp ? qOApp->findChild<QObject*>( DEBUG_INDENT_OBJECTNAME ) : 0;
0061     return (obj ? static_cast<IndentPrivate*>( obj ) : new IndentPrivate( qApp ));
0062 }
0063 
0064 /*
0065   Text color codes (use last digit here)
0066   30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
0067 */
0068 static int s_colors[] = { 1, 2, 4, 5, 6 }; // no yellow and white for sanity
0069 static int s_colorIndex = 0;
0070 
0071 static QString toString( DebugLevel level )
0072 {
0073     switch( level )
0074     {
0075         case DEBUG_WARN:
0076             return "[WARNING]";
0077         case DEBUG_ERROR:
0078             return "[ERROR__]";
0079         case DEBUG_FATAL:
0080             return "[FATAL__]";
0081         default:
0082             return QString();
0083     }
0084 }
0085 
0086 static int toColor( DebugLevel level )
0087 {
0088     switch( level ) {
0089         case DEBUG_WARN:
0090             return 3; // red
0091         case DEBUG_ERROR:
0092         case DEBUG_FATAL:
0093             return 1; // yellow
0094         default:
0095             return 0; // default: black
0096     }
0097 }
0098 
0099 static QString colorize( const QString &text, int color = s_colorIndex )
0100 {
0101     if( !debugColorEnabled() )
0102         return text;
0103 
0104     return QString( "\x1b[00;3%1m%2\x1b[00;39m" ).arg( QString::number(s_colors[color]), text );
0105 }
0106 
0107 static QString reverseColorize( const QString &text, int color )
0108 {
0109     if( !debugColorEnabled() )
0110         return text;
0111 
0112     return QString( "\x1b[07;3%1m%2\x1b[00;39m" ).arg( QString::number(color), text );
0113 }
0114 
0115 QString Debug::indent()
0116 {
0117     return IndentPrivate::instance()->m_string;
0118 }
0119 
0120 bool Debug::debugEnabled()
0121 {
0122     return s_debugLevel < DEBUG_NONE;
0123 }
0124 
0125 bool Debug::debugColorEnabled()
0126 {
0127     return s_debugColorsEnabled;
0128 }
0129 
0130 DebugLevel Debug::minimumDebugLevel()
0131 {
0132     return s_debugLevel;
0133 }
0134 
0135 void Debug::setColoredDebug( bool enable )
0136 {
0137     s_debugColorsEnabled = enable;
0138 }
0139 
0140 void Debug::setMinimumDebugLevel(DebugLevel level)
0141 {
0142     s_debugLevel = level;
0143 }
0144 
0145 QDebug Debug::dbgstream( DebugLevel level )
0146 {
0147     if ( level < s_debugLevel )
0148         return nullDebug();
0149 
0150     mutex.lock();
0151     const QString currentIndent = indent();
0152     mutex.unlock();
0153 
0154     QString text = QString("%1%2").arg( APP_PREFIX ).arg( currentIndent );
0155     if ( level > DEBUG_INFO )
0156         text.append( ' ' + reverseColorize( toString(level), toColor( level ) ) );
0157 
0158     return QDebug( QtDebugMsg ) << qPrintable( text );
0159 }
0160 
0161 void Debug::perfLog( const QString &message, const QString &func )
0162 {
0163 #ifdef Q_OS_UNIX
0164     if( !debugEnabled() )
0165         return;
0166 
0167     QString str = QString( "MARK: %1: %2 %3" ).arg( qApp->applicationName(), func, message );
0168     access( str.toLocal8Bit().data(), F_OK );
0169 #endif
0170 }
0171 
0172 Block::Block( const char *label )
0173     : m_label( label )
0174     , m_color( s_colorIndex )
0175 {
0176     if( !debugEnabled() || DEBUG_INFO < s_debugLevel)
0177         return;
0178 
0179 #if QT_VERSION >= 0x040700
0180     m_startTime.start();
0181 #else
0182     m_startTime = QTime::currentTime();
0183 #endif
0184 
0185     mutex.lock();
0186     s_colorIndex = (s_colorIndex + 1) % 5;
0187     dbgstream()
0188         << qPrintable( colorize( QLatin1String( "BEGIN:" ), m_color ) )
0189         << m_label;
0190     IndentPrivate::instance()->m_string += QLatin1String("  ");
0191     mutex.unlock();
0192 }
0193 
0194 Block::~Block()
0195 {
0196     if( !debugEnabled() || DEBUG_INFO < s_debugLevel)
0197         return;
0198 
0199 #if QT_VERSION >= 0x040700
0200     const double duration = m_startTime.elapsed() / 1000.0;
0201 #else
0202     const double duration = (double)m_startTime.msecsTo( QTime::currentTime() ) / 1000.0;
0203 #endif
0204 
0205     mutex.lock();
0206     IndentPrivate::instance()->m_string.truncate( Debug::indent().length() - 2 );
0207     mutex.unlock();
0208 
0209     // Print timing information, and a special message (DELAY) if the method took longer than 5s
0210     if( duration < 5.0 )
0211     {
0212         dbgstream()
0213             << qPrintable( colorize( QLatin1String( "END__:" ), m_color ) )
0214             << m_label
0215             << qPrintable( colorize( QString( "[Took: %3s]")
0216                                      .arg( QString::number(duration, 'g', 2) ), m_color ) );
0217     }
0218     else
0219     {
0220         dbgstream()
0221             << qPrintable( colorize( QString( "END__:" ), m_color ) )
0222             << m_label
0223             << qPrintable( reverseColorize( QString( "[DELAY Took (quite long) %3s]")
0224                                             .arg( QString::number(duration, 'g', 2) ), toColor( DEBUG_WARN ) ) );
0225     }
0226 }
0227 
0228 void Debug::stamp()
0229 {
0230     static int n = 0;
0231     debug() << "| Stamp: " << ++n << Qt::endl;
0232 }