This commit is contained in:
+149
@@ -0,0 +1,149 @@
|
||||
#include <modulus/log.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
auto is_valid_log_level(modulus::log_level level) noexcept -> std::bool_t {
|
||||
return static_cast<std::int32_t>(level) >= static_cast<std::int32_t>(modulus::log_level::TRACE) && static_cast<std::int32_t>(level) <= static_cast<std::int32_t>(modulus::log_level::OFF);
|
||||
}
|
||||
|
||||
auto should_log(modulus::log_level record_level, modulus::log_level configured_level) noexcept -> std::bool_t {
|
||||
assert(is_valid_log_level(record_level));
|
||||
assert(is_valid_log_level(configured_level));
|
||||
return configured_level != modulus::log_level::OFF && static_cast<std::int32_t>(record_level) >= static_cast<std::int32_t>(configured_level);
|
||||
}
|
||||
|
||||
auto format_log_record(std::ostream& stream, const modulus::log_record& record) -> void {
|
||||
assert(is_valid_log_level(record.level));
|
||||
assert(record.location.file_name() != nullptr);
|
||||
stream << '[' << modulus::to_string(record.level) << "] " << record.message << " (" << record.location.file_name() << ':' << record.location.line() << ")\n";
|
||||
}
|
||||
|
||||
auto stderr_sink(const modulus::log_record& record) -> void {
|
||||
assert(is_valid_log_level(record.level));
|
||||
assert(record.location.file_name() != nullptr);
|
||||
static auto mutex = std::mutex{};
|
||||
auto lock = std::lock_guard{mutex};
|
||||
format_log_record(std::cerr, record);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
auto modulus::to_string(modulus::log_level level) noexcept -> std::string_view {
|
||||
assert(is_valid_log_level(level));
|
||||
switch (level) {
|
||||
case modulus::log_level::TRACE: return "trace";
|
||||
case modulus::log_level::DEBUG: return "debug";
|
||||
case modulus::log_level::INFO: return "info";
|
||||
case modulus::log_level::WARN: return "warn";
|
||||
case modulus::log_level::ERROR: return "error";
|
||||
case modulus::log_level::CRITICAL: return "critical";
|
||||
case modulus::log_level::OFF: return "off";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
modulus::logger::logger() : sink_(stderr_sink) {}
|
||||
|
||||
auto modulus::logger::set_level(modulus::log_level level) -> void {
|
||||
assert(is_valid_log_level(level));
|
||||
auto lock = std::lock_guard{mutex_};
|
||||
level_ = level;
|
||||
}
|
||||
|
||||
auto modulus::logger::level() const -> modulus::log_level {
|
||||
auto lock = std::lock_guard{mutex_};
|
||||
assert(is_valid_log_level(level_));
|
||||
return level_;
|
||||
}
|
||||
|
||||
auto modulus::logger::enabled(modulus::log_level level) const -> std::bool_t {
|
||||
assert(is_valid_log_level(level));
|
||||
auto lock = std::lock_guard{mutex_};
|
||||
return should_log(level, level_) && static_cast<std::bool_t>(sink_);
|
||||
}
|
||||
|
||||
auto modulus::logger::set_sink(std::function<void(const modulus::log_record&)> sink) -> void {
|
||||
auto lock = std::lock_guard{mutex_};
|
||||
sink_ = std::move(sink);
|
||||
}
|
||||
|
||||
auto modulus::logger::write(modulus::log_record record) const -> void {
|
||||
assert(is_valid_log_level(record.level));
|
||||
assert(record.location.file_name() != nullptr);
|
||||
assert(record.location.function_name() != nullptr);
|
||||
auto sink = std::function<void(const modulus::log_record&)>{};
|
||||
{
|
||||
auto lock = std::lock_guard{mutex_};
|
||||
if (!should_log(record.level, level_) || !sink_) {
|
||||
return;
|
||||
}
|
||||
sink = sink_;
|
||||
}
|
||||
assert(static_cast<std::bool_t>(sink));
|
||||
auto sink_lock = std::lock_guard(sink_mutex_);
|
||||
sink(record);
|
||||
}
|
||||
|
||||
auto modulus::logger::log(modulus::log_level level, std::string message, modulus::source_location location) const -> void {
|
||||
assert(is_valid_log_level(level));
|
||||
assert(location.file_name() != nullptr);
|
||||
assert(location.function_name() != nullptr);
|
||||
write(modulus::log_record{
|
||||
.level = level,
|
||||
.message = std::move(message),
|
||||
.location = location,
|
||||
});
|
||||
}
|
||||
|
||||
auto modulus::default_logger() -> modulus::logger& {
|
||||
static auto instance = modulus::logger{};
|
||||
return instance;
|
||||
}
|
||||
|
||||
auto modulus::set_default_log_level(modulus::log_level level) -> void {
|
||||
assert(is_valid_log_level(level));
|
||||
modulus::default_logger().set_level(level);
|
||||
}
|
||||
|
||||
auto modulus::is_log_enabled(modulus::log_level level) -> std::bool_t {
|
||||
assert(is_valid_log_level(level));
|
||||
return modulus::default_logger().enabled(level);
|
||||
}
|
||||
|
||||
auto modulus::log(modulus::log_level level, std::string message, modulus::source_location location) -> void {
|
||||
assert(is_valid_log_level(level));
|
||||
assert(location.file_name() != nullptr);
|
||||
assert(location.function_name() != nullptr);
|
||||
modulus::default_logger().log(level, std::move(message), location);
|
||||
}
|
||||
|
||||
auto modulus::log_trace(std::string message, modulus::source_location location) -> void {
|
||||
modulus::log(modulus::log_level::TRACE, std::move(message), location);
|
||||
}
|
||||
|
||||
auto modulus::log_debug(std::string message, modulus::source_location location) -> void {
|
||||
modulus::log(modulus::log_level::DEBUG, std::move(message), location);
|
||||
}
|
||||
|
||||
auto modulus::log_info(std::string message, modulus::source_location location) -> void {
|
||||
modulus::log(modulus::log_level::INFO, std::move(message), location);
|
||||
}
|
||||
|
||||
auto modulus::log_warn(std::string message, modulus::source_location location) -> void {
|
||||
modulus::log(modulus::log_level::WARN, std::move(message), location);
|
||||
}
|
||||
|
||||
auto modulus::log_error(std::string message, modulus::source_location location) -> void {
|
||||
modulus::log(modulus::log_level::ERROR, std::move(message), location);
|
||||
}
|
||||
|
||||
auto modulus::log_critical(std::string message, modulus::source_location location) -> void {
|
||||
modulus::log(modulus::log_level::CRITICAL, std::move(message), location);
|
||||
}
|
||||
Reference in New Issue
Block a user