/* **************************************************************************** * Copyright 2019 Open Systems Development BV * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * * DEALINGS IN THE SOFTWARE. * * ***************************************************************************/ // std #include #include #include #include #include "timeutils.h" #include "log.h" #include "threadcontext.h" #include #include #include #include #include #include #include #include #include #include namespace osdev { namespace components { namespace { QString toString(LogLevel level) { switch(level) { case LogLevel::Trace: return "T"; case LogLevel::Debug: return "D"; case LogLevel::Info: return "I"; case LogLevel::Warning: return "W"; case LogLevel::Error: return "E"; } return "U"; } } // anonymous QString Log::s_context = QString(); QString Log::s_fileName = QString(); LogLevel Log::s_logLevel = LogLevel::Debug; QMutex Log::m_mutex; void Log::init(const QString& context, const QString& logFile, LogLevel logDepth) { s_logLevel = logDepth; s_context = context; if ( !logFile.isEmpty() ) { s_fileName = logFile; } } void Log::terminate() { s_context.clear(); s_fileName.clear(); s_logLevel = LogLevel::Info; } void Log::log(const QString& category, const QString& message, LogLevel level) { QMutexLocker lock( &m_mutex ); QString logCategory = s_context + '|' + toString(level) + '|' + ThreadContext::instance().context() + '|' + category; QString logMessage = message; if(logMessage.isEmpty()) { static const QString emptyMessage("--"); logMessage = emptyMessage; } else { // Replace % signs. logMessage.replace('%', "%%"); } writeLog( logCategory, logMessage, level ); } QString Log::fileinfoMessage(const char* file, int line, const QString& message) { static const QString templ("%1:%2| %3"); QFileInfo fi(file); return templ.arg( fi.fileName() ).arg(line).arg(message); } void Log::trace(const QString &category, const QString &message) { log(category, message, LogLevel::Trace); } void Log::debug(const QString& category, const QString& message) { log( category, message, LogLevel::Debug ); } void Log::info(const QString& category, const QString& message) { log( category, message, LogLevel::Info ); } void Log::warning(const QString& category, const QString& message) { log(category, message, LogLevel::Warning ); } void Log::error(const QString& category, const QString& message) { log(category, message, LogLevel::Error ); } void Log::logObject(const QString& category, QObject* object) { QBuffer buffer; buffer.open(QIODevice::ReadWrite); QDataStream datastream(&buffer); QString data; datastream << object; datastream >> data; log( category, data, LogLevel::Debug ); } void Log::trace(const char *file, int line, const QString &category, const QString &message) { log(category, fileinfoMessage(file, line, message), LogLevel::Trace ); } void Log::debug(const char* file, int line, const QString& category, const QString& message) { log( category, fileinfoMessage(file, line, message), LogLevel::Debug ); } void Log::info(const char* file, int line, const QString& category, const QString& message) { log( category, fileinfoMessage(file, line, message), LogLevel::Info ); } void Log::warning(const char* file, int line, const QString& category, const QString& message) { log( category, fileinfoMessage(file, line, message), LogLevel::Warning); } void Log::error(const char* file, int line, const QString& category, const QString& message) { log( category, fileinfoMessage(file, line, message), LogLevel::Error ); } void Log::logObject(const char* file, int line, const QString& category, QObject* object) { QBuffer buffer; buffer.open(QIODevice::ReadWrite); QDataStream datastream(&buffer); QString data; datastream << object; datastream >> data; log( " [LOGOBJECT] " + category, fileinfoMessage(file, line, data), LogLevel::Debug ); } QString Log::getDateTime() { return QDateTime::currentDateTime().toString( "dd-MM-yyyy HH:mm:ss.zzz" ); } void Log::writeLog(const QString& category, const QString& message, LogLevel level) { if ( level >= s_logLevel ) { std::ostringstream threadIdStr; threadIdStr << std::right << std::setfill('0') << std::setw(12) << std::hex << std::this_thread::get_id(); QString logLine; QTextStream(&logLine) << getDateTime() << '|' << threadIdStr.str().c_str() << '|' << category << '|' << message; if ( !s_fileName.isEmpty() ) { QFile mFile( s_fileName ); if ( !mFile.open( QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text ) ) { qWarning() << "Error opening the logfile : " << s_fileName << " for writing."; qWarning() << logLine; } else { QTextStream out( &mFile ); out << logLine << '\n'; mFile.close(); } } else { qDebug() << logLine; } } } } /* End namespace components */ } /* End namespace osdev */