Skip to content
Extraits de code Groupes Projets

Add clean logs support + dependent MR

Fusionnées Kubat a demandé de fusionner log-macros vers master
3 files
+ 41
23
Comparer les modifications
  • Côte à côte
  • En ligne

Fichiers

src/Lib/Log.cc 0 → 100644
+ 311
0
#include "Log.hh"
// Vivy::LogLevel utility implementation
namespace Vivy
{
const std::string_view
LogLevel::toStdStringView(const LogLevel::Level lvl) noexcept
{
return LevelsStringViews[static_cast<Array::size_type>(lvl)];
}
}
// LogSinkUpdater implementations
namespace Vivy
{
StlLogSinkUpdater::StlLogSinkUpdater(MutexType *const lock, MessageQueueType *const queue) noexcept
: updater(lock, queue)
{
setPriority(QThread::LowestPriority);
}
void
StlLogSinkUpdater::run() noexcept
{
forever {
if (QThread::currentThread()->isInterruptionRequested())
return;
if (updater.isMessageAvailable())
emit messageAvailable();
usleep(chrono::microseconds(10000).count()); // Sleeps for 0.1s
}
}
}
// Vivy::LogSinkDispatcher and child classes implementation
namespace Vivy
{
LogSinkDispatcher::~LogSinkDispatcher() noexcept {}
const std::string_view
StderrLogSinkDispatcher::trunkFileName(const char *fileName) noexcept
{
using size_type = std::string_view::size_type;
static constexpr char basePrefix[] = "/src/";
static constexpr size_type basePrefixLen = (sizeof(basePrefix) / sizeof(char)) - 1;
const std::string_view fileNameView{ fileName };
const size_type basePath = fileNameView.rfind(basePrefix);
return std::string_view{ fileNameView.data() + basePath + basePrefixLen,
fileNameView.data() + fileNameView.size() };
}
std::string
StderrLogSinkDispatcher::reduceFileName(const std::string_view fileName) noexcept
{
return std::filesystem::path(fileName).lexically_normal();
}
StderrLogSinkDispatcher::StderrLogSinkDispatcher() noexcept
: LogSinkDispatcher(std::string_view{ "stderr" })
{
}
void
StderrLogSinkDispatcher::handleLogMessage(const std::string_view category,
const LogMessage &msg) noexcept
{
std::cerr << "#(" << reduceFileName(trunkFileName(msg.getHeader().fileName)) << " +"
<< msg.getHeader().lineNumberInFile << " | "
<< LogLevel::toStdStringView(msg.getHeader().severity) << " -> " << category << ") "
<< msg.getTextBuffer() << '\n';
}
}
// Vivy::LogSink implementation
namespace Vivy
{
LogSink::LogSink() noexcept
{
workerThread = new StlLogSinkUpdater(&messageQueueLock, &messageQueue);
connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater);
connect(
workerThread, &StlLogSinkUpdater::messageAvailable, this, [this]() { flush(); },
Qt::QueuedConnection);
workerThread->start();
}
// Flush all messages before exiting
LogSink::~LogSink() noexcept
{
workerThread->requestInterruption();
workerThread->wait();
flush();
}
// Get the log message from the logger and add it to the sink's queue.
void
LogSink::recieveLogMessage(const Logger *const logger, LogMessage &&msg) noexcept
{
const std::lock_guard<std::mutex> messageQueueLockGuard(messageQueueLock);
const bool isFatal = msg.getHeader().severity == LogLevel::Critical;
messageQueue.emplace_back(std::make_tuple<const std::string_view, LogMessage>(
logger->getCategoryView(), std::move(msg.sink())));
if (isFatal) {
std::cerr << "-->>Found a fatal log! flush the message queue and abort<<--\n";
flush();
abort();
}
}
// Flush all LogMessages to all of the LogSinkDispatchers. Also clear the message queue.
void
LogSink::flush() noexcept
{
const std::lock_guard<std::mutex> messageQueueLockGuard(messageQueueLock);
for (std::shared_ptr<LogSinkDispatcher> dispatcher : logDispatchers) {
for (const auto &[category, msg] : messageQueue)
dispatcher->handleLogMessage(category, msg);
}
messageQueue.clear();
}
std::shared_ptr<LogSink>
LogSink::newSink() noexcept
{
struct makeSharedEnabler : public LogSink {
// NOTE: For make_shared with private CTor
};
return std::make_shared<makeSharedEnabler>();
}
void
LogSink::registerLogDispatcher(std::shared_ptr<LogSinkDispatcher> dispatcher) noexcept
{
logDispatchers.push_back(dispatcher);
}
void
LogSink::registerLogger(std::shared_ptr<Logger> ptr) noexcept
{
loggers.push_back(ptr);
}
}
// Vivy::Logger implementation
namespace Vivy
{
void
Logger::sendLogMessage(LogMessage &&msg) const noexcept
{
parentLogSink->recieveLogMessage(this, std::move(msg));
}
LogMessage
Logger::logEvent(const char *fileName, const char *functionName, const int lineNumber,
const LogLevel::Level logSeverity) noexcept
{
return LogMessage(this, LogMessage::Header{ .fileName = fileName,
.functionName = functionName,
.severity = logSeverity,
.lineNumberInFile = lineNumber });
}
}
// Vivy::LogMessage implementation
namespace Vivy
{
LogMessage::LogMessage(const Logger *const logger, const LogMessage::Header hdr) noexcept
: messageHeader(hdr)
, parentLogger(logger)
{
}
LogMessage::LogMessage(LogMessage &&other) noexcept
: messageHeader(other.messageHeader)
, parentLogger(other.parentLogger)
{
std::memcpy(this, &other, sizeof(LogMessage));
std::memset(reinterpret_cast<void *>(&other), 0, sizeof(LogMessage));
}
LogMessage &&
LogMessage::sink() noexcept
{
parentLogger = nullptr;
return std::move(*this);
}
LogMessage &
LogMessage::operator<<(const std::string &msg) noexcept
{
return (*this << msg.c_str());
}
LogMessage &
LogMessage::operator<<(const QVariant &variant) noexcept
{
return (*this << variant.toString());
}
LogMessage &
LogMessage::operator<<(const QString &msg) noexcept
{
return (*this << msg.toStdString());
}
LogMessage &
LogMessage::operator<<(const QFileInfo &fileInfo) noexcept
{
return (*this << "QFileInfo{ " << fileInfo.absoluteFilePath() << "}");
}
LogMessage &
LogMessage::operator<<(const double *ptr) noexcept
{
return (*this << "Pointer{ double, " << pointerToString<double>(ptr) << " }");
}
LogMessage &
LogMessage::operator<<(const unsigned char c) noexcept
{
return (*this << static_cast<char>(c));
}
LogMessage &
LogMessage::operator<<(const unsigned int i) noexcept
{
return (*this << static_cast<unsigned long>(i));
}
LogMessage &
LogMessage::operator<<(const unsigned long i) noexcept
{
return (*this << std::to_string(i));
}
LogMessage &
LogMessage::operator<<(const unsigned long long i) noexcept
{
return (*this << std::to_string(i));
}
LogMessage &
LogMessage::operator<<(const long long i) noexcept
{
return (*this << std::to_string(i));
}
LogMessage &
LogMessage::operator<<(const int i) noexcept
{
return (*this << static_cast<long>(i));
}
LogMessage &
LogMessage::operator<<(const long i) noexcept
{
return (*this << std::to_string(i));
}
LogMessage &
LogMessage::operator<<(const std::string_view strv) noexcept
{
for (std::size_t i = 0; (i < strv.size()) && (indexInArray < messageBufferLength - 1);
++i, ++indexInArray) {
textBuffer[indexInArray] = strv[i];
}
textBuffer[indexInArray] = '\0';
return *this;
}
LogMessage &
LogMessage::operator<<(const char *str) noexcept
{
const std::size_t length = strlen(str);
for (std::size_t i = 0; (i < length) && (indexInArray < messageBufferLength - 1);
++i, ++indexInArray) {
textBuffer[indexInArray] = str[i];
}
textBuffer[indexInArray] = '\0';
return *this;
}
LogMessage &
LogMessage::operator<<(const char c) noexcept
{
if (indexInArray < messageBufferLength - 1) {
textBuffer[indexInArray] = c;
++indexInArray;
textBuffer[indexInArray] = '\0';
}
return *this;
}
const std::string_view
LogMessage::getTextBuffer() const noexcept
{
const char *txt = textBuffer.data();
return std::string_view{ txt, strlen(txt) };
}
LogMessage::~LogMessage() noexcept
{
if (parentLogger)
parentLogger->sendLogMessage(std::move(*this));
}
}
Chargement en cours