Files
modulus/src/log.cpp
T
khodowany 097cb61d2d
publish / publish (push) Successful in 11m55s
Formatting
2026-09-14 23:54:30 -05:00

159 lines
5.2 KiB
C++

#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);
}