Reworked log system: now logs are handled by lms itself (better control on what is logged), ref #725
This commit is contained in:
@@ -17,7 +17,17 @@
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "core/ILogger.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
#include <Wt/WDateTime.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "core/Exception.hpp"
|
||||
#include "core/String.hpp"
|
||||
|
||||
namespace lms::core::logging
|
||||
{
|
||||
@@ -63,6 +73,8 @@ namespace lms::core::logging
|
||||
return "UI";
|
||||
case Module::UTILS:
|
||||
return "UTILS";
|
||||
case Module::WT:
|
||||
return "WT";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -103,4 +115,94 @@ namespace lms::core::logging
|
||||
{
|
||||
return _oss.str();
|
||||
}
|
||||
|
||||
std::unique_ptr<ILogger> createLogger(Severity minSeverity, const std::filesystem::path& logFilePath)
|
||||
{
|
||||
return std::make_unique<Logger>(minSeverity, logFilePath);
|
||||
}
|
||||
|
||||
Logger::OutputStream::OutputStream(std::ostream& os)
|
||||
: stream{ os }
|
||||
{
|
||||
}
|
||||
|
||||
Logger::Logger(Severity minSeverity, const std::filesystem::path& logFilePath)
|
||||
{
|
||||
if (!logFilePath.empty())
|
||||
{
|
||||
_logFileStream = std::make_unique<std::ofstream>(logFilePath, std::ios::out | std::ios::app);
|
||||
if (!_logFileStream->is_open())
|
||||
{
|
||||
const std::error_code ec{ errno, std::generic_category() };
|
||||
throw LmsException{ "Cannot open log file '" + logFilePath.string() + "' for writing: " + ec.message() };
|
||||
}
|
||||
}
|
||||
|
||||
switch (minSeverity)
|
||||
{
|
||||
case core::logging::Severity::DEBUG:
|
||||
if (_logFileStream)
|
||||
addOutputStream(*_logFileStream, { core::logging::Severity::DEBUG });
|
||||
else
|
||||
addOutputStream(std::cout, { core::logging::Severity::DEBUG });
|
||||
[[fallthrough]];
|
||||
case core::logging::Severity::INFO:
|
||||
if (_logFileStream)
|
||||
addOutputStream(*_logFileStream, { core::logging::Severity::INFO });
|
||||
else
|
||||
addOutputStream(std::cout, { core::logging::Severity::INFO });
|
||||
[[fallthrough]];
|
||||
case core::logging::Severity::WARNING:
|
||||
if (_logFileStream)
|
||||
addOutputStream(*_logFileStream, { core::logging::Severity::WARNING });
|
||||
else
|
||||
addOutputStream(std::cerr, { core::logging::Severity::WARNING });
|
||||
[[fallthrough]];
|
||||
case core::logging::Severity::ERROR:
|
||||
if (_logFileStream)
|
||||
addOutputStream(*_logFileStream, { core::logging::Severity::ERROR });
|
||||
else
|
||||
addOutputStream(std::cerr, { core::logging::Severity::ERROR });
|
||||
[[fallthrough]];
|
||||
case core::logging::Severity::FATAL:
|
||||
if (_logFileStream)
|
||||
addOutputStream(*_logFileStream, { core::logging::Severity::FATAL });
|
||||
else
|
||||
addOutputStream(std::cerr, { core::logging::Severity::FATAL });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Logger::~Logger() = default;
|
||||
|
||||
void Logger::addOutputStream(std::ostream& os, Severity severity)
|
||||
{
|
||||
auto it{ std::find_if(_outputStreams.begin(), _outputStreams.end(), [&os](const OutputStream& outputStream) { return &outputStream.stream == &os; }) };
|
||||
if (it == _outputStreams.end())
|
||||
it = _outputStreams.emplace(_outputStreams.end(), os);
|
||||
|
||||
assert(!_severityToOutputStreamMap.contains(severity));
|
||||
_severityToOutputStreamMap.emplace(severity, &(*it));
|
||||
}
|
||||
|
||||
bool Logger::isSeverityActive(Severity severity) const
|
||||
{
|
||||
return _severityToOutputStreamMap.contains(severity);
|
||||
}
|
||||
|
||||
void Logger::processLog(const Log& log)
|
||||
{
|
||||
processLog(log.getModule(), log.getSeverity(), log.getMessage());
|
||||
}
|
||||
|
||||
void Logger::processLog(Module module, Severity severity, std::string_view message)
|
||||
{
|
||||
assert(isSeverityActive(severity)); // should have been filtered out by a isSeverityActive call
|
||||
OutputStream* outputStream{ _severityToOutputStreamMap.at(severity) };
|
||||
const Wt::WDateTime now{ Wt::WDateTime::currentDateTime() };
|
||||
|
||||
std::unique_lock lock{ outputStream->mutex };
|
||||
outputStream->stream << stringUtils::toISO8601String(now) << " " << std::this_thread::get_id() << " [" << getSeverityName(severity) << "] [" << getModuleName(module) << "] " << message << std::endl;
|
||||
}
|
||||
|
||||
} // namespace lms::core::logging
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS 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.
|
||||
*
|
||||
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <iosfwd>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "core/ILogger.hpp"
|
||||
|
||||
namespace lms::core::logging
|
||||
{
|
||||
class Logger final : public ILogger
|
||||
{
|
||||
public:
|
||||
Logger(Severity minSeverity, const std::filesystem::path& logFilePath);
|
||||
~Logger() override;
|
||||
Logger(const Logger&) = delete;
|
||||
Logger& operator=(const Logger&) = delete;
|
||||
|
||||
private:
|
||||
bool isSeverityActive(Severity severity) const override;
|
||||
void processLog(const Log& log) override;
|
||||
void processLog(Module module, Severity severity, std::string_view message) override;
|
||||
|
||||
void addOutputStream(std::ostream& os, Severity severity);
|
||||
|
||||
struct OutputStream
|
||||
{
|
||||
OutputStream(std::ostream& os);
|
||||
|
||||
std::mutex mutex;
|
||||
std::ostream& stream;
|
||||
};
|
||||
|
||||
std::list<OutputStream> _outputStreams;
|
||||
std::unordered_map<Severity, OutputStream*> _severityToOutputStreamMap;
|
||||
std::unique_ptr<std::ofstream> _logFileStream;
|
||||
};
|
||||
} // namespace lms::core::logging
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS 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.
|
||||
*
|
||||
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <thread>
|
||||
|
||||
#include "core/StreamLogger.hpp"
|
||||
|
||||
namespace lms::core::logging
|
||||
{
|
||||
StreamLogger::StreamLogger(std::ostream& os, EnumSet<Severity> severities)
|
||||
: _os{ os }
|
||||
, _severities{ severities }
|
||||
{
|
||||
}
|
||||
|
||||
void StreamLogger::processLog(const Log& log)
|
||||
{
|
||||
assert(isSeverityActive(log.getSeverity()));
|
||||
_os << std::this_thread::get_id() << " [" << getSeverityName(log.getSeverity()) << "] [" << getModuleName(log.getModule()) << "] " << log.getMessage() << std::endl;
|
||||
}
|
||||
} // namespace lms::core::logging
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "core/Exception.hpp"
|
||||
#include "core/ILogger.hpp"
|
||||
#include "core/String.hpp"
|
||||
|
||||
namespace lms::core::tracing
|
||||
{
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS 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.
|
||||
*
|
||||
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "core/WtLogger.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
#include <Wt/WLogger.h>
|
||||
#include <Wt/WServer.h>
|
||||
|
||||
#include "core/Exception.hpp"
|
||||
|
||||
namespace lms::core::logging
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::string to_string(std::thread::id id)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << id;
|
||||
return oss.str();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
WtLogger::WtLogger(Severity minSeverity)
|
||||
: _minSeverity{ minSeverity }
|
||||
{
|
||||
}
|
||||
|
||||
std::string WtLogger::computeLogConfig(Severity minSeverity)
|
||||
{
|
||||
switch (minSeverity)
|
||||
{
|
||||
case Severity::DEBUG:
|
||||
return "*";
|
||||
case Severity::INFO:
|
||||
return "* -debug";
|
||||
case Severity::WARNING:
|
||||
return "* -debug -info";
|
||||
case Severity::ERROR:
|
||||
return "* -debug -info -warning";
|
||||
case Severity::FATAL:
|
||||
return "* -debug -info -warning -error";
|
||||
}
|
||||
|
||||
throw LmsException{ "Unhandled severity" };
|
||||
}
|
||||
|
||||
bool WtLogger::isSeverityActive(Severity severity) const
|
||||
{
|
||||
return static_cast<int>(severity) <= static_cast<int>(_minSeverity);
|
||||
}
|
||||
|
||||
void WtLogger::processLog(const Log& log)
|
||||
{
|
||||
Wt::log(getSeverityName(log.getSeverity())) << Wt::WLogger::sep << to_string(std::this_thread::get_id()) << Wt::WLogger::sep << "[" << getModuleName(log.getModule()) << "]" << Wt::WLogger::sep << log.getMessage();
|
||||
}
|
||||
} // namespace lms::core::logging
|
||||
Reference in New Issue
Block a user