Loading files
0e185510cThis file is pinned to the selected release. Download the original to open it in your design tool.
/*
* LibrePCB - Professional EDA for everyone!
* Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
* https://librepcb.org/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*******************************************************************************
* Includes
******************************************************************************/
#include "debug.h"
#include "fileio/filepath.h"
#include <QtCore>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
Debug::Debug()
: mDebugLevelStderr(DebugLevel_t::All),
mDebugLevelLogFile(DebugLevel_t::Nothing),
mStderrStream(new QTextStream(stderr)),
mLogFilepath(),
mLogFile(nullptr) {
// determine the filename of the log file which will be used if logging is
// enabled
QString datetime =
QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss");
QString dataDir =
QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
if (!dataDir.isEmpty())
mLogFilepath.setPath(dataDir % "/logs/" % datetime % ".log");
// install the message handler for Qt's debug functions (qDebug(), ...)
qInstallMessageHandler(messageHandler);
}
Debug::~Debug() {
delete mStderrStream;
mStderrStream = nullptr;
if (mLogFile) {
mLogFile->close();
delete mLogFile;
mLogFile = nullptr;
}
}
/*******************************************************************************
* General Methods
******************************************************************************/
void Debug::setDebugLevelStderr(DebugLevel_t level) {
mDebugLevelStderr = level;
}
void Debug::setDebugLevelLogFile(DebugLevel_t level) {
if (level == mDebugLevelLogFile) return;
if ((mDebugLevelLogFile == DebugLevel_t::Nothing) &&
(level != DebugLevel_t::Nothing)) {
// enable logging to file
QDir().mkpath(mLogFilepath.getParentDir().toStr());
mLogFile = new QFile(mLogFilepath.toStr());
bool success = mLogFile->open(QFile::WriteOnly);
if (success) {
mDebugLevelLogFile = level; // activate logging to file immediately!
qDebug() << "Enabled logging to file:" << mLogFilepath.toNative();
} else {
qWarning().nospace() << "Failed to enable logging to file "
<< mLogFilepath.toNative() << ": "
<< mLogFile->errorString();
delete mLogFile;
mLogFile = nullptr;
}
} else if ((mDebugLevelLogFile != DebugLevel_t::Nothing) &&
(level == DebugLevel_t::Nothing) && (mLogFile)) {
// disable logging to file
mLogFile->close();
delete mLogFile;
mLogFile = nullptr;
}
mDebugLevelLogFile = level;
}
Debug::DebugLevel_t Debug::getDebugLevelStderr() const {
return mDebugLevelStderr;
}
Debug::DebugLevel_t Debug::getDebugLevelLogFile() const {
return mDebugLevelLogFile;
}
const FilePath& Debug::getLogFilepath() const {
return mLogFilepath;
}
void Debug::print(DebugLevel_t level, const QString& msg, const char* file,
int line) {
QMutexLocker locker(&mMutex);
// If there is nothing to print, return immediately from this function.
if ((mDebugLevelStderr < level) &&
((mDebugLevelLogFile < level) || (!mLogFile))) {
return;
}
// The debug level string has always 9 characters.
const char* levelStr = "---------";
switch (level) {
case DebugLevel_t::DebugMsg:
levelStr = "DEBUG-MSG";
break;
case DebugLevel_t::Info:
levelStr = " INFO ";
break;
case DebugLevel_t::Warning:
levelStr = " WARNING ";
break;
case DebugLevel_t::Exception:
levelStr = "EXCEPTION";
break;
case DebugLevel_t::Critical:
levelStr = "CRITICAL ";
break;
case DebugLevel_t::Fatal:
levelStr = " FATAL ";
break;
default:
break;
}
QString logMsg = QString("[%1] %2").arg(levelStr).arg(msg);
if (file || line) {
// Avoid printing useless "(:0)" in release builds.
logMsg += QString(" (%1:%2)").arg(file).arg(line);
}
if (mDebugLevelStderr >= level) {
// write to stderr
*mStderrStream << logMsg << '\n';
mStderrStream->flush();
}
if ((mDebugLevelLogFile >= level) && (mLogFile)) {
// write to the log file
QTextStream logFileStream(mLogFile);
logFileStream << logMsg << '\n';
}
}
/*******************************************************************************
* The message handler for qDebug(), qWarning(), qCritical() and qFatal()
******************************************************************************/
void Debug::messageHandler(QtMsgType type, const QMessageLogContext& context,
const QString& msg) {
switch (type) {
case QtDebugMsg:
instance()->print(DebugLevel_t::DebugMsg, msg, context.file,
context.line);
break;
case QtInfoMsg:
instance()->print(DebugLevel_t::Info, msg, context.file, context.line);
break;
case QtWarningMsg:
instance()->print(DebugLevel_t::Warning, msg, context.file, context.line);
break;
case QtCriticalMsg:
instance()->print(DebugLevel_t::Critical, msg, context.file,
context.line);
break;
case QtFatalMsg:
instance()->print(DebugLevel_t::Fatal, msg, context.file, context.line);
abort(); // fatal error --> quit the whole application!
default:
Q_ASSERT(false);
instance()->print(DebugLevel_t::Critical,
QString("unhandled case: %1").arg(type), __FILE__,
__LINE__);
break;
}
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace librepcb