mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-10 06:45:50 +00:00
feat: Use spdlog logger (#2372)
This commit is contained in:
@@ -21,35 +21,27 @@
|
||||
|
||||
#include "util/SourceLocation.hpp"
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/json.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/log/core/core.hpp>
|
||||
#include <boost/log/core/record.hpp>
|
||||
#include <boost/log/expressions/filter.hpp>
|
||||
#include <boost/log/expressions/keyword.hpp>
|
||||
#include <boost/log/expressions/predicates/channel_severity_filter.hpp>
|
||||
#include <boost/log/keywords/channel.hpp>
|
||||
#include <boost/log/keywords/severity.hpp>
|
||||
#include <boost/log/sinks/unlocked_frontend.hpp>
|
||||
#include <boost/log/sources/record_ostream.hpp>
|
||||
#include <boost/log/sources/severity_channel_logger.hpp>
|
||||
#include <boost/log/sources/severity_feature.hpp>
|
||||
#include <boost/log/sources/severity_logger.hpp>
|
||||
#include <boost/log/utility/manipulators/add_value.hpp>
|
||||
#include <boost/log/utility/setup/common_attributes.hpp>
|
||||
#include <boost/log/utility/setup/console.hpp>
|
||||
#include <boost/log/utility/setup/file.hpp>
|
||||
#include <boost/log/utility/setup/formatter_parser.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
// We forward declare spdlog::logger and spdlog::sinks::sink
|
||||
// to avoid including the spdlog headers in this header file.
|
||||
namespace spdlog {
|
||||
|
||||
class logger;
|
||||
|
||||
namespace sinks {
|
||||
class sink;
|
||||
} // namespace sinks
|
||||
|
||||
} // namespace spdlog
|
||||
|
||||
struct BenchmarkLoggingInitializer;
|
||||
|
||||
@@ -85,23 +77,6 @@ enum class Severity {
|
||||
FTL,
|
||||
};
|
||||
|
||||
/** @cond */
|
||||
// NOLINTBEGIN(readability-identifier-naming)
|
||||
BOOST_LOG_ATTRIBUTE_KEYWORD(LogSeverity, "Severity", Severity);
|
||||
BOOST_LOG_ATTRIBUTE_KEYWORD(LogChannel, "Channel", std::string);
|
||||
// NOLINTEND(readability-identifier-naming)
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Custom labels for @ref Severity in log output.
|
||||
*
|
||||
* @param stream std::ostream The output stream
|
||||
* @param sev Severity The severity to output to the ostream
|
||||
* @return The same ostream we were given
|
||||
*/
|
||||
std::ostream&
|
||||
operator<<(std::ostream& stream, Severity sev);
|
||||
|
||||
/**
|
||||
* @brief A simple thread-safe logger for the channel specified
|
||||
* in the constructor.
|
||||
@@ -111,31 +86,25 @@ operator<<(std::ostream& stream, Severity sev);
|
||||
* severity levels for each channel.
|
||||
*/
|
||||
class Logger final {
|
||||
using LoggerType = boost::log::sources::severity_channel_logger_mt<Severity, std::string>;
|
||||
mutable LoggerType logger_;
|
||||
std::shared_ptr<spdlog::logger> logger_;
|
||||
|
||||
friend class LogService; // to expose the Pump interface
|
||||
friend struct ::BenchmarkLoggingInitializer;
|
||||
|
||||
/**
|
||||
* @brief Helper that pumps data into a log record via `operator<<`.
|
||||
*/
|
||||
class Pump final {
|
||||
using PumpOptType = std::optional<boost::log::aux::record_pump<LoggerType>>;
|
||||
|
||||
boost::log::record rec_;
|
||||
PumpOptType pump_ = std::nullopt;
|
||||
std::shared_ptr<spdlog::logger> logger_;
|
||||
Severity const severity_;
|
||||
SourceLocationType const sourceLocation_;
|
||||
std::ostringstream stream_;
|
||||
bool const enabled_;
|
||||
|
||||
public:
|
||||
~Pump() = default;
|
||||
~Pump();
|
||||
|
||||
Pump(LoggerType& logger, Severity sev, SourceLocationType const& loc)
|
||||
: rec_{logger.open_record(boost::log::keywords::severity = sev)}
|
||||
{
|
||||
if (rec_) {
|
||||
pump_.emplace(boost::log::aux::make_record_pump(logger, rec_));
|
||||
pump_->stream() << boost::log::add_value("SourceLocation", prettyPath(loc));
|
||||
}
|
||||
}
|
||||
Pump(std::shared_ptr<spdlog::logger> logger, Severity sev, SourceLocationType const& loc);
|
||||
|
||||
Pump(Pump&&) = delete;
|
||||
Pump(Pump const&) = delete;
|
||||
@@ -145,7 +114,7 @@ class Logger final {
|
||||
operator=(Pump&&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Perfectly forwards any incoming data into the underlying boost::log pump if the pump is available.
|
||||
* @brief Perfectly forwards any incoming data into the underlying stream if data should be logged.
|
||||
*
|
||||
* @tparam T Type of data to pump
|
||||
* @param data The data to pump
|
||||
@@ -155,8 +124,8 @@ class Logger final {
|
||||
[[maybe_unused]] Pump&
|
||||
operator<<(T&& data)
|
||||
{
|
||||
if (pump_)
|
||||
pump_->stream() << std::forward<T>(data);
|
||||
if (enabled_)
|
||||
stream_ << std::forward<T>(data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -165,11 +134,11 @@ class Logger final {
|
||||
*/
|
||||
operator bool() const
|
||||
{
|
||||
return pump_.has_value();
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] static std::string
|
||||
[[nodiscard]] static std::string_view
|
||||
prettyPath(SourceLocationType const& loc, size_t maxDepth = 3);
|
||||
};
|
||||
|
||||
@@ -194,9 +163,7 @@ public:
|
||||
*
|
||||
* @param channel The channel this logger will report into.
|
||||
*/
|
||||
Logger(std::string channel) : logger_{boost::log::keywords::channel = channel}
|
||||
{
|
||||
}
|
||||
Logger(std::string channel);
|
||||
|
||||
Logger(Logger const&) = default;
|
||||
~Logger() = default;
|
||||
@@ -261,6 +228,9 @@ public:
|
||||
*/
|
||||
[[nodiscard]] Pump
|
||||
fatal(SourceLocationType const& loc = CURRENT_SRC_LOCATION) const;
|
||||
|
||||
private:
|
||||
Logger(std::shared_ptr<spdlog::logger> logger);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -270,8 +240,19 @@ public:
|
||||
* entrypoint for logging into the `General` channel as well as raising alerts.
|
||||
*/
|
||||
class LogService {
|
||||
static Logger generalLog; /*< Global logger for General channel */
|
||||
static boost::log::filter filter;
|
||||
struct Data {
|
||||
bool isAsync;
|
||||
Severity severity;
|
||||
std::vector<std::shared_ptr<spdlog::sinks::sink>> allSinks;
|
||||
};
|
||||
|
||||
friend class Logger;
|
||||
|
||||
private:
|
||||
static Data data;
|
||||
|
||||
static std::shared_ptr<spdlog::logger>
|
||||
registerLogger(std::string const& channel, Severity severity = data.severity);
|
||||
|
||||
public:
|
||||
LogService() = delete;
|
||||
@@ -285,6 +266,12 @@ public:
|
||||
[[nodiscard]] static std::expected<void, std::string>
|
||||
init(config::ClioConfigDefinition const& config);
|
||||
|
||||
/**
|
||||
* @brief Shutdown spdlog to guarantee output is not lost
|
||||
*/
|
||||
static void
|
||||
shutdown();
|
||||
|
||||
/**
|
||||
* @brief Globally accessible General logger at Severity::TRC severity
|
||||
*
|
||||
@@ -292,10 +279,7 @@ public:
|
||||
* @return The pump to use for logging
|
||||
*/
|
||||
[[nodiscard]] static Logger::Pump
|
||||
trace(SourceLocationType const& loc = CURRENT_SRC_LOCATION)
|
||||
{
|
||||
return generalLog.trace(loc);
|
||||
}
|
||||
trace(SourceLocationType const& loc = CURRENT_SRC_LOCATION);
|
||||
|
||||
/**
|
||||
* @brief Globally accessible General logger at Severity::DBG severity
|
||||
@@ -304,10 +288,7 @@ public:
|
||||
* @return The pump to use for logging
|
||||
*/
|
||||
[[nodiscard]] static Logger::Pump
|
||||
debug(SourceLocationType const& loc = CURRENT_SRC_LOCATION)
|
||||
{
|
||||
return generalLog.debug(loc);
|
||||
}
|
||||
debug(SourceLocationType const& loc = CURRENT_SRC_LOCATION);
|
||||
|
||||
/**
|
||||
* @brief Globally accessible General logger at Severity::NFO severity
|
||||
@@ -316,10 +297,7 @@ public:
|
||||
* @return The pump to use for logging
|
||||
*/
|
||||
[[nodiscard]] static Logger::Pump
|
||||
info(SourceLocationType const& loc = CURRENT_SRC_LOCATION)
|
||||
{
|
||||
return generalLog.info(loc);
|
||||
}
|
||||
info(SourceLocationType const& loc = CURRENT_SRC_LOCATION);
|
||||
|
||||
/**
|
||||
* @brief Globally accessible General logger at Severity::WRN severity
|
||||
@@ -328,10 +306,7 @@ public:
|
||||
* @return The pump to use for logging
|
||||
*/
|
||||
[[nodiscard]] static Logger::Pump
|
||||
warn(SourceLocationType const& loc = CURRENT_SRC_LOCATION)
|
||||
{
|
||||
return generalLog.warn(loc);
|
||||
}
|
||||
warn(SourceLocationType const& loc = CURRENT_SRC_LOCATION);
|
||||
|
||||
/**
|
||||
* @brief Globally accessible General logger at Severity::ERR severity
|
||||
@@ -340,10 +315,7 @@ public:
|
||||
* @return The pump to use for logging
|
||||
*/
|
||||
[[nodiscard]] static Logger::Pump
|
||||
error(SourceLocationType const& loc = CURRENT_SRC_LOCATION)
|
||||
{
|
||||
return generalLog.error(loc);
|
||||
}
|
||||
error(SourceLocationType const& loc = CURRENT_SRC_LOCATION);
|
||||
|
||||
/**
|
||||
* @brief Globally accessible General logger at Severity::FTL severity
|
||||
@@ -352,10 +324,7 @@ public:
|
||||
* @return The pump to use for logging
|
||||
*/
|
||||
[[nodiscard]] static Logger::Pump
|
||||
fatal(SourceLocationType const& loc = CURRENT_SRC_LOCATION)
|
||||
{
|
||||
return generalLog.fatal(loc);
|
||||
}
|
||||
fatal(SourceLocationType const& loc = CURRENT_SRC_LOCATION);
|
||||
|
||||
/**
|
||||
* @brief Whether the LogService is enabled or not
|
||||
@@ -370,14 +339,14 @@ private:
|
||||
std::string logDir;
|
||||
|
||||
uint32_t rotationSizeMB;
|
||||
uint32_t dirMaxSizeMB;
|
||||
uint32_t rotationHours;
|
||||
uint32_t dirMaxFiles;
|
||||
};
|
||||
|
||||
friend struct ::BenchmarkLoggingInitializer;
|
||||
|
||||
static void
|
||||
initFileLogging(FileLoggingParams const& params, std::string const& format);
|
||||
[[nodiscard]]
|
||||
static std::shared_ptr<spdlog::sinks::sink>
|
||||
createFileSink(FileLoggingParams const& params);
|
||||
};
|
||||
|
||||
}; // namespace util
|
||||
|
||||
Reference in New Issue
Block a user