2016-09-03 15:54:33 +02:00
|
|
|
#include <utils/Logger.h>
|
|
|
|
#include <utils/FileUtils.h>
|
2016-06-05 16:08:55 +02:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <algorithm>
|
2019-08-13 20:41:01 +02:00
|
|
|
|
2020-05-12 19:51:19 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
#include <syslog.h>
|
|
|
|
#elif _WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#include <Shlwapi.h>
|
|
|
|
#pragma comment(lib, "Shlwapi.lib")
|
|
|
|
#endif
|
2016-06-05 16:08:55 +02:00
|
|
|
#include <QFileInfo>
|
2016-11-26 22:34:46 +01:00
|
|
|
#include <time.h>
|
2016-06-05 16:08:55 +02:00
|
|
|
|
2016-11-26 22:34:46 +01:00
|
|
|
static const char * LogLevelStrings[] = { "", "DEBUG", "INFO", "WARNING", "ERROR" };
|
2020-05-12 19:51:19 +02:00
|
|
|
#ifndef _WIN32
|
2016-11-26 22:34:46 +01:00
|
|
|
static const int LogLevelSysLog[] = { LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR };
|
2020-05-12 19:51:19 +02:00
|
|
|
#endif
|
2016-11-26 22:34:46 +01:00
|
|
|
static unsigned int loggerCount = 0;
|
|
|
|
static unsigned int loggerId = 0;
|
2016-06-21 21:41:26 +02:00
|
|
|
|
2017-03-04 22:17:42 +01:00
|
|
|
std::map<QString,Logger*> *Logger::LoggerMap = nullptr;
|
2016-06-21 21:41:26 +02:00
|
|
|
Logger::LogLevel Logger::GLOBAL_MIN_LOG_LEVEL = Logger::UNSET;
|
2016-11-26 22:46:16 +01:00
|
|
|
LoggerManager* LoggerManager::_instance = nullptr;
|
2019-08-13 20:41:01 +02:00
|
|
|
int _repeatCount = 0;
|
|
|
|
Logger::T_LOG_MESSAGE _repeatMessage;
|
|
|
|
const int _maxRepeatCountSize = 200;
|
2016-06-05 16:08:55 +02:00
|
|
|
|
2017-01-10 19:58:41 +01:00
|
|
|
Logger* Logger::getInstance(QString name, Logger::LogLevel minLevel)
|
2016-06-05 16:08:55 +02:00
|
|
|
{
|
2017-03-01 15:23:53 +01:00
|
|
|
qRegisterMetaType<Logger::T_LOG_MESSAGE>();
|
2016-11-26 22:34:46 +01:00
|
|
|
Logger* log = nullptr;
|
2016-06-21 21:41:26 +02:00
|
|
|
if (LoggerMap == nullptr)
|
2016-06-05 16:08:55 +02:00
|
|
|
{
|
2017-03-04 22:17:42 +01:00
|
|
|
LoggerMap = new std::map<QString,Logger*>;
|
2016-06-05 16:08:55 +02:00
|
|
|
}
|
2017-10-12 11:55:03 +02:00
|
|
|
|
2020-06-28 23:12:22 +02:00
|
|
|
if (LoggerMap->find(name) == LoggerMap->end())
|
2016-06-05 16:08:55 +02:00
|
|
|
{
|
2017-03-04 22:17:42 +01:00
|
|
|
log = new Logger(name,minLevel);
|
|
|
|
LoggerMap->insert(std::pair<QString,Logger*>(name,log)); // compat version, replace it with following line if we have 100% c++11
|
|
|
|
//LoggerMap->emplace(name,log); // not compat with older linux distro's e.g. wheezy
|
2019-08-13 20:41:01 +02:00
|
|
|
connect(log, &Logger::newLogMessage, LoggerManager::getInstance(), &LoggerManager::handleNewLogMessage);
|
2016-11-26 22:34:46 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-04 22:17:42 +01:00
|
|
|
log = LoggerMap->at(name);
|
2016-11-26 22:34:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return log;
|
2016-06-05 16:08:55 +02:00
|
|
|
}
|
|
|
|
|
2017-03-04 22:17:42 +01:00
|
|
|
void Logger::deleteInstance(QString name)
|
2016-06-21 21:41:26 +02:00
|
|
|
{
|
|
|
|
if (LoggerMap == nullptr)
|
|
|
|
return;
|
2017-10-12 11:55:03 +02:00
|
|
|
|
2020-06-28 23:12:22 +02:00
|
|
|
if (name.isEmpty())
|
2016-06-21 21:41:26 +02:00
|
|
|
{
|
2017-03-04 22:17:42 +01:00
|
|
|
std::map<QString,Logger*>::iterator it;
|
2020-06-28 23:12:22 +02:00
|
|
|
for (it = LoggerMap->begin(); it != LoggerMap->end(); it++)
|
2016-06-21 21:41:26 +02:00
|
|
|
{
|
|
|
|
delete it->second;
|
|
|
|
}
|
|
|
|
LoggerMap->clear();
|
|
|
|
}
|
|
|
|
else if (LoggerMap->find(name) != LoggerMap->end())
|
|
|
|
{
|
|
|
|
delete LoggerMap->at(name);
|
|
|
|
LoggerMap->erase(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-03-04 22:17:42 +01:00
|
|
|
void Logger::setLogLevel(LogLevel level,QString name)
|
2016-06-21 21:41:26 +02:00
|
|
|
{
|
2020-06-28 23:12:22 +02:00
|
|
|
if (name.isEmpty())
|
2016-06-21 21:41:26 +02:00
|
|
|
{
|
|
|
|
GLOBAL_MIN_LOG_LEVEL = level;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-04 22:17:42 +01:00
|
|
|
Logger* log = Logger::getInstance(name,level);
|
2016-06-21 21:41:26 +02:00
|
|
|
log->setMinLevel(level);
|
|
|
|
}
|
|
|
|
}
|
2016-06-05 16:08:55 +02:00
|
|
|
|
2017-03-04 22:17:42 +01:00
|
|
|
Logger::LogLevel Logger::getLogLevel(QString name)
|
2016-06-27 23:56:21 +02:00
|
|
|
{
|
2020-06-28 23:12:22 +02:00
|
|
|
if (name.isEmpty())
|
2016-06-27 23:56:21 +02:00
|
|
|
{
|
|
|
|
return GLOBAL_MIN_LOG_LEVEL;
|
|
|
|
}
|
|
|
|
|
2017-03-04 22:17:42 +01:00
|
|
|
Logger* log = Logger::getInstance(name);
|
2016-06-27 23:56:21 +02:00
|
|
|
return log->getMinLevel();
|
|
|
|
}
|
2016-06-05 16:08:55 +02:00
|
|
|
|
2020-06-28 23:12:22 +02:00
|
|
|
Logger::Logger (QString name, LogLevel minLevel)
|
2016-11-26 22:34:46 +01:00
|
|
|
: QObject()
|
|
|
|
, _name(name)
|
|
|
|
, _minLevel(minLevel)
|
|
|
|
, _syslogEnabled(true)
|
|
|
|
, _loggerId(loggerId++)
|
2016-06-05 16:08:55 +02:00
|
|
|
{
|
2016-06-14 20:14:06 +02:00
|
|
|
#ifdef __GLIBC__
|
2016-08-07 18:39:45 +02:00
|
|
|
const char* _appname_char = program_invocation_short_name;
|
2020-05-12 19:51:19 +02:00
|
|
|
#elif !defined(_WIN32)
|
2016-08-07 18:39:45 +02:00
|
|
|
const char* _appname_char = getprogname();
|
2020-05-12 19:51:19 +02:00
|
|
|
#else
|
|
|
|
char fileName[MAX_PATH];
|
|
|
|
char *_appname_char;
|
|
|
|
HINSTANCE hinst = GetModuleHandle(NULL);
|
|
|
|
if (GetModuleFileNameA(hinst, fileName, sizeof(fileName)))
|
|
|
|
{
|
|
|
|
_appname_char = PathFindFileName(fileName);
|
|
|
|
*(PathFindExtension(fileName)) = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
_appname_char = "unknown";
|
2016-06-12 22:27:34 +02:00
|
|
|
#endif
|
2017-03-04 22:17:42 +01:00
|
|
|
_appname = QString(_appname_char).toLower();
|
2017-10-12 11:55:03 +02:00
|
|
|
|
2016-06-05 16:08:55 +02:00
|
|
|
loggerCount++;
|
2016-06-21 21:41:26 +02:00
|
|
|
|
2020-06-28 23:12:22 +02:00
|
|
|
if (_syslogEnabled && loggerCount == 1)
|
2016-06-05 16:08:55 +02:00
|
|
|
{
|
2020-05-12 19:51:19 +02:00
|
|
|
#ifndef _WIN32
|
2016-08-07 18:39:45 +02:00
|
|
|
openlog (_appname_char, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL0);
|
2020-05-12 19:51:19 +02:00
|
|
|
#endif
|
2016-06-05 16:08:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Logger::~Logger()
|
|
|
|
{
|
2017-10-12 11:55:03 +02:00
|
|
|
//Debug(this, "logger '%s' destroyed", QSTRING_CSTR(_name) );
|
2016-06-05 16:08:55 +02:00
|
|
|
loggerCount--;
|
2020-05-12 19:51:19 +02:00
|
|
|
#ifndef _WIN32
|
2020-06-28 23:12:22 +02:00
|
|
|
if (loggerCount == 0)
|
2016-06-05 16:08:55 +02:00
|
|
|
closelog();
|
2020-05-12 19:51:19 +02:00
|
|
|
#endif
|
2016-06-05 16:08:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Logger::Message(LogLevel level, const char* sourceFile, const char* func, unsigned int line, const char* fmt, ...)
|
|
|
|
{
|
2016-06-21 21:41:26 +02:00
|
|
|
if ( (GLOBAL_MIN_LOG_LEVEL == Logger::UNSET && level < _minLevel) // no global level, use level from logger
|
|
|
|
|| (GLOBAL_MIN_LOG_LEVEL > Logger::UNSET && level < GLOBAL_MIN_LOG_LEVEL) ) // global level set, use global level
|
2016-06-05 16:08:55 +02:00
|
|
|
return;
|
|
|
|
|
2016-07-21 20:12:51 +02:00
|
|
|
const size_t max_msg_length = 1024;
|
|
|
|
char msg[max_msg_length];
|
2016-06-05 16:08:55 +02:00
|
|
|
va_list args;
|
|
|
|
va_start (args, fmt);
|
2016-07-21 20:12:51 +02:00
|
|
|
vsnprintf (msg, max_msg_length, fmt, args);
|
2016-06-05 16:08:55 +02:00
|
|
|
va_end (args);
|
|
|
|
|
2019-08-13 20:41:01 +02:00
|
|
|
auto repeatedSummary = [=]
|
|
|
|
{
|
|
|
|
Logger::T_LOG_MESSAGE repMsg = _repeatMessage;
|
|
|
|
repMsg.message = "Previous line repeats " + QString::number(_repeatCount) + " times";
|
|
|
|
|
|
|
|
emit newLogMessage(repMsg);
|
2016-11-26 22:34:46 +01:00
|
|
|
|
2019-08-13 20:41:01 +02:00
|
|
|
std::cout << QString("[" + repMsg.appName + " " + repMsg.loggerName + "] <" + LogLevelStrings[repMsg.level] + "> " + repMsg.message).toStdString() << std::endl;
|
2016-11-26 22:34:46 +01:00
|
|
|
|
2020-05-12 19:51:19 +02:00
|
|
|
#ifndef _WIN32
|
2019-08-13 20:41:01 +02:00
|
|
|
if ( _syslogEnabled && repMsg.level >= Logger::WARNING )
|
|
|
|
syslog (LogLevelSysLog[repMsg.level], "Previous line repeats %d times", _repeatCount);
|
2020-05-12 19:51:19 +02:00
|
|
|
#endif
|
2016-11-26 22:34:46 +01:00
|
|
|
|
2019-08-13 20:41:01 +02:00
|
|
|
_repeatCount = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (_repeatMessage.loggerName == _name
|
|
|
|
&& _repeatMessage.function == QString(func)
|
|
|
|
&& _repeatMessage.line == line
|
|
|
|
&& _repeatMessage.message == QString(msg))
|
2016-06-05 16:08:55 +02:00
|
|
|
{
|
2019-08-13 20:41:01 +02:00
|
|
|
if (_repeatCount >= _maxRepeatCountSize)
|
|
|
|
repeatedSummary();
|
|
|
|
else
|
|
|
|
_repeatCount++;
|
|
|
|
|
|
|
|
return;
|
2016-06-05 16:08:55 +02:00
|
|
|
}
|
2019-08-13 20:41:01 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (_repeatCount) repeatedSummary();
|
2016-11-26 22:34:46 +01:00
|
|
|
|
2019-08-13 20:41:01 +02:00
|
|
|
Logger::T_LOG_MESSAGE logMsg;
|
2016-06-05 16:08:55 +02:00
|
|
|
|
2019-08-13 20:41:01 +02:00
|
|
|
logMsg.appName = _appname;
|
|
|
|
logMsg.loggerName = _name;
|
|
|
|
logMsg.function = QString(func);
|
|
|
|
logMsg.line = line;
|
|
|
|
logMsg.fileName = FileUtils::getBaseName(sourceFile);
|
|
|
|
time(&(logMsg.utime));
|
|
|
|
logMsg.message = QString(msg);
|
|
|
|
logMsg.level = level;
|
|
|
|
logMsg.levelString = LogLevelStrings[level];
|
|
|
|
|
|
|
|
emit newLogMessage(logMsg);
|
|
|
|
|
|
|
|
QString location;
|
|
|
|
if ( level == Logger::DEBUG )
|
|
|
|
{
|
|
|
|
location = "<" + logMsg.fileName + ":" + QString::number(line)+":"+ logMsg.function + "()> ";
|
|
|
|
}
|
2016-06-05 16:08:55 +02:00
|
|
|
|
2019-08-13 20:41:01 +02:00
|
|
|
std::cout << QString("[" + _appname + " " + _name + "] <" + LogLevelStrings[level] + "> " + location + msg).toStdString() << std::endl;
|
2020-05-12 19:51:19 +02:00
|
|
|
#ifndef _WIN32
|
2019-08-13 20:41:01 +02:00
|
|
|
if ( _syslogEnabled && level >= Logger::WARNING )
|
|
|
|
syslog (LogLevelSysLog[level], "%s", msg);
|
2020-05-12 19:51:19 +02:00
|
|
|
#endif
|
2019-08-13 20:41:01 +02:00
|
|
|
_repeatMessage = logMsg;
|
|
|
|
}
|
|
|
|
}
|
2016-06-05 16:08:55 +02:00
|
|
|
|
2016-11-26 22:46:16 +01:00
|
|
|
LoggerManager::LoggerManager()
|
2016-11-26 22:34:46 +01:00
|
|
|
: QObject()
|
2016-11-26 22:46:16 +01:00
|
|
|
, _loggerMaxMsgBufferSize(200)
|
2016-11-26 22:34:46 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-06-05 18:19:08 +02:00
|
|
|
void LoggerManager::handleNewLogMessage(const Logger::T_LOG_MESSAGE &msg)
|
2016-11-26 22:34:46 +01:00
|
|
|
{
|
2016-11-26 22:46:16 +01:00
|
|
|
_logMessageBuffer.append(msg);
|
|
|
|
if (_logMessageBuffer.length() > _loggerMaxMsgBufferSize)
|
|
|
|
{
|
|
|
|
_logMessageBuffer.erase(_logMessageBuffer.begin());
|
|
|
|
}
|
2016-11-26 22:34:46 +01:00
|
|
|
|
|
|
|
emit newLogMessage(msg);
|
|
|
|
}
|
|
|
|
|
2016-11-26 22:46:16 +01:00
|
|
|
LoggerManager* LoggerManager::getInstance()
|
2016-11-26 22:34:46 +01:00
|
|
|
{
|
2020-06-28 23:12:22 +02:00
|
|
|
if (_instance == nullptr)
|
2016-11-26 22:46:16 +01:00
|
|
|
_instance = new LoggerManager();
|
|
|
|
return _instance;
|
2016-11-26 22:34:46 +01:00
|
|
|
}
|