Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Z/src/NGLLogger/NGLLogger.cpp
T
2026-09-01 12:27:57 +02:00

487 lines
11 KiB
C++
Executable File

#include "NGLLogger.h"
#include "MurmurHash2.h"
#include <cstdlib>
#include <iostream>
#ifdef HAVE_LOG4QT
#include <log4qt/logger.h>
#include <log4qt/logmanager.h>
#include <log4qt/loggerrepository.h>
#include <log4qt/propertyconfigurator.h>
#include <log4qt/rollingfileappender.h>
#include <log4qt/helpers/configuratorhelper.h>
#include <log4qt/helpers/properties.h>
#include <log4qt/helpers/factory.h>
#endif
#include <mutex>
#include <unordered_map>
#include <QtCore/QCoreApplication>
#include <QtCore/QFileInfo>
namespace NGL
{
void LtsRollingFileAppender::setLtsLogfileName(const QString &ltsLogfileName)
{
m_ltsLogfileName = ltsLogfileName;
}
void LtsRollingFileAppender::activateOptions()
{
if (!m_ltsLogfileName.isEmpty())
setFile(m_ltsLogfileName);
#ifdef HAVE_LOG4QT
Log4Qt::RollingFileAppender::activateOptions();
#endif
}
QString LtsRollingFileAppender::m_ltsLogfileName;
#ifdef HAVE_LOG4QT
static Log4Qt::Appender *createLtsRollingFileAppender()
{
auto ret = new LtsRollingFileAppender;
ret->setAppendFile(true);
return ret;
}
#endif
class CleanupHelper final
{
public:
CleanupHelper() = default;
~CleanupHelper();
std::mutex &getLoggerMapMutex();
std::unordered_map<unsigned int, NGL::NGLLogger *> m_loggermap;
protected:
std::mutex m_loggermapmutex;
};
NGL::NGLLogger *NGL::NGLLogger::rootlogger_ptr = nullptr;
NGL::CleanupHelper NGL::NGLLogger::s_cleanup;
CleanupHelper::~CleanupHelper()
{
std::lock_guard<std::mutex> lock(m_loggermapmutex);
for (auto it : m_loggermap)
delete it.second;
m_loggermap.clear();
delete NGL::NGLLogger::rootlogger_ptr;
NGL::NGLLogger::rootlogger_ptr = nullptr;
}
std::mutex &CleanupHelper::getLoggerMapMutex()
{
return m_loggermapmutex;
}
}
NGL::NGLLogger::NGLLogger(const std::string &fullqualifiedname)
: name(fullqualifiedname)
, currentLevel(LogLevel::Undefined)
, m_bNoSpace(true)
{
#ifdef HAVE_LOG4QT
if (!fullqualifiedname.empty())
{
logger_ptr = Log4Qt::LogManager::loggerRepository()->logger(QString::fromStdString(name));
s_cleanup.m_loggermap[MurmurHash2(fullqualifiedname.c_str(), fullqualifiedname.size())] = this;
}
else
{
logger_ptr = Log4Qt::LogManager::loggerRepository()->rootLogger();
}
#endif
configChanged();
}
NGL::INGLLogger &NGL::NGLLogger::getNGLLogger(const char *fullqualifiedname)
{
std::lock_guard<std::mutex> lock(s_cleanup.getLoggerMapMutex());
auto it = s_cleanup.m_loggermap.find(MurmurHash2(fullqualifiedname, strlen(fullqualifiedname)));
if (it != s_cleanup.m_loggermap.end())
return *(*it).second;
return *(new NGLLogger(fullqualifiedname));
}
NGL::INGLLogger &NGL::NGLLogger::getNGLLogger(const std::string &fullqualifiedname)
{
std::lock_guard<std::mutex> lock(s_cleanup.getLoggerMapMutex());
auto it = s_cleanup.m_loggermap.find(MurmurHash2(fullqualifiedname.c_str(), fullqualifiedname.size()));
if (it != s_cleanup.m_loggermap.end())
return *(*it).second;
return *(new NGLLogger(fullqualifiedname));
}
void NGL::NGLLogger::log(LogLevel level, const INGLLogger::String &message, const char *file, int line, const char *function)
{
#ifdef HAVE_LOG4QT
logger_ptr->logWithLocation(static_cast<Log4Qt::Level::Value>(level), file, line, function, QString::fromStdString(message));
#else
// Stub implementation - use qDebug/qWarning/qCritical based on level
Q_UNUSED(file);
Q_UNUSED(line);
Q_UNUSED(function);
const QString msg = QString::fromStdString(message);
switch (level)
{
case LogLevel::Fatal:
case LogLevel::Error:
qCritical() << msg;
break;
case LogLevel::Warning:
qWarning() << msg;
break;
case LogLevel::Info:
case LogLevel::Debug:
case LogLevel::Trace:
default:
qDebug() << msg;
break;
}
#endif
}
void NGL::NGLLogger::logTrace(const INGLLogger::String &message, const char *file, int line, const char *function)
{
if (currentLevel >= LogLevel::Trace)
log(LogLevel::Trace, message, file, line, function);
}
void NGL::NGLLogger::logDebug(const INGLLogger::String &message, const char *file, int line, const char *function)
{
if (currentLevel >= LogLevel::Debug)
log(LogLevel::Debug, message, file, line, function);
}
void NGL::NGLLogger::logInfo(const INGLLogger::String &message, const char *file, int line, const char *function)
{
if (currentLevel >= LogLevel::Info)
log(LogLevel::Info, message, file, line, function);
}
void NGL::NGLLogger::logWarning(const INGLLogger::String &message, const char *file, int line, const char *function)
{
if (currentLevel >= LogLevel::Warning)
log(LogLevel::Warning, message, file, line, function);
}
void NGL::NGLLogger::logError(const INGLLogger::String &message, const char *file, int line, const char *function)
{
if (currentLevel >= LogLevel::Error)
log(LogLevel::Error, message, file, line, function);
}
void NGL::NGLLogger::logFatal(const INGLLogger::String &message, const char *file, int line, const char *function)
{
log(LogLevel::Fatal, message, file, line, function);
}
#ifndef LTS_VERSION_MAJOR
#define LTS_VERSION_MAJOR "undefined"
#endif
#ifndef LTS_VERSION_MINOR
#define LTS_VERSION_MINOR "undefined"
#endif
#ifndef LTS_VERSION_PATCH
#define LTS_VERSION_PATCH "undefined"
#endif
#ifndef LTS_VERSION_DATE
#define LTS_VERSION_DATE "undefined"
#endif
#ifndef JENKINS_BUILD_NUMBER
#define JENKINS_BUILD_NUMBER "unknown"
#endif
static const char ver_major[] = LTS_VERSION_MAJOR;
static const char ver_minor[] = LTS_VERSION_MINOR;
static const char ver_patch[] = LTS_VERSION_PATCH;
static const char ver_date[] = LTS_VERSION_DATE;
static const char ver_jenkins[] = JENKINS_BUILD_NUMBER;
void NGL::NGLLogger::logStartup(const char *file, int line, const char *function)
{
log(LogLevel::Info, QStringLiteral("Application is started (%1.%2-%3 rev%4 from %5)")
.arg(QString::fromLatin1(ver_major),
QString::fromLatin1(ver_minor),
QString::fromLatin1(ver_jenkins),
QString::fromLatin1(ver_patch),
QString::fromLatin1(ver_date)).toUtf8().constData(), file, line, function);
}
void NGL::NGLLogger::logShutdown(const char *file, int line, const char *function)
{
log(LogLevel::Info, QStringLiteral("Application is shut down (%1.%2-%3 rev%4 from %5)")
.arg(QString::fromLatin1(ver_major),
QString::fromLatin1(ver_minor),
QString::fromLatin1(ver_jenkins),
QString::fromLatin1(ver_patch),
QString::fromLatin1(ver_date)).toUtf8().constData(), file, line, function);
}
NGL::NGLLogger &NGL::NGLLogger::getNGLRootLogger()
{
if (!rootlogger_ptr) throw NotCreatedError();
return *rootlogger_ptr;
}
static QString findConfigFile(const QString &configfilename)
{
if (configfilename.isEmpty())
return QString();
QFileInfo fi(configfilename);
if (fi.isFile() && fi.isReadable())
return fi.absoluteFilePath();
QString p = QCoreApplication::applicationDirPath() + QLatin1Char('/') + configfilename;
fi.setFile(p);
if (fi.isFile() && fi.isReadable())
return fi.absoluteFilePath();
return QString();
}
NGL::NGLLogger &NGL::NGLLogger::createNGLRootLogger(const QString &configfilename,
bool ignorealreadycreated,
const QString &logOutputName,
bool quiet)
{
if (rootlogger_ptr)
{
if (!ignorealreadycreated) throw AlreadyCreatedError();
}
else
{
#ifdef HAVE_LOG4QT
Log4Qt::Factory::registerAppender("Lts::RollingFileAppender", createLtsRollingFileAppender);
LtsRollingFileAppender::setLtsLogfileName(logOutputName);
rootlogger_ptr = new NGLLogger(std::string());
const QString filename = findConfigFile(configfilename);
if (!filename.isEmpty())
{
Log4Qt::PropertyConfigurator::configureAndWatch(filename);
QObject::connect(Log4Qt::ConfiguratorHelper::instance(), &Log4Qt::ConfiguratorHelper::configurationFileChanged,
[]() { configurationFileChanged(); });
const auto l = Log4Qt::ConfiguratorHelper::instance()->configureError();
for (const auto &t : l)
std::cerr << t.message().toUtf8().data() << std::endl;
if (!l.isEmpty())
exit(-1);
}
else
{
if (!quiet)
std::cerr << "Could not find log4cxx configuration file " << configfilename << std::endl
<< "Using default logging to stdout" << std::endl;
Log4Qt::Properties props;
props.setProperty(QLatin1String("log4j.rootLogger"),
QLatin1String("WARN, stdout"));
props.setProperty(QLatin1String("log4j.appender.stdout"),
QLatin1String("org.apache.log4j.ConsoleAppender"));
props.setProperty(QLatin1String("log4j.appender.stdout.layout"),
QLatin1String("org.apache.log4j.PatternLayout"));
props.setProperty(QLatin1String("log4j.appender.stdout.layout.ConversionPattern"),
QLatin1String("%d %-5p %c |#| %m (%.50F:%L) %n"));
Log4Qt::PropertyConfigurator::configure(props);
}
rootlogger_ptr->configChanged();
#else
// Stub implementation - no logging initialization needed
Q_UNUSED(configfilename);
Q_UNUSED(ignorealreadycreated);
Q_UNUSED(logOutputName);
Q_UNUSED(quiet);
rootlogger_ptr = new NGLLogger(std::string());
#endif
}
return *rootlogger_ptr;
}
void NGL::NGLLogger::configurationFileChanged()
{
for (auto ptr : s_cleanup.m_loggermap)
ptr.second->configChanged();
}
void NGL::NGLLogger::configChanged()
{
if (logger_ptr->isTraceEnabled())
currentLevel = LogLevel::Trace;
else if (logger_ptr->isDebugEnabled())
currentLevel = LogLevel::Debug;
else if (logger_ptr->isInfoEnabled())
currentLevel = LogLevel::Info;
else if (logger_ptr->isWarnEnabled())
currentLevel = LogLevel::Warning;
else if (logger_ptr->isErrorEnabled())
currentLevel = LogLevel::Error;
else
currentLevel = LogLevel::Fatal;
}
namespace NGL
{
namespace NGLLoggerHelper
{
void hexDumpHelper(NGL::INGLLogger &logger, NGL::LogLevel level,
const void *a_data, const unsigned int a_size)
{
if (!logger.isLevelEnabled(level) || !a_data)
return;
unsigned char *data = (unsigned char *)a_data;
QByteArray baBuf;
for (unsigned int i = 0; i < a_size; i++)
{
if (0 == (i % 8))
baBuf = QByteArray::number(i, 16).rightJustified(8, '0').toUpper();
baBuf += " " + QByteArray::number(data[i], 16).rightJustified(2, '0').toUpper();
if (7 == (i % 8))
logger.log(level, baBuf.constData(), __FILE__, __LINE__);
}
if (a_size % 8)
logger.log(level, baBuf.constData(), __FILE__, __LINE__);
}
}
NGL::INGLLogger& getMemoryLogger()
{
try
{
return NGLLogger::getNGLRootLogger().getNGLLogger("memorystate");
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
int parseLine(char* line){
int i = strlen(line);
const char* p = line;
while (*p <'0' || *p > '9') p++;
line[i-3] = '\0';
i = atoi(p);
return i;
}
int getMemoryValue()
{
FILE* file = fopen("/proc/self/status", "r");
int result = -1;
char line[128];
while (fgets(line, 128, file) != NULL){
if (strncmp(line, "VmRSS:", 6) == 0){
result = parseLine(line);
break;
}
}
fclose(file);
return result;
}
std::string getMemoryData()
{
return QStringLiteral("VmRSS: %1 kB #").arg(QString::number(getMemoryValue())).toStdString();
}
}