/* Copyright (c) 2008 Volker Krause Inspired by kdelibs/kdecore/io/kdebug.h Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) 2002 Holger Freyther (freyther@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "akdebug.h" #include "akcrash.h" #include "akstandarddirs.h" #include using Akonadi::XdgBaseDirs; #include #include #include #include #include class FileDebugStream : public QIODevice { public: FileDebugStream() : mType( QtCriticalMsg ) { open( WriteOnly ); } bool isSequential() const { return true; } qint64 readData( char *, qint64 ) { return 0; } qint64 readLineData( char *, qint64 ) { return 0; } qint64 writeData( const char *data, qint64 len ) { QByteArray buf = QByteArray::fromRawData( data, len ); if ( !mFileName.isEmpty() ) { QFile outputFile( mFileName ); outputFile.open( QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered ); outputFile.write( data, len ); outputFile.putChar( '\n' ); outputFile.close(); } qt_message_output( mType, #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) QMessageLogContext(), QString::fromLatin1( buf.trimmed() ) ); #else buf.trimmed().constData() ); #endif return len; } void setFileName( const QString &fileName ) { mFileName = fileName; } void setType( QtMsgType type ) { mType = type; } private: QString mFileName; QtMsgType mType; }; class DebugPrivate { public: DebugPrivate() : fileStream( new FileDebugStream() ) { } ~DebugPrivate() { delete fileStream; } QString errorLogFileName() const { return AkStandardDirs::saveDir( "data" ) + QDir::separator() + name + QString::fromLatin1( ".error" ); } QDebug stream( QtMsgType type ) { QMutexLocker locker( &mutex ); #ifndef QT_NO_DEBUG_OUTPUT if ( type == QtDebugMsg ) { return qDebug(); } #endif fileStream->setType( type ); return QDebug( fileStream ); } void setName( const QString &appName ) { // Keep only the executable name, e.g. akonadi_control name = appName.mid( appName.lastIndexOf( QLatin1Char( '/' ) ) + 1 ); fileStream->setFileName( errorLogFileName() ); } QMutex mutex; FileDebugStream *fileStream; QString name; }; Q_GLOBAL_STATIC( DebugPrivate, sInstance ) QDebug akFatal() { return sInstance()->stream( QtFatalMsg ); } QDebug akError() { return sInstance()->stream( QtCriticalMsg ); } #ifndef QT_NO_DEBUG_OUTPUT QDebug akDebug() { return sInstance()->stream( QtDebugMsg ); } #endif void akInit( const QString &appName ) { AkonadiCrash::init(); sInstance()->setName( appName ); QFileInfo infoOld( sInstance()->errorLogFileName() + QString::fromLatin1( ".old" ) ); if ( infoOld.exists() ) { QFile fileOld( infoOld.absoluteFilePath() ); const bool success = fileOld.remove(); if ( !success ) { qFatal( "Cannot remove old log file - running on a readonly filesystem maybe?" ); } } QFileInfo info( sInstance()->errorLogFileName() ); if ( info.exists() ) { QFile file( info.absoluteFilePath() ); const bool success = file.rename( sInstance()->errorLogFileName() + QString::fromLatin1( ".old" ) ); if ( !success ) { qFatal( "Cannot rename log file - running on a readonly filesystem maybe?" ); } } } QString getEnv( const char *name, const QString &defaultValue ) { const QString v = QString::fromLocal8Bit( qgetenv( name ) ); return !v.isEmpty() ? v : defaultValue; }