8#include "cpu_counter_clock.hpp"
9#include "hires_utc_clock.hpp"
10#include "polymorphic_optional.hpp"
11#include "wfree_message_queue.hpp"
15#include "source_location.hpp"
16#include "os_detect.hpp"
17#include "delayed_format.hpp"
18#include "fixed_string.hpp"
19#include "system_status.hpp"
21#include <fmt/format.h>
22#include <fmt/ostream.h>
31enum class log_level : uint8_t {
32 debug = to_log_level(system_status_type::log_level_debug),
33 info = to_log_level(system_status_type::log_level_info),
34 statistics = to_log_level(system_status_type::log_level_statistics),
35 trace = to_log_level(system_status_type::log_level_trace),
36 audit = to_log_level(system_status_type::log_level_audit),
37 warning = to_log_level(system_status_type::log_level_warning),
38 error = to_log_level(system_status_type::log_level_error),
39 fatal = to_log_level(system_status_type::log_level_fatal)
42[[nodiscard]]
constexpr log_level operator&(log_level
const &lhs, log_level
const &rhs)
noexcept
44 return static_cast<log_level
>(
static_cast<uint8_t
>(lhs) &
static_cast<uint8_t
>(rhs));
47[[nodiscard]]
constexpr log_level operator|(log_level
const &lhs, log_level
const &rhs)
noexcept
49 return static_cast<log_level
>(
static_cast<uint8_t
>(lhs) |
static_cast<uint8_t
>(rhs));
52constexpr log_level &operator|=(log_level &lhs, log_level
const &rhs)
noexcept
60[[nodiscard]]
constexpr log_level make_log_level(log_level user_level)
noexcept
66 case debug: r |= log_level::debug; [[fallthrough]];
67 case info: r |= info; [[fallthrough]];
78 default: tt_no_default();
84constexpr char const *to_const_string(log_level level)
noexcept
86 if (level >= log_level::fatal) {
88 }
else if (level >= log_level::error) {
90 }
else if (level >= log_level::warning) {
92 }
else if (level >= log_level::audit) {
94 }
else if (level >= log_level::trace) {
96 }
else if (level >= log_level::statistics) {
98 }
else if (level >= log_level::info) {
100 }
else if (level >= log_level::debug) {
107inline void system_status_set_log_level(log_level level)
noexcept
109 return system_status_set_log_level(
static_cast<uint8_t
>(level));
112inline int command_line_argument_to_log_level(std::string_view str)
114 if (str ==
"debug") {
115 return static_cast<int>(make_log_level(log_level::debug));
117 }
else if (str ==
"info") {
118 return static_cast<int>(make_log_level(log_level::info));
120 }
else if (str ==
"warning") {
121 return static_cast<int>(make_log_level(log_level::warning));
123 }
else if (str ==
"error") {
124 return static_cast<int>(make_log_level(log_level::error));
127 throw parse_error(
"Unknown log level '{}'", str);
149 static_assert(std::is_same_v<
decltype(SourceFile)::value_type,
char>,
"SourceFile must be a basic_fixed_string<char>");
150 static_assert(std::is_same_v<
decltype(Fmt)::value_type,
char>,
"Fmt must be a basic_fixed_string<char>");
152 template<
typename... Args>
154 _timestamp(::tt::cpu_counter_clock::now()), _what(std::forward<Args>(args)...)
160 ttlet local_timestring = log_message_base::cpu_utc_clock_as_iso8601(_timestamp);
162 if constexpr (
static_cast<bool>(Level & log_level::statistics)) {
163 return fmt::format(
"{} {:5} {}\n", local_timestring, to_const_string(Level), _what());
165 return fmt::format(
"{} {:5} {} ({}:{})\n", local_timestring, to_const_string(Level), _what(), SourceFile, SourceLine);
178static constexpr size_t MAX_MESSAGE_SIZE = 224;
179static constexpr size_t MAX_NR_MESSAGES = 4096;
191void trace_record() noexcept;
195tt_no_inline
void logger_flush() noexcept;
199tt_no_inline
void logger_deinit() noexcept;
206tt_no_inline
void logger_init() noexcept;
212inline
bool logger_start()
214 return system_status_start_subsystem(system_status_type::logger, logger_init, logger_deinit);
225template<log_level Level, basic_fixed_string SourceFile,
int SourceLine, basic_fixed_string Fmt,
typename... Args>
226void log(Args &&...args)
noexcept
228 ttlet status = system_status.load(std::memory_order::relaxed);
230 if (!
static_cast<bool>(to_log_level(status) &
static_cast<uint8_t
>(Level))) [[likely]] {
242 log_queue.
write<
"logger_blocked">()->emplace<log_message<Level, SourceFile, SourceLine, Fmt, forward_value_t<Args>...>>(
243 std::forward<Args>(args)...);
245 if (
static_cast<bool>(Level & log_level::fatal) || !logger_start()) {
246 [[unlikely]] logger_flush();
249 if constexpr (
static_cast<bool>(Level & log_level::fatal)) {
252 }
else if constexpr (
static_cast<bool>(Level & log_level::error)) {
260#define tt_log(level, fmt, ...) \
262 ::tt::log<level, __FILE__, __LINE__, fmt>(__VA_ARGS__); \
265#define tt_log_debug(fmt, ...) tt_log(::tt::log_level::debug, fmt __VA_OPT__(, ) __VA_ARGS__)
266#define tt_log_info(fmt, ...) tt_log(::tt::log_level::info, fmt __VA_OPT__(, ) __VA_ARGS__)
267#define tt_log_statistics(fmt, ...) tt_log(::tt::log_level::statistics, fmt __VA_OPT__(, ) __VA_ARGS__)
268#define tt_log_trace(fmt, ...) tt_log(::tt::log_level::trace, fmt __VA_OPT__(, ) __VA_ARGS__)
269#define tt_log_audit(fmt, ...) tt_log(::tt::log_level::audit, fmt __VA_OPT__(, ) __VA_ARGS__)
270#define tt_log_warning(fmt, ...) tt_log(::tt::log_level::warning, fmt __VA_OPT__(, ) __VA_ARGS__)
271#define tt_log_error(fmt, ...) tt_log(::tt::log_level::error, fmt __VA_OPT__(, ) __VA_ARGS__)
272#define tt_log_fatal(fmt, ...) \
273 tt_log(::tt::log_level::fatal, fmt __VA_OPT__(, ) __VA_ARGS__); \
Delayed formatting.
Definition delayed_format.hpp:19
example: ``` template<tt::basic_fixed_string Foo> class A { auto bar() { return std::string{Foo}; } }...
Definition fixed_string.hpp:29
Definition logger.hpp:131
Definition logger.hpp:147
Polymorphic optional.
Definition polymorphic_optional.hpp:26
Definition wfree_message_queue.hpp:75
scoped_write_operation write() noexcept
Definition wfree_message_queue.hpp:130